I'm very much new to Python, essentially being pushed into a new project with no knowledge of the language whatsoever. I've gone over a number of tutorials to get a gist of the syntax and some of the functions, but I'm currently stumped on something that seems pretty basic.
I have a class GeoLocationHandlerObj in GeoLocationSolver.py which has a method 'myMethod':
class GeoLocationHandlerObj(object):
def __init__(self, connector, debug=0):
self._debug = debug
self.locator = GeoLocationSolverObj(connector)
return(None)
def close(self):
...
return(None)
def getAdr(self, point, lang):
...
return(None)
def getCom(self, point, lang):
...
return(None)
def getHmp(self, point, lang):
...
return(None)
def myMethod(self):
print "test"
return(None)
I import it and try to call myFunction:
import sys
import os
import psycopg2
import string
import json
import socket
import random
from GeoPackage.GeoCoding.GeoLocationSolver import *
if __name__ == "__main__":
connector = GeoPSConnectorObj(...)
handler = GeoLocationHandlerObj(connector)
handler.myMethod()
When I run this code, I get the following error:
AttributeError: 'GeoLocationHandlerObj' object has no attribute 'myMethod'.
What am I missing in order to successfully call this method?
I had the same problem, adding two new methods to a previously existing class, trying to call the methods would fail because of "object has no attribute". Finally chased it down to the previous dev using a different tabs/spaces configuration from my editor. Once I changed my new code to use the same configuration as the previous code, Python was able to reference the functions.
Related
I'm asked to develop unit tests for a program which is such badly developed that the tests don't run... but the program does. Thus, I need to explain the reason why and I actually don't know!
Here is a piece of code that intends to represent the code I need to test:
from services import myModule1
from services.spec1 import importedFunc
from services.spec2 import getTool
from services.spec3 import getDict
class myClass(object):
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2
self.param3 = 0
self.param4 = 0
def myMethod(self):
try:
myVar1 = globalDict['key1']
myVar2 = globalDict['key2']
newVar = importedFunc(par1=myVar1, par2=myVar2, par3=extVar3)
calcParam = myModule1.methodMod1(self.param1)
self.param3 = calcParam["keyParam3"]
self.param4 = newVar.meth1(self.param2)
globTools.send_message(self.param3, self.param4)
except:
globTools.error_message(self.param3, self.param4)
return
class myClass2(object):
def __init__(self, *myclass2_params):
# some piece of code to intialize dedicated attributes
self.add_objects()
def add_objects(self):
# Some piece of code
my_class = myClass(**necessary_params)
# Some piece of code
return
if __name__ == '__main__':
globTools = getTool("my_program")
globalDict = getDict(some_params)
# Some piece of code
my_class2 = myClass2(**any_params)
# Some piece of code
As you can see, the problem is that the class and its methods uses global variables, defined in the main scope. And it's just a quick summary because it's actually a bit more complicated, but I hope it's enough to give you an overview of the context and help me understand why the unit test fail.
I tried to mock the imported modules, but I did not manage to a successful result, so I first tried to make it simple and just initialize all parameters.
I went to this test file:
import unittest
from my_module import myClass
from services import myModule1
from services.spec1 import importedFunc
from services.spec2 import getTool
from services.spec3 import getDict
def test_myClass(unittest.TestCase):
def setUp(self):
globTools = getTool("my_program")
globalDict = getDict(some_params)
def test_myMethod(self):
test_class = myClass(*necessary_parameters)
test_res = test_class.myMethod()
self.assertIsNotNone(test_res)
if __name__ == '__main__':
unittest.main()
But the test fail, telling me 'globTools is not defined' when trying to instantiate myClass
I also tried to initialize variables directly in the test method, but the result is the same
And to be complete about the technical environment, I cannot run python programs directly and need to launch a docker environment via a Jenkins pipeline - I'm not very familiar with this but I imagine it should not have an impact on the result
I guess the problem comes from the variable's scopes, but I'm not able to explain it in this case: why the test fail where as the method itself works (yes, it actually works, or at least the program globally runs without)
It's not as bad as you think. Your setUp method just needs to define the appropriate top-level globals in your module, rather than local variables.
import unittest
import my_module
from my_module import myClass
from services import myModule1
from services.spec1 import importedFunc
from services.spec2 import getTool
from services.spec3 import getDict
class test_myClass(unittest.TestCase):
def setUp(self):
my_module.globTools = getTool("my_program")
my_module.globalDict = getDict(some_params)
def test_myMethod(self):
test_class = myClass(*necessary_parameters)
test_res = test_class.myMethod()
self.assertIsNotNone(test_res)
if __name__ == '__main__':
unittest.main()
Depending on how the code uses the two globals, setUpClass might be a better place to initialize them, but it's probably not worth worrying about. Once you have tests for the code, you are in a better position to remove the dependency on these globals from the code.
I am trying to re-use some code from the CoderBot project to build my own web controlled robot.
I am using python3 on a raspberry PI and I have simplified the code just to generate the error.
'''
class myclass():
objClass = None
def init(self):
print("initialised")
#classmethod
def get_it(cls):
if not cls.objClass:
print("objClass does not exist")
cls.objClass = myclass()
print("created")
return cls.objClass
def main(args):
method_list = [method for method in dir(myclass) if method.startswith('_') is False]
print(method_list)
makeone = myclass.get_it()
print(makeone)
print(myclass.get_it())
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
'''
when I run this the following output is produced
'''
['get_it', 'objClass']
objClass does not exist
initialised
created
<__main__.myclass object at 0x7fbe6e1fa0>
<__main__.myclass object at 0x7fbe6e1fa0>
'''
Everything is as I expected.
When I run this code in a separate script
'''
import ct
def main(args):
method_list = [attribute for attribute in dir(ct.myclass) if
callable(getattr(ct.myclass, attribute)) and attribute.startswith('__') is
False]
print(method_list)
two = ct.get_it()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
'''
The following output is produced:
'''
['get_it']
Traceback (most recent call last):
File "/home/pi/classTest/mainct.py", line 35, in <module>
sys.exit(main(sys.argv))
File "/home/pi/classTest/mainct.py", line 30, in main
two = ct.get_it()
AttributeError: module 'ct' has no attribute 'get_it'
'''
This output is telling me that 'get_it' exists in the class, but not when I try and create one.
I am very confused and have looked at lots of tutorials but can't spot what I am doing wrong.
It is probably one of those errors where if I sat down and spoke to someone it would be obvious, but I can't spot it!
Steve
PS I hope the formatting is ok,
As jasonharper said, I was not referencing the class!
When I went back and looked at the original code I had not spotted the change in case.
so with my example the class MyClass should have been defined in a file myclass.py and then referenced as
from myclass import MyClass
then in the code
two = MyClass.get_it()
I have hopefully sorted out the formatting, the post was originally created on my PI and I spent 40 minutes trying to format it correctly.
This problem is definitely closed, thanks for replies
Is "ct" your class?
two = ct()
two.get_it()
In my Python class I have a nested class defined and it works well, but when I try to move the nested class to a separate file I'm having trouble importing it.
I've tried to follow a few tutorials on Mixins and importing but I keep running into the issue of my object not having the attribute of the new method.
class SomeClass():
def __init__(self):
pass
# # This works
# class NestedClass():
# def helloWorld():
# print("Hello World")
# But when I move it to a separate file (nestedclass.py) I'm having trouble importing
from nestedclass import NestedClass
c = SomeClass()
c.NestedClass.helloWorld() # throws an error when I try to import
The error message I receive is "Attribute Error: 'NestedClass' object has no attribute 'helloWorld'
First of all, here are my two python files:
sred.py:
import _thread,time
class Thread:
def __init__(self,time:int,say:str):
self.time=time
self.say=say
def create():
id = _thread.get_ident()
for i in range(5):
print("HALLO", id)
return
from sred import Thread
import time,_thread
_thread.start_new_thread(Thread.create,())
The second one:
main.py
from sred import Thread
import time,_thread
_thread.start_new_thread(Thread.create,())
when executing this it doesn't print anything out, why?
UPDATE:
import _thread
class Thread:
#classmethod
def create():
id = _thread.get_ident()
for i in range(5):
print("HALLO", id)
return
main.py:
from sred import Thread
import time,_thread
_thread.start_new_thread(Thread().create,())
Is this now right, or is there still something wrong?
The create method is missing self as a parameter -- it looks like it should also be a #classmethod if you want to call it as it's written now. Note that your __init__ method is never getting called, because you never instantiate any Thread objects. You may want it to read:
_thread.start_new_thread(Thread().create, ())
i.e., instantiate a thread, then pass its create method to be executed in the new thread. I'm not sure what's happening, but I suspect that something is erroring and the stacktrace is being suppressed by something.
Also, you need to delete the space after the for statement -- it's significant, and it should be throwing you a syntax error about an unexpected indent.
EDIT:
This version runs on my machine:
import _thread
class Thread:
def create(self):
id = _thread.get_ident()
for i in range(5):
print("HALLO", id)
return
_thread.start_new_thread(Thread().create, ())
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.