Unable to locate object referenced in object method without redundant import - python

I was attempting to render a Jinja2 template while passing in a single parameter. This parameter is an instance of an object which has a method that references a second object. The object I'm passing into Jinja2 is stored in one module, while the referenced object is stored in a second module. The rendering takes place in a third module. The original code would error out when the first object's method references the second object (global name ... is not defined). This method works fine outside of Jinja2. Here's a simple example to set the scene...
The jinja2 rendering module looks like this:
from jinja2 import Template
from module1 import *
from module2 import *
def return_rendered():
otr = ObjectToRender()
otr.name = 'Just making the instance special!'
temp_str = open('template.html', 'r')
template = Template(temp_str.read())
temp_str.close()
return template.render(otr=otr)
and the template looks like this:
<p>Here is the output from a super cool method!<p>
{{ otr.get_a_cool_name() }}
The object to render:
# module1
class ObjectToRender(object):
def __init__(self):
self.name = ''
def get_a_cool_name(self):
rc = ReferencedClass() # fails here with "global name
# 'ReferencedClass' is not defined"
return rc.make_cool(self.name)
from module2 import *
and the referenced class:
# module2
from module1 import *
class ReferencedClass(object):
def __init__(self):
self.cool_str = 'SUPER COOL'
def make_cool(self, in_str):
return in_str + self.cool_str
You'll notice I've imported modules 1 and 2 "into each other". It's obviously not necessary here, but in my use case it is. Anyway, I was able to get this working by importing the second class again, just before the ReferencedClass is used. It looks like this:
# module1
class ObjectToRender(object):
def __init__(self):
self.name = ''
def get_a_cool_name(self):
from module2 import ReferencedClass
rc = ReferencedClass() # it works!
return rc.make_cool(self.name)
from module2 import *
So, I got it working without really understanding why it didn't work in the first place... Classic. Does anyone know why I'm having to import this class a second time?

Related

Redundant classname references in Python

My python program has the following structure
projectfolder
|--classes
|--__init__.py
|--Exampleclass.py
|--singletons
|--__init__.py
|--Examplesingleton.py
__init__.py
Main.py
Basically, in my main class, I want to create several instances of Exampleclass.py (and other classes from the folder classes) and put them inside an instance of Examplesingleton.py (basically the "World" that is populated by the instances of classes).
The problem is, I always have to call Examplesingleton and Exampleclass like this:
Main.py
import singletons.Examplesingleton as Examplesingleton
import classes.Exampleclass as Exampleclass
test = Exampleclass.Exampleclass("test")
Examplesingleton.Examplesingleton.Exampleclasses.append(test)
Is there a way in Python to reference these classes without typing the Class name twice?
Instead of
Exampleclass.Exampleclass()
I want to write just
Exampleclass()
I tried using
from classes.Exampleclass import Exampleclass
seems to enable that but leads to circular import error messages.
Exampleclass.py:
class Exampleclass:
Somevariable = 0
def __init__(self, somevariable):
self.Somevariable = somevariable
Examplesingleton.py:
class Examplesingleton(object):
Exampleclasses = []
#classmethod
def __init__(cls):
pass

python: call a class from a script in a different directory and get function

I have a script that I am currently working on, named exp1.py and it's located in
/project/exp1.py
In this script, I am trying to call a function named computelikelihood(), which is inside the class Class(), which is in script method.py, in a different directory:
/project/methods/c_CLASS/method.py
So, in my code in exp1.py, I do this:
import sys
sys.path.append('/project/methods/c_CLASS/')
Which gets me to the folder where method.py is located, but when I want to call the Class() from the method.py, so that I get the function computelikelihood(), that I actually want, I get error. I try this:
from method import Class
from Class import computelikelihood
But I get ImportError: No module named Class. Can anyone help?
EDIT
This is how the __init__ of my Class looks like:
class Class:
def __init__(self,e2wl,w2el,label_set):
self.e2wl = e2wl
self.w2el = w2el
self.workers = self.w2el.keys()
self.examples = self.e2wl.keys()
self.label_set = label_set
Since you are trying to use a method from a Class, you should do so via the class. Do not import the function alone as it isn't intended to be used as such:
from method import Class
Class.computelikelihood()
However, this only works if computelikelihood is a static/class method:
class Class:
#classmethod
def computelikelihood(cls):
...
# or
#staticmethod
def computelikelihood():
...
If it's an instance method:
class Class:
def computelikelihood(self):
...
You'll need to first instantiate an object of class Class:
from method import Class
classObject = Class()
classObject.computelikelihood()

