cant "connect" classes in my sublime text 3 python code - python

I'm programming in Sublime Text 3 and I need to use an object-oriented class in another class and I can't reach it and its functions from another class (I saved them both on the same directory on my computer), thanks for the helpers.

If I understand you correctly, I think you're trying to access one python module from another python module (each "module" is a file), and each module contains a class.
If class A is Foo, saved in foo.py, and class B is Bar saved in bar.py, and you want to use Foo inside of Bar, then you need to import Foo such that it is in scope when Bar is defined.
You might try, in bar.py, above where Bar is defined: from foo import Foo
For more information, this might help: https://docs.python.org/3/tutorial/modules.html

class1:
import sqlite3
from driver import Driver
from sqlitte import error
def create():
try:
conn = sqlite3.connect(':memory:')
except error as e:
print (e)
c = conn.cursor()
c.excute("""CREATE TABLE users(
price real,
discount real
)""")
conn.commit()
conn.close()
and class 2(saved in the same directory as driver.py):
class Driver:
def __init__(self, online_id):
self.online_id = online_id
def get_online_id():
return self.online_id

Related

Registering classes to factory with classes in different files

I have a factory as shown in the following code:
class ClassFactory:
registry = {}
#classmethod
def register(cls, name):
def inner_wrapper(wrapped_class):
if name in cls.registry:
print(f'Class {name} already exists. Will replace it')
cls.registry[name] = wrapped_class
return wrapped_class
return inner_wrapper
#classmethod
def create_type(cls, name):
exec_class = cls.registry[name]
type = exec_class()
return type
#ClassFactory.register('Class 1')
class M1():
def __init__(self):
print ("Starting Class 1")
#ClassFactory.register('Class 2')
class M2():
def __init__(self):
print("Starting Class 2")
This works fine and when I do
if __name__ == '__main__':
print(ClassFactory.registry.keys())
foo = ClassFactory.create_type("Class 2")
I get the expected result of dict_keys(['Class 1', 'Class 2']) Starting Class 2
Now the problem is that I want to isolate classes M1 and M2 to their own files m1.py and m2.py, and in the future add other classes using their own files in a plugin manner.
However, simply placing it in their own file
m2.py
from test_ import ClassFactory
#MethodFactory.register('Class 2')
class M2():
def __init__(self):
print("Starting Class 2")
gives the result dict_keys(['Class 1']) since it never gets to register the class.
So my question is: How can I ensure that the class is registered when placed in a file different from the factory, without making changes to the factory file whenever I want to add a new class? How to self register in this way? Also, is this decorator way a good way to do this kind of thing, or are there better practices?
Thanks
How can I ensure that the class is registered when placed in a file different from the factory, without making changes to the factory file whenever I want to add a new class?
I'm playing around with a similar problem, and I've found a possible solution. It seems too much of a 'hack' though, so set your critical thinking levels to 'high' when reading my suggestion below :)
As you've mentioned in one of your comments above, the trick is to force the loading of the individual *.py files that contain individual class definitions.
Applying this to your example, this would involve:
Keeping all class implementations in a specific folders, e.g., structuring the files as follows:
.
└- factory.py # file with the ClassFactory class
└─ classes/
└- __init__.py
└- m1.py # file with M1 class
└- m2.py # file with M2 class
Adding the following statement to the end of your factory.py file, which will take care of loading and registering each individual class:
from classes import *
Add a piece of code like the snippet below to your __init__.py within the classes/ foder, so that to dynamically load all classes [1]:
from inspect import isclass
from pkgutil import iter_modules
from pathlib import Path
from importlib import import_module
# iterate through the modules in the current package
package_dir = Path(__file__).resolve().parent
for (_, module_name, _) in iter_modules([package_dir]):
# import the module and iterate through its attributes
module = import_module(f"{__name__}.{module_name}")
for attribute_name in dir(module):
attribute = getattr(module, attribute_name)
if isclass(attribute):
# Add the class to this package's variables
globals()[attribute_name] = attribute
If I then run your test code, I get the desired result:
# test.py
from factory import ClassFactory
if __name__ == "__main__":
print(ClassFactory.registry.keys())
foo = ClassFactory.create_type("Class 2")
$ python test.py
dict_keys(['Class 1', 'Class 2'])
Starting Class 2
Also, is this decorator way a good way to do this kind of thing, or are there better practices?
Unfortunately, I'm not experienced enough to answer this question. However, when searching for answers to this problem, I've came across the following sources that may be helpful to you:
[2] : this presents a method for registering class existence based on Python Metaclasses. As far as I understand, it relies on the registering of subclasses, so I don't know how well it applies to your case. I did not follow this approach, as I've noticed that the new edition of the book suggests the use of another technique (see bullet below).
[3], item 49 : this is the 'current' suggestion for subclass registering, which relies on the definition of the __init_subclass__() function in a base class.
If I had to apply the __init_subclass__() approach to your case, I'd do the following:
Add a Registrable base class to your factory.py (and slightly re-factor ClassFactory), like this:
class Registrable:
def __init_subclass__(cls, name:str):
ClassFactory.register(name, cls)
class ClassFactory:
registry = {}
#classmethod
def register(cls, name:str, sub_class:Registrable):
if name in cls.registry:
print(f'Class {name} already exists. Will replace it')
cls.registry[name] = sub_class
#classmethod
def create_type(cls, name):
exec_class = cls.registry[name]
type = exec_class()
return type
from classes import *
Slightly modify your concrete classes to inherit from the Registrable base class, e.g.:
from factory import Registrable
class M2(Registrable, name='Class 2'):
def __init__(self):
print ("Starting Class 2")

