Cannot find metaclass in module - python

I seem to be running into a problem where I can't inherit from another class in the same module. Here's the MCVE I came up with.
The (uninteresting) contents of main.py:
#!/usr/bin/python
import foobar
if __name__ == "__main__":
print("Hello, World!")
The contents of foobar/__init__.py:
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
from foobar.this_one_works import Pucker
from foobar.csend import Csend
That Singleton class up there is shamelessly copy-pasted from here.
It's important to note that __init__ successfully imports the Pucker class from this_one_works.py. Here is the contents of the latter file:
class PuckerMeta():
def __init__(self):
pass
class Pucker(metaclass=PuckerMeta):
def __init__(self):
pass
The contents of foobar/csend.py:
class Csend(metaclass=Singleton):
def __init__(self):
pass
And now running main.py gives the following error:
Traceback (most recent call last):
File "/home/sam/mcve/python/./main.py", line 3, in <module>
import foobar
File "/home/sam/mcve/python/foobar/__init__.py", line 9, in <module>
from foobar.csend import Csend
File "/home/sam/mcve/python/foobar/csend.py", line 1, in <module>
class Csend(Singleton):
NameError: name 'Singleton' is not defined
I'm puzzled about the fact that importing foobar seems to find PuckerMeta okay, but not Singleton. Is there anything special about a class that's defined in __init__.py that means it can't be inherited from or something?
Oh and in case it matters, I'm on Python 3.9.2.

Related

Dynamically add function to class through decorator

I'm trying to find a way to dynamically add methods to a class through decorator.
The decorator i have look like:
def deco(target):
def decorator(function):
#wraps(function)
def wrapper(self, *args, **kwargs):
return function(*args, id=self.id, **kwargs)
setattr(target, function.__name__, wrapper)
return function
return decorator
class A:
pass
# in another module
#deco(A)
def compute(id: str):
return do_compute(id)
# in another module
#deco(A)
def compute2(id: str):
return do_compute2(id)
# **in another module**
a = A()
a.compute() # this should work
a.compute2() # this should work
My hope is the decorator should add the compute() function to class A, any object of A should have the compute() method.
However, in my test, this only works if i explicitly import compute into where an object of A is created. I think i'm missing something obvious, but don't know how to fix it. appreciate any help!
I think this will be quite simpler using a decorator implemented as a class:
class deco:
def __init__(self, cls):
self.cls = cls
def __call__(self, f):
setattr(self.cls, f.__name__, f)
return self.cls
class A:
def __init__(self, val):
self.val = val
#deco(A)
def compute(a_instance):
print(a_instance.val)
A(1).compute()
A(2).compute()
outputs
1
2
But just because you can do it does not mean you should. This can become a debugging nightmare, and will probably give a hard time to any static code analyser or linter (PyCharm for example "complains" with Unresolved attribute reference 'compute' for class 'A')
Why doesn't it work out of the box when we split it to different modules (more specifically, when compute is defined in another module)?
Assume the following:
a.py
print('importing deco and A')
class deco:
def __init__(self, cls):
self.cls = cls
def __call__(self, f):
setattr(self.cls, f.__name__, f)
return self.cls
class A:
def __init__(self, val):
self.val = val
b.py
print('defining compute')
from a import A, deco
#deco(A)
def compute(a_instance):
print(a_instance.val)
main.py
from a import A
print('running main')
A(1).compute()
A(2).compute()
If we execute main.py we get the following:
importing deco and A
running main
Traceback (most recent call last):
A(1).compute()
AttributeError: 'A' object has no attribute 'compute'
Something is missing. defining compute is not outputted. Even worse, compute is never defined, let alone getting bound to A.
Why? because nothing triggered the execution of b.py. Just because it sits there does not mean it gets executed.
We can force its execution by importing it. Feels kind of abusive to me, but it works because importing a file has a side-effect: it executes every piece of code that is not guarded by if __name__ == '__main__, much like importing a module executes its __init__.py file.
main.py
from a import A
import b
print('running main')
A(1).compute()
A(2).compute()
outputs
importing deco and A
defining compute
running main
1
2

Why is a Python class initialized variable not available to a class instance object from a package import but is otherwise?