How to know if a variable is imported in python2.7?

I want to list variables "defined" in a module. And then I found there is no way to distinct variables defined in the module and variables imported from other modules. Is there any way to know if a variable is imported?
I KNOW inspect.getmembers and inspect.getmodule and dir but my concern is variable, not function or class definition.
AND I KNOW I COULD IMPORT MODULE RATHER THAN IMPORT VARIABLE FROM MODULE.
I just want to know is there a way or not :).
a.py, define a class
class A(object):
pass
b.py, define a instance using class A
from a import A
ins_b = A()
c.py, define another instance using class A and
from a import A
from b import ins_b
ins_c = A()
I want to list variables like this:
["b.ins_b", "c.ins_c"]
but actually I could do is :
{
<a.A instance at pos1>: ["b.ins_b", "c.ins_b"],
<a.A instance at pos2>: ["c.ins_c"],
}
OK. Thanks to #juanpa.arrivillaga I know it is impossible to do this.
And I just change the problem: how to know "the module which object is created" and "the attr name which the object is assigned".
I try to find something like "metaclass", maybe "metamodule" but I find it changes many behaviors which I do not need.
So according to "How to use inspect to get the caller's info from callee in Python?" and "Retrieve module object from stack frame", I do some trick to realize my idea.
import inspect
import re
attr_r = re.compile(u"\s*([^\s=]+)\s*=")
class A(object):
def __init__(self):
pre_frame = inspect.currentframe().f_back
frame_info = inspect.getframeinfo(pre_frame)
self.init_module_name = inspect.getmodule(pre_frame).__name__
self.init_attr_name = ""
if len(frame_info[3]) > 0:
line = frame_info[3][0]
m = attr_r.match(line)
if m:
self.init_attr_name = m.group(1)
the method to get attr name is trick but work for me.
# init_module_name == "a"
a = A()
print a.init_module_name, a.init_attr_name
# init_module_name == "a"
a = b = A()
print a.init_module_name, a.init_attr_name
# init_module_name == ""
a = \
A()
print a.init_module_name, a.init_attr_name

python module __init__ function

Is there any way to make an implicit initializer for modules (not packages)?
Something like:
#file: mymodule.py
def __init__(val):
global value
value = 5
And when you import it:
#file: mainmodule.py
import mymodule(5)
The import statement uses the builtin __import__ function.
Therefore it's not possible to have a module __init__ function.
You'll have to call it yourself:
import mymodule
mymodule.__init__(5)
These things often are not closed as duplicates, so here's a really nice solution from Pass Variable On Import. TL;DR: use a config module, configure that before importing your module.
[...] A cleaner way to do it which is very useful for multiple configuration
items in your project is to create a separate Configuration module
that is imported by your wrapping code first, and the items set at
runtime, before your functional module imports it. This pattern is
often used in other projects.
myconfig/__init__.py :
PATH_TO_R_SOURCE = '/default/R/source/path'
OTHER_CONFIG_ITEM = 'DEFAULT'
PI = 3.14
mymodule/__init__.py :
import myconfig
PATH_TO_R_SOURCE = myconfig.PATH_TO_R_SOURCE
robjects.r.source(PATH_TO_R_SOURCE, chdir = True) ## this takes time
class SomeClass:
def __init__(self, aCurve):
self._curve = aCurve
if myconfig.VERSION is not None:
version = myconfig.VERSION
else:
version = "UNDEFINED"
two_pi = myconfig.PI * 2
And you can change the behaviour of your module at runtime from the
wrapper:
run.py :
import myconfig
myconfig.PATH_TO_R_SOURCE = 'actual/path/to/R/source'
myconfig.PI = 3.14159
# we can even add a new configuration item that isn't present in the original myconfig:
myconfig.VERSION="1.0"
import mymodule
print "Mymodule.two_pi = %r" % mymodule.two_pi
print "Mymodule.version is %s" % mymodule.version
Output:
> Mymodule.two_pi = 6.28318
> Mymodule.version is 1.0