Best practices for importing rarely used package in Python

My Python package depends on an external library for a few of it's functions. This is a non-Python package and can be difficult to install, so I'd like users to still be able to use my package but have it fail when using any functions that depend on this non-Python package.
What is the standard practice for this? I could only import the non-Python package inside the methods that use it, but I really hate doing this
My current setup:
myInterface.py
myPackage/
--classA.py
--classB.py
The interfaces script myInterface.py imports classA and classB and classB imports the non-Python package. If the import fails I print a warning. If myMethod is called and the package isn't installed there will be some error downstream but I do not catch it anywhere, nor do I warn the user.
classB is imported every time the interface script is called so I can't have anything fail there, which is why I included the pass. Like I said above, I could import inside the method and have it fail there, but I really like keeping all of my imports in one place.
From classB.py
try:
import someWeirdPackage
except ImportError:
print("Cannot import someWeirdPackage")
pass
class ClassB():
...
def myMethod():
swp = someWeirdPackage()
...
If you are only importing one external library, I would go for something along these lines:
try:
import weirdModule
available = True
except ImportError:
available = False
def func_requiring_weirdmodule():
if not available:
raise ImportError('weirdModule not available')
...
The conditional and error checking is only needed if you want to give more descriptive errors. If not you can omit it and let python throw the corresponding error when trying to calling a non-imported module, as you do in your current setup.
If multiple functions do use weirdModule, you can wrap the checking into a function:
def require_weird_module():
if not available:
raise ImportError('weirdModule not available')
def f1():
require_weird_module()
...
def f2():
require_weird_module()
...
On the other hand, if you have multiple libraries to be imported by different functions, you can load them dynamically. Although it doesn't look pretty, python caches them and there is nothing wrong with it. I would use importlib
import importlib
def func_requiring_weirdmodule():
weirdModule = importlib.import_module('weirdModule')
Again, if multiple of your functions import complicated external modules you can wrap them into:
def import_external(name):
return importlib.import_module(name)
def f1():
weird1 = import_external('weirdModule1')
def f2():
weird2 = import_external('weirdModule2')
And last, you could create a handler to prevent importing the same module twice, something along the lines of:
class Importer(object):
__loaded__ = {}
#staticmethod
def import_external(name):
if name in Importer.__loaded__:
return Importer.__loaded__[name]
mod = importlib.import_module(name)
Importer.__loaded__[name] = mod
return mod
def f1():
weird = Importer.import_external('weird1')
def f2():
weird = Importer.import_external('weird1')
Although I'm pretty sure that importlib does caching behing the scenes and you don't really need for manual caching.
In short, although it does look ugly, there is nothing wrong with importing modules dynamically in python. In fact, a lot of libraries rely on this. On the other hand, if it is just for an special case of 3 methods accessing 1 external function, do use your approach or my first one in case you cant to add custom sception handling.
I'm not really sure that there's any best practice in this situation, but I would redefine the function if it's not supported:
def warn_import():
print("Cannot import someWeirdPackage")
try:
import someWeirdPackage
external_func = someWeirdPackage
except ImportError:
external_func = warn_import
class ClassB():
def myMethod(self):
swp = external_func()
b = ClassB()
b.myMethod()
You can create two separate classes for the two cases. The first will be used when the the package exist . The second will used when the package does not exist.
class ClassB1():
def myMethod(self):
print("someWeirdPackage exist")
# do something
class ClassB2(ClassB1):
def myMethod(self):
print("someWeirdPackage does not exist")
# do something or raise Exception
try:
import someWeirdPackage
class ClassB(ClassB1):
pass
except ImportError:
class ClassB(ClassB2):
pass
You can also use given below approach to overcome the problem that you're facing.
class UnAvailableName(object):
def __init__(self, name):
self.target = name
def __getattr_(self, attr):
raise ImportError("{} is not available.".format(attr))
try:
import someWeirdPackage
except ImportError:
print("Cannot import someWeirdPackage")
someWeirdPackage = someWeirdPackage("someWeirdPackage")
class ClassB():
def myMethod():
swp = someWeirdPackage.hello()
a = ClassB()
a.myMethod()

