I have following simplified class named Password.py in folder1:
import random
CHARS = "ABC"
class PasswordHelper(object):
#staticmethod
def generateChars(length):
return ''.join(random.choice(CHARS) for x in range(length))
Now I have another class TestClass.py in folder2:
sys.path.append('../folder1/')
import Password
class Tester:
def whatever(self):
print Password.generateChars(3)
def main():
x = Tester()
x.whatever()
# call main method
main()
When calling python TestClass.py I get the following error: AttributeError: 'module' object has no attribute 'generateChars'. Both folders are on the same level. Is there a problem with the way I import the class files or with the static method declaration itself?
Python is not Java.
Firstly, there is absolutely no point to either the Tester or the Password classes. If you're not storing state, then don't define a class. Make both whatever and generateChars into normal standalone functions.
However, assuming you're doing this just to learn about Python classes, you have not understood that a class does not equal a module in Python. Since you've imported the Password module, you still need to refer to the PasswordHelper class:
Password.PasswordHelper.generateChars(3)
Alternatively, you can import the PasswordHelper class:
from Password import PasswordHelper
...
PasswordHelper.generateChars(3)
Finally, please follow PEP8 for your module, class and function names.
You defined the function in a class, so you need to reference it with the classname too:
print Password.PasswordHelper.generateChars(3)
Alternatively, move the function out of the class definition, at which point you do not need to use #staticmethod at all:
import random
CHARS = "ABC"
def generateChars(length):
return ''.join(random.choice(CHARS) for x in range(length))
In Python, functions do not have to be part of a class definition.
Related
I have a class
class Foo():
def some_method():
pass
And another class in the same module:
class Bar():
def some_other_method():
class_name = "Foo"
# Can I access the class Foo above using the string "Foo"?
I want to be able to access the Foo class using the string "Foo".
I can do this if I'm in another module by using:
from project import foo_module
foo_class = getattr(foo_module, "Foo")
Can I do the same sort of thing in the same module?
The guys in IRC suggested I use a mapping dict that maps string class names to the classes, but I don't want to do that if there's an easier way.
import sys
getattr(sys.modules[__name__], "Foo")
# or
globals()['Foo']
You can do it with help of the sys module:
import sys
def str2Class(str):
return getattr(sys.modules[__name__], str)
globals()[class_name]
Note that if this isn't strictly necessary, you may want to refactor your code to not use it.
I have class with few methods. Let's say A
file a.py
class A:
def foo():
...
def bar():
...
during normal runtime (not testing) I use it in different modules, like that.
file functions.py
from a import A
def sample_function():
a_instance = A()
result = a_instance.foo()
return result
But during tests I would like to replace it with different class, let's say MockA.
file mock_a.py
class MockA:
# same methods name, but with different implementation
def foo():
...
def bar():
...
Now I would like to test module with some functionality
tests
from functions import sample_function
def test_sample_function():
assert sample_function() == expected_output
The QUESTION is:
Can I somehow "globally" set alias A = MockA (or do this in other way), so that during tests sample_function use functionality from MockA?
sample_function uses whatever A is bound to in the global namespace of the module functions. You can rebind your own class to that name.
from functions import one_function
class MockA:
...
functions.A = MockA
def test_sample_function():
assert sample_function() == expected_output
This is exactly what unittest.mock.patch is for
How about you use:
tests
from unittest.mock import patch
from mock_a import MockA
from functions import sample_function
#patch('functions.A', new_callable=MockA)
def test_sample_function(mocked_A):
assert sample_function() == expected_output
Try changeing this:
from a import A
into this:
from mock_a import MockA as A
First correct me in comments if I am wrong, but is it a mistake that you wrote one_function in your last code snippet, where you should have written sample_function.
I think your concern is that you don't want to change the functions.py code by replacing a_instance = A() with a_instance = MockA() everywhere in the code. So just make mock_a.py with same class name class A: and same methods name, but different implementations(like you said). All you will have to change in your functions.py code is from mock_a import A instead all all instance of class A() to class MockA(). This way I think your tests should work perfectly.
In my builder/graph_builder.py, I have a class
class GraphBuilder(object):
def __init__(self):
pass
#staticmethod
def parse(path):
...
return path
Then in the same directory, I have a linker.py, and I want to import the 'parse' function:
from builder.graph_builder.GraphBuilder import parse
I am in PyCharm and it prompts that 'from builder.graph_builder.' is visible, but after that, it can't reference GraphBuilder and parse function.
Why is that?
The syntax is from MODULE import NAME, therefore
from builder.graph_builder import GraphBuilder
will work, but
from builder.graph_builder.GraphBuilder import parse
will not - builder.graph_builder.GraphBuilder is not a module.
It's not possible to import a Method from a Class in python
You have to, first import the class and after call the method. It happen even if it is a static method.
As graph_builder is located at same directory, you could refer graph_builder directly.
Furthermore GraphBuilder is a class, so you could instantiate and store parse function into a variable
You could try like this:
from graph_builder import GraphBuilder
if __name__=='__main__':
path="C:\\Users\\"
parse=GraphBuilder().parse
test=parse(path)
This works in a script to recognise if a is of class myproject.aa.RefClass
isinstance(a, myproject.aa.RefClass)
But how could I do it so I do not have to specify the full namespace ? I would like to be able to type:
isinstance(a, RefClass)
How is this done in Python ?
EDIT: let me give more details.
In module aa.referencedatatable.py:
class ReferenceDataTable(object):
def __init__(self, name):
self.name = name
def __call__(self, f):
self._myfn = f
return self
def referencedatatable_from_tag(tag):
import definitions
defn_lst = [definitions]
for defn in defn_lst:
referencedatatable_instance_lst = [getattr(defn, a) for a in dir(defn) if isinstance(getattr(defn, a), ReferenceDataTable)]
for referencedatatable_instance in referencedatatable_instance_lst
if referencedatatable_instance.name == tag
return referencedatatable_instance
raise("could not find")
def main()
referencedata_from_tag("Example")
In module aa.definitions.py:
from aa.referencedatatable import ReferenceDataTable
#ReferenceDataTable("Example")
def EXAMPLE():
raise NotImplementedError("not written")
For some reason calling the main from aa.referencedatatable.py will throw as it will not be able to recognise the instance of the class. But if I copy this main in another module it will work:
import aa.referencedatatable
a = aa.referencedatatable.referencedatatable_from_tag("Example")
print a
This second example works, for some reason calling this function inside the same module where the class is declared does not.
The 'namespace' is just a module object, and so is the class. You can always assign the class to a different name:
RefClass = myproject.aa.RefClass
or better yet, import it directly into your own namespace:
from myproject.aa import RefClass
Either way, now you have a global name RefClass that references the class object, so you can do:
isinstance(a, RefClass)
I am trying to get a module to import, but only if an object of a specific class is called. For example:
class One(object):
try:
import OneHelper
except ImportError:
pass
def __init__(self):
# this function doesn't use OneHelper
...
def blah(self):
# this function does
OneHelper.blah()
This causes a NameError: global name 'OneHelper' is not defined when the One.blah() function is called. So far the only thing I have found that works is importing the module into the actual functions that use it. So:
class One(object):
def __init__(self):
# this function doesn't use OneHelper
...
def blah(self):
try:
import OneHelper
except ImportError:
pass
# this function does
OneHelper.blah()
But I don't want to have to import the module in each function I want to use it in, I want it to be available to the whole class, but only if an instance of that class is instantiated. Apologies if I'm not being clear enough...
The import OneHelper works fine in the class, making it a class attribute. You can verify this with dir(One) after defining your class -- there's your OneHelper attribute. One.OneHelper is a reference to the module. In an instance, of course, you may access it as self.OneHelper from your methods. (You could also continue to access it as One.OneHelper.)
Import it on __init__ and attribute to some property:
class One(object):
def __init__(self):
try:
import OneHelper
except ImportError:
self.OneHelper = None
else:
self.OneHelper = OneHelper
def blah(self):
if self.OneHelper:
self.OneHelper.blah()
Your example looks funny because if the module fails to import what is the point of calling it later?
You might also consider using global OneHelper before importing the module. This adds the OneHelper to the global namespace.