python update class instance to reflect change in a class method

As I work and update a class, I want a class instance that is already created to be updated. How do I go about doing that?
class MyClass:
""" """
def __init__(self):
def myMethod(self, case):
print 'hello'
classInstance = MyClass()
I run Python inside of Maya and on software start the instance is created. When I call classInstance.myMethod() it always prints 'hello' even if I change this.
Thank you,
/Christian
More complete example:
class MayaCore:
'''
Super class and foundational Maya utility library
'''
def __init__(self):
""" MayaCore.__init__(): set initial parameters """
#maya info
self.mayaVer = self.getMayaVersion()
def convertToPyNode(self, node):
"""
SYNOPSIS: checks and converts to PyNode
INPUTS: (string?/PyNode?) node: node name
RETURNS: (PyNode) node
"""
if not re.search('pymel', str(node.__class__)):
if not node.__class__ == str and re.search('Meta', str(node)): return node # pass Meta objects too
return PyNode(node)
else: return node
def verifyMeshSelection(self, all=0):
"""
SYNOPSIS: Verifies the selection to be mesh transform
INPUTS: all = 0 - acts only on the first selected item
all = 1 - acts on all selected items
RETURNS: 0 if not mesh transform or nothing is selected
1 if all/first selected is mesh transform
"""
self.all = all
allSelected = []
error = 0
iSel = ls(sl=1)
if iSel != '':
if self.all: allSelected = ls(sl=1)
else:
allSelected.append(ls(sl=1)[0])
if allSelected:
for each in allSelected:
if nodeType(each) == 'transform' and nodeType(each.getShape()) == 'mesh':
pass
else: error = 1
else: error = 1
else: error = 1
if error: return 0
else: return 1
mCore = MayaCore()
The last line is inside the module file (mCore = MayaCore()).
There are tons of methods inside the class so I have removed them to shorten the scrolling :-)
Also there are import statements above the class but they screw up the formatting for some reason. Here they are:
from pymel.all import *
import re
from maya import OpenMaya as om
from our_libs.configobj import ConfigObj
if getMelGlobal('float', "mVersion") >= 2011:
from PyQt4 import QtGui, QtCore, uic
import sip
from maya import OpenMayaUI as omui
Inside Maya, we import this and subclasses of this class upon program start:
from our_maya.mayaCore import *
In other tools we write, we then call mCore.method() on a need basis.
The caveat I am running into is that when I am going back to modify the mCore method and the instance call is already in play, I have to restart Maya for all the instances to get updated with the method change (they will still use the un-modified method).
Alright, trying again, but with a new understanding of the question:
class Foo(object):
def method(self):
print "Before"
f = Foo()
f.method()
def new_method(self):
print "After"
Foo.method = new_method
f.method()
will print
Before
After
This will work with old style classes too. The key is modifying the class, not overriding the class's name.
You'll have to provide more details about what you are doing, but Python instances don't store methods, they always get them from their class. So if you change the method on the class, existing instances will see the new method.
My other answer answers your original question, so I'm leaving it there, but I think what you really want is the reload function.
import our_maya.mayaCore
reload(our_maya.mayaCore)
from our_maya.mayaCore import *
Do that after you change the class definition. Your new method ought to show up and be used by all the existing instances of your class.

Categories