Pass arg while importing

How can I pass an argument to a Python module while importing it?
For instance, while running a script from command line, I can do this:
python script.py [arg1] [arg2]
I want to do the same while I am importing a module in python
I have two modules, one.py and two.py
one.py:
name='TestTab'
import two [arg(which i want to be name variable)]
tweet = Tweet()
two.py:
import sqlalchemy
name= [received arg]
class Tweet():
__tabname__ = name
id = Column(String(255))
Basically, I want to create a new table every time I import two.py, and I want the name of the new table to be passed while importing.
That's not a feature of Python, and you're not using classes well by using class-level variables and no constructor. The way to approach this is to pass the parameter to the constructor of Tweet, and store the data as instance variables.
one.py
name='TestTab'
from two import Tweet
tweet = Tweet(whatever_name)
two.py
import sqlalchemy
class Tweet(object):
def __init__(self, name):
self.tabname = name
self.id = Column(String(255))
Not really pythonic but a possible simplest way is to expose your variable out
one.py
import two
two.name = "test"
tweet = two.Tweet()
two.py
import sqlalchemy
name = None
class Tweet():
__tabname__ = name
id = Column(String(255))

Accessing global cursor from within function

This works okay (some code ommited for brevity):
# main.py
cursor = db.cursor()
cursor.execute('foo')
As does this:
# other.py
def do_something(script, cursor):
cursor.execute(script)
# main.py
from other import do_something
cursor = db.cursor()
do_something('foo', cursor)
But (as I understand it) the "lower" scope of the function should be able to access the "higher" (global?) scoped cursor - why should I need to pass the cursor as an argument on my function? So I tried this:
# other.py
def do_something(script):
cursor.execute(script)
# main.py
from other import do_something
cursor = db.cursor()
do_something('foo')
Which returns:
NameError: global name 'cursor' is not defined
I thought "maybe running a query against the cursor is a write operation, not a read" and tried:
# other.py
def do_something(script):
global cursor
cursor.execute(script)
# main.py
from other import do_something
cursor = db.cursor()
do_something('foo')
Same error. What am I missing?
EDIT: It sounds like "how do I make variable names global across different modules" is the wrong question. The right question - if I have a primary handler, a SQL cursor and a file of common functions, how should I structure my files / imports?
try this code
# other.py
def do_something(script):
global cursor
cursor.execute(script)
# main.py
from other import do_something
import other
other.cursor = db.cursor()
do_something(script)
My English is not good, so you can read these answers
Global Variable from a different file Python
Using global variables between files?
make variable global to multiple files in python

how to test exception in python working with postgresql

I have my own class Article designed to wrok with PostgreSQL. Each object created from the class is used to work with one row. Now I dont know how to test exception case. When I create such case:
article = Article(2)/*connects to the db and loads line with id 2*/
print article.title2 /*here my db does not have table title2 and should launch an error*/
it should throw error. And it does)
How should test case looks like? I use unittest. My test class with my wrong method which does not work is below:
import unittest
from article import * /*import my ORM class*/
class EntityTest(unittest.TestCase):
def setUp(self):
Entity.db = psycopg2.connect("dbname='postgres' user='postgres' host='192.168.136.129' password='xxxxxxxxx'")/*creates connection to db*/
def test_should_lounch_attr_error(self):
article = Article(2)
print article.title2
self.assertRaisesRegex(article.AttributeError, "No attribute exists")
I have no expirience how to create test cases and no much good documentation of how to do it(((
As I undestood if testcase is passed (exception is generated), unittest should return Ok statement. Now it just shows error.
If you do not supply a callable to assertRaisesRegexp() (N.B. assertRaisesRegexp(), not assertRaisesRegex()), then it acts as a context manager. In that case you should use a with statement like this:
import unittest
from article import * /*import my ORM class*/
class EntityTest(unittest.TestCase):
def setUp(self):
Entity.db = psycopg2.connect("dbname='postgres' user='postgres' host='192.168.136.129' password='xxxxxxxxx'")/*creates connection to db*/
def test_should_lounch_attr_error(self):
with self.assertRaisesRegexp(article.AttributeError, "No attribute exists"):
article = Article(2)
print article.title2
Unless your code can raise article.AttributeError with different string representations, I don't think that you actually need to use a regex for this. Just check for article.AttributeError with assertRaises(). This should suffice:
with self.assertRaisesRegexp(article.AttributeError):
article = Article(2)
print article.title2

Categories