Can a python module have a __repr__? - python

Can a python module have a __repr__? The idea would be to do something like:
import mymodule
print mymodule
EDIT: precision: I mean a user-defined repr!

Short answer: basically the answer is no.
But can't you find the functionality you are looking for using docstrings?
testmodule.py
""" my module test does x and y
"""
class myclass(object):
...
test.py
import testmodule
print testmodule.__doc__
Long answer:
You can define your own __repr__ on a module level (just provide def __repr__(...) but then you'd have to do:
import mymodule
print mymodule.__repr__()
to get the functionality you want.
Have a look at the following python shell session:
>>> import sys # we import the module
>>> sys.__repr__() # works as usual
"<module 'sys' (built-in)>"
>>> sys.__dict__['__repr__'] # but it's not in the modules __dict__ ?
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: '__repr__'
>>> sys.__class__.__dict__['__repr__'] # __repr__ is provided on the module type as a slot wrapper
<slot wrapper '__repr__' of 'module' objects>
>>> sys.__class__.__dict__['__repr__'](sys) # which we should feed an instance of the module type
"<module 'sys' (built-in)>"
So I believe the problem lies within these slot wrapper objects which (from what can be read at the link) have the result of bypassing the usual 'python' way of looking up item attributes.
For these class methods CPython returns C pointers to the corresponding methods on these objects (which then get wrapped in the slot wrapper objects to be callable from the python-side).

You can achieve this effect--if you're willing to turn to the Dark Side of the Force.
Add this to mymodule.py:
import sys
class MyReprModule(mymodule.__class__):
def __init__(self, other):
for attr in dir(other):
setattr(self, attr, getattr(other, attr))
def __repr__(self):
return 'ABCDEFGHIJKLMNOQ'
# THIS LINE MUST BE THE LAST LINE IN YOUR MODULE
sys.modules[__name__] = MyReprModule(sys.modules[__name__])
Lo and behold:
>>> import mymodule
>>> print mymodule
ABCDEFGHIJKLMNOQ
I dimly remember, in previous attempts at similarly evil hacks, having trouble setting special attributes like __class__. I didn't have that trouble when testing this. If you run into that problem, just catch the exception and skip that attribute.

Modules can have a __repr__ function, but it isn't invoked when getting the representation of a module.
So no, you can't do what you want.

As a matter of fact, many modules do [have a __repr__]!
>>> import sys
>>> print(sys)
<module 'sys' (built-in)> #read edit, however, this info didn't come from __repr__ !
also try dir(sys) to see __repr__ is there along with __name__ etc..
Edit:
__repr__ seems to be found in modules, in Python 3.0 and up.
As indicated by Ned Batchelder, this methods is not used by Python when it print out the a module. (A quick experiment, where the repr property was re-assigned showed that...)

No, because __repr__ is a special method (I call it a capability), and it is only ever looked up on the class. Your module is just another instance of the module type, so however you would manage to define a __repr__, it would not be called!

Related

Python using function like variable

I've got a Python module which has several variables with hard-coded values which are used throughout the project. I'd like to bind the variables somehow to a function to redirect to a config file. Is this possible?
# hardcoded_values.py
foo = 'abc'
bar = 1234
# usage somewhere else in another module
from hardcoded_values import *
print foo
print bar
What I want to do is change only hardcoded_values.py, so that print foo transparently calls a function.
# hardcoded_values.py
import config
foo = SomeWrapper(config.get_value, 'foo') # or whatever you can think of to call config.get_value('foo')
...
config.get_value would be a function that is called with parameter 'foo' when using variable foo (as in print foo).
I'm pretty sure that you can't do what you want to do if you import like from hardcoded_values import *.
What you want to do is to set foo to some function, and then apply the property decorator (or equivalent) so that you can call foo as foo rather than foo(). You cannot apply the property decorator to modules for reasons detailed here: Why Is The property Decorator Only Defined For Classes?
Now, if you were to import hardcoded_values then I think there is a way to do what you want to hardcoded_values.foo. I have a pretty good feeling that what I am about to describe is a BAD IDEA that should never be used, but I think it is interesting.
BAD IDEA???
So say you wanted to replace a constant like os.EX_USAGE which on my system is 64 with some function, and then call it as os.EX_USAGE rather than os.EX_USAGE(). We need to be able to use the property decorator, but for that we need a type other than module.
So what can be done is to create a new type on the fly and dump in the __dict__ of a module with a type factory function that takes a module as an argument:
def module_class_factory(module):
ModuleClass = type('ModuleClass' + module.__name__,
(object,), module.__dict__)
return ModuleClass
Now I will import os:
>>> import os
>>> os.EX_USAGE
64
>>> os.getcwd()
'/Users/Eric'
Now I will make a class OsClass, and bind the name os to an instance of this class:
>>> OsClass = module_class_factory(os)
>>> os = OsClass()
>>> os.EX_USAGE
64
>>> os.getcwd()
'/Users/Eric'
Everything still seems to work. Now define a function to replace os.EX_USAGE, noting that it will need to take a dummy self argument:
>>> def foo(self):
... return 42
...
...and bind the class attribute OsClass.EX_USAGE to the function:
>>> OsClass.EX_USAGE = foo
>>> os.EX_USAGE()
42
It works when called by the os object! Now just apply the property decorator:
>>> OsClass.EX_USAGE = property(OsClass.EX_USAGE)
>>> os.EX_USAGE
42
now the constant defined in the module has been transparently replaced by a function call.
You definitely cannot do this if the client code of your module uses from hardcoded_variables import *. That makes references to the contents of hardcoded_variables in the other module's namespace, and you can't do anything with them after that.
If the client code can be changed to just import the module (with e.g. import hardcoded_variables) and then access its attributes (with hardcoded_variables.foo) you do have a chance, but it's a bit awkward.
Python caches modules that have been imported in sys.modules (which is a dictionary). You can replace a module in that dictionary with some other object, such as an instance of a custom class, and use property objects or other descriptors to implement special behavior when you access the object's attributes.
Try making your new hardcoded_variables.py look like this (and consider renaming it, too!):
import sys
class DummyModule(object):
def __init__(self):
self._bar = 1233
#property
def foo(self):
print("foo called!")
return "abc"
#property
def bar(self):
self._bar += 1
return self._bar
if __name__ != "__main__": # Note, this is the opposite of the usual boilerplate
sys.modules[__name__] = DummyModule()
If I understand correctly, you want your hardcoded_variables module evaluated every time you try to access a variable.
I would probably have hardcoded_variables in a document (e.g. json?) and a custom wrapper function like:
import json
def getSettings(var):
with open('path/to/variables.json') as infl:
data = json.load(infl)
return infl[var]

imported modules becomes None when replacing current module in sys.modules using a class object

an unpopular but "supported" python hack (see Guido: https://mail.python.org/pipermail/python-ideas/2012-May/014969.html) that enables __getattr__ usage on module attributes involves the following:
import os, sys
class MyClass(object):
def check_os(self):
print os
sys.modules[__name__] = MyClass()
On import, this the imported module becomes a class instance:
>>> import myModule
>>> myModule
<myModule.MyClass object at 0xf76def2c>
However, in Python-2.7, all other imported modules within the original module is set to None.
>>> repro.check_os()
None
In Python-3.4, everything works:
>>> repro.check_os()
<module 'os' from '/python/3.4.1/lib/python3.4/os.py'>
This feels like something to do with Imported modules become None when running a function, but, anyone knows why this happens internally?
It seems that if you store the original module (without fully replacing it in Python-2) then everything continues to work:
sys.modules[__name__+'_bak'] = sys.modules[__name__]
The problem you are running in to is that in Pythons prior to 3.4 when a module is destroyed (as yours is because you replace it with a class and there are no further references to it), the items in that module's __dict__ are forcibly set to None.
The workaround, if you need to support Pythons prior to 3.4, is have an import statement in the class that will replace the module:
class MyClass(object):
import os
def check_os(self):
print(os)
For more info, see this answer about interpreter shutdown.

Casting in python

I have problem with casting in python.
I have a method in file module_A.py:
import Common.Models.Pax as Pax
def verify_passangers_data(self,paxes):
for i in range(len(paxes)):
pax=paxes[i]
Here is my Pax.py
class Pax:
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
#----------------------------------------------------------------------
class Adult(Pax):
def __init__(self,last_day_of_travel,first_name,last_name,nationality,address=None):
self.birth_day=datetime.today() - timedelta(days = random.randrange(6563, 20793-(date.today()-last_day_of_travel).days))
self.first_name=first_name
self.last_name=last_name
self.nationality=nationality
self.address=address
This is how I create collection in another module(module_C.py):
paxes=[]
paxes.append(Pax.Adult(last_day_of_travel,'FirstName','LastName',Nationality.Poland,DataRepository.addresses['Default']))
but, look at my output from debug probe (in wing ide)
>>> type(pax)
<class 'Common.Models.Pax.Adult'>
>>> pax is Common.Models.Pax.Adult
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
builtins.NameError: name 'Common' is not defined
How can I check is pax is instance of Adult?
How can I check is pax is instance of Adult?
Use the isinstance function:
isinstance(pax, Common.Models.Pax.Adult)
Make you have imported the class, though (e.g., import Common.Models.Pax).
(Although purists would argue that there's rarely a need to check the type of a Python object. Python is dynamically typed, so you should generally check to see if an object responds to a particular method call, rather than checking its type. But you may have a good reason for needing to check the type, too.)
You can use isinstance:
isinstance(pax, Common.Models.Pax.Adult)
Or the builtin type function:
type(pax) == Common.Models.Pax.Adult
Of course, you will have to import the module so that Common.Models.Pax.Adult is defined. That's why you're getting that error at the end.
You need to have imported the type in order to reference it:
>>> x is socket._fileobject
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'socket' is not defined
>>> import socket
>>> x is socket._fileobject
False
Presumably, you obtained the instance pointed to by pax from some other call, so you haven't actually imported the class into your namespace.
Also, is tests object identity (are these the same object?), not type. You want instanceof(pax,Common...).
You have two errors, first one is using is instead of isinstance function. Second is trying to refer module by it's absolute name, but you've imported it with alias.
Thus what you should do is:
isinstance(pax,Pax.Adult)

Python: Can't pickle type X, attribute lookup failed

I am trying to pickle a namedtuple:
from collections import namedtuple
import cPickle
class Foo:
Bar = namedtuple('Bar', ['x', 'y'])
def baz(self):
s = set()
s.add(Foo.Bar(x=2, y=3))
print cPickle.dumps(s)
if __name__ == '__main__':
f = Foo()
f.baz()
This produces the following output:
Traceback (most recent call last):
File "scratch.py", line 15, in <module>
f.baz()
File "scratch.py", line 11, in baz
print cPickle.dumps(s)
cPickle.PicklingError: Can't pickle <class '__main__.Bar'>: attribute lookup __main__.Bar failed
What am I doing wrong? Is the problem that Bar is a member of Foo? (Moving the definition of Bar to the top level solves the problem, although I'm still curious why this happens.)
Yes, the fact that it's a class member is a problem:
>>> class Foo():
... Bar = namedtuple('Bar', ['x','y'])
... def baz(self):
... b = Foo.Bar(x=2, y=3)
... print(type(b))
...
>>> a = Foo()
>>> a.baz()
<class '__main__.Bar'>
The problem is that when namedtuple() returns a type object, it isn't aware of the fact that it's being assigned to a class member - and thus, it tells the type object that its type name should be __main__.Bar, even though it should really be __main__.Foo.Bar.
Nesting classes makes pickle fail, since it relies on the path of the object inside your application to reconstruct it later.
The immediate solution is to not nest classes, i.e. move Bar definition to outside Foo. Code will work all the same.
But a better thing to do is to not use pickle at all to store data. Use some other serialization format, like json, or a database, like sqlite3.
You have just hit one of the many inconveniences of pickle, if you change your code, move things around, or sometimes make small structural changes, your data becomes unloadable.
Besides that, pickle has other disadvantages: It is slow, unsecure, python-only...
Using dill in place of pickle here will allow this to work
The solution here is to move your named tuple definition to the module level, then pickle works. A detailed answer is provided here:
How to pickle a namedtuple instance correctly

Error when calling the metaclass bases: function() argument 1 must be code, not str

I tried to subclass threading.Condition earlier today but it didn't work out. Here is the output of the Python interpreter when I try to subclass the threading.Condition class:
>>> import threading
>>> class ThisWontWork(threading.Condition):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
function() argument 1 must be code, not str
Can someone explain this error? Thanks!
You're getting that exception because, despite its class-like name, threading.Condition is a function, and you cannot subclass functions.
>>> type(threading.Condition)
<type 'function'>
This not-very-helpful error message has been raised on the Python bugtracker, but it has been marked "won't fix."
Different problem than OP had, but you can also get this error if you try to subclass from a module instead of a class (e.g. you try to inherit My.Module instead of My.Module.Class). Kudos to this post for helping me figure this out.
TypeError: Error when calling the metaclass bases
For this one, the answer is that you probably named a python class the
same thing as the module (i.e., the file) that it's in. You then
imported the module and attempted to use it like a class. You did this
because you, like me, were probably a Java programmer not that long
ago :-). The way to fix it is to import the module.class instead of
just the module. Or, for sanity's sake, change the name of the class
or the module so that it's more obvious what's being imported.
With respect to subclassing a module, this is a really easy mistake to make if you have, for example, class Foo defined in a file Foo.py.
When you create a subclass of Foo in a different file, you might accidentally do the following (this is an attempt to subclass a module and will result in an error):
import Foo
class SubclassOfFoo(Foo):
when you really need to do either:
from Foo import Foo
class SubclassOfFoo(Foo):
or:
import Foo
class SubclassofFoo(Foo.Foo):
Gotten into the same problem. Finally solved by taking a keen look at the code and this is where the TypeError that alarms about a string instead of code comes about..
Class Class_name(models.model): //(gives a TypeError of 'str' type)
"And"
Class Class_name(models.Model): // is the correct one.
Notice that specific error comes about because of a single lowercase letter to the code "Model" which in turn makes it a string

Categories