heyo... i'm learning decorators. interesting stuff. i think i'm missing something though, or maybe it's not the decorators but how i'm working with classes? when I do this in terminal it works:
class Client:
"""The main client."""
def __init__(self, config, creds):
"""Initialize."""
self.config = config
self.creds = creds
def context(func, *args, **kwargs):
#wraps(func)
def func_with_context(*args, **kwargs):
print(f'contextualizing {func.__name__}')
print(creds.user_name)
return (args, kwargs)
return func_with_context
#context
def test(self, creds):
pass
i have two package objects i can instantiate and pass in:
creds = mypackage.credentials.auto()
config = mypackage.Configuration()
and then when i do:
client = Client(config, creds)
client.test('yo')
>>>contextualizing test
username#org
((<__main__.Client object at 0x101b66208>, 'yo'), {})
but when i do this from the package itself i get
import mypackage as mypackage
client = mypackage.Client(config, creds)
client.test('yo')
contextualizing test
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/dblack/Code/mypackage/mypackage/client.py", line 51, in func_with_context
creds.user_name,
NameError: name 'creds' is not defined
why would this work when i just declare a class but not when it's in the package namespace?
Since func_with_context is going to take the place of a method, it should have a self parameter. Then inside it, you can reference the creds attribute using self.creds.
def context(func, *args, **kwargs):
#wraps(func)
def func_with_context(self, *args, **kwargs):
print(f'contextualizing {func.__name__}')
print(self.creds.user_name)
return (args, kwargs)
return func_with_context

Python Inheritance initialize problems

I have threading class in serverThread.py file as shown:
import threading
class serverThread(threading.Thread):
def __init__(self, name):
try:
threading.Thread.__init__(self)
self.name = name
except:
exit()
def run(self):
print("Hello")
I created a new project.I want to inherit class from above class as shown:
import serverThread
class tcpThread(serverThread):
def __init__(self, name):
serverThread.__init__(self,name)
def run():
serverThread.run(self)
t1 = tcpThread("Tcp Server")
t1.start()
When I run this script gives me error:
Error:
Traceback (most recent call last): File "serverTcpThread.py", line 4, in <module> class tcpThread(serverThread): TypeError: module.&lowbar;&lowbar;init&lowbar;&lowbar;() takes at most 2 arguments (3 given)
The error you're reporting is probably because the base class is imported from a bad path, cannot reproduce here.
That said, there's another (similar) error: when redefining the run method, you have to pass the self parameter
class tcpThread(serverThread):
def __init__(self, name):
serverThread.__init__(self,name)
def run(self):
serverThread.run(self)
the code runs fine after that. note that there's no need to redefine the run method only to call the parent method.

initializing python class globally?

I have two files, one of the test.py is
import new.py
class Test:
def __init__(self):
return
def run(self):
return 1
if __name__ == "__main__":
one=Test()
one.run()
and new.py
class New:
def __init__(self):
one.run()
New()
Now when i run python test.py I get this error,
Traceback (most recent call last):
File "test.py", line 1, in <module>
import new.py
File "/home/phanindra/Desktop/new.py", line 5, in <module>
New()
File "/home/phanindra/Desktop/new.py", line 3, in __init__
one.run()
NameError: global name 'one' is not defined
But I want to use this instance of one in my New!!
Can I do this??
edit:
I want to access the variable in test.py in new.py to do some process and give them back to test.py. Isn't this possible?
If you want your New class to use the instance of Test you created, you have to pass it in as part of the constructor.
new.py
class New:
def __init__(self, one):
one.run()
test.py
import new
class Test:
def __init__(self):
return
def run(self):
return 1
if __name__ == "__main__":
one=Test()
two = new.New(one);
Playing around with globals is a great way to break your code without realizing how you did it. It is better to explicitly pass in the reference you want to use.
No, you can't. The closest you can get is to pass the thing you need in to the constructor:
class New(object):
def __init__(self, one):
one.run()
one is defined inside the if __name__=='__main__' block.
Consequently, one will get defined only if test.py is run as a script (rather than imported).
For the module new to access one from the test module, you'll need to pull one out of the if __name__ block:
test.py:
class Test:
def __init__(self):
return
def run(self):
return 1
one=Test()
if __name__ == "__main__":
one.run()
Then access one by the qualified name test.one:
new.py:
import test
class New:
def __init__(self):
test.one.run()
New()

Python Cmd module, subclassing issue

I'm trying to work out what's not working in this code:
#!/usr/bin/python
import cmd
class My_class (cmd.Cmd):
"""docstring for Twitter_handler"""
def __init__(self):
super(My_class, self).__init__()
if __name__ == '__main__':
my_handler = My_class()
Here's the error I get
Traceback (most recent call last):
File "main.py", line 12, in <module>
my_handler = My_class()
File "main.py", line 9, in __init__
super(My_class, self).__init__()
TypeError: super() argument 1 must be type, not classobj
If I change the superclass of "My_class" to an object it works fine. Where am I going wrong?
super() only works for new-style classes
cmd.Cmd is not a new style class in Python 2.5, 2.6, 2.7.
Note that your code does not raise an exception in Python 3.0.
So if super() doesn't work use :
import cmd
class My_class(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self)
You can still use super() if your MyClass extends object. This works even though the cmd.Cmd module is not a new-style class. Like this:
#!/usr/bin/python
import cmd
class My_class (cmd.Cmd, object):
"""docstring for Twitter_handler"""
def __init__(self):
super(My_class, self).__init__()
if __name__ == '__main__':
my_handler = My_class()

Categories

Resources