I'm struggling with understanding the __init __ function for a class when calling another file. This has been asked a lot, and I must be having an off day, because I can't get this to work at all! Well, I take that back.. if I only use __init __ or don't use it at all, it works. it's probably something dumb and obvious that I'm missing - Here's what's up ::
Folder Structure
root
controller
__init __.py
main.py
File 1 - main.py
from controller import appkey , appconf
# log file gets created in here #
app_process = appkey.generate(logfile)
File 2 - controller.__init __.py
from public import printlog
class appkey(object) :
def __init__(self,logfile) :
self.logfile = logfile
def generate(self) :
printlog.log( message = f'Generating runtime key for application instance.'
## <<<< ERROR HAPPENS HERE | AttributeError: 'str' object has no attribute 'logfile' >>>> ##
, file = self.logfile ### <--
, level = 'info' )
try :
<<<< stuff >>>>
return run_ , key_
except :
<<<< mayday | exit >>>>
Visual Studio shows self: 'runtime/application_logs/12072021-122743' as a variable once entering the controller.__init __.py file, but it never becomes "self.logfile".
I appreciate the feedback. Thank you!
The issue is that you are not creating an appkey object anywhere, you are attempting to call generate on the class itself (not an instance of the class). You are also passing logfile to the generate method when you should be passing it to the constructor.
You can change your code in main.py to this or something similar:
# Call the constructor first to create an appkey object, named 'a'
a = appkey(logfile)
# Now call generate on it
app_process = a.generate()
You would need to first create the class object, then call the generate method in main.py.
from controller import appkey , appconf
# log file gets created in here #
appkey_obj = appkey(logfile)
app_process = appkey_obj.generate()
You are setting the value of self.logfile (ie. the logfile instance variable) when you create the object. Since it is an instance variable, you do not need to pass it into the generate` method.
You are getting that error because when you pass logfile into generate, the self argument in generate is being set to the logfile string value. self is also an instance variable that will refer to the object itself when nothing else is passed in. However, since you are passing in logfile, self is set to logfile and it tries to call (basically) logfile.logfile (ie. tries to call an instance variable of the string).
Related
I am a total at writing code let alone python. I am facing this error with the following code.
filename is abcd.py
class device():
def login(self,ip):
self.tn= telnetlib.Telnet(ip)
self.tn.read_until("login: ")
self.tn.write(login)
def sendcommand(self,command):
self.sendcommand= self.tn.write(command)
This python code is imported by another file.
from abcd import *
def foo():
ip = 'ip address'
dev1 = switch()
dev1.login(ip)
dev1.sendcommand('cmd1')
dev1.sendcommand('cmd2')
foo()
When I call the foo function everything executes correctly till we reach dev1.sendcommand('cmd2'). The error received is
dev1.sendcommand('cmd2')
TypeError: 'NoneType' object is not callable
I have simply no clue why its happening. Am I modifying the object in some way?
Yes. When you do self.sendcommand= self.tn.write(command), you overwrite the method sendcommand with the value of self.tn.write(command). Use a different name for the variable than for the method.
The issue seems to be in the line -
def sendcommand(self,command):
self.sendcommand= self.tn.write(command)
You are setting the return value of your writer() to self.sendcommand , which is overwriting the function , you should not do that , just call the function , without setting the return value anywhere . Example -
def sendcommand(self,command):
self.tn.write(command)
Here is part of the code; the parts which seem to be giving me the problem. This is of course part of a larger program. When I run it gives the error message:
unbound method start_data_printer() must be called with printer instance as first argument (got nothing instead)
I have dealt with the error before but can't quite figure it out this time.
from start_geonode_correction_new_style_class_2 import data
## import from the data class
class printer(data):
def start_data_printer(data): ## method to print from data class
import csv
generator_start = data.data_out_start() ## data_out_start: a
## data sifting method in
## data class
outfile = csv.writer(open('start_data_output.csv','wb'))
for row in generator_start:
print row[0:]
outfile.writerows([row])
## writes output from data_func_start function to a .csv file
Below is the main class call to run the program
import os
os.chdir('C:\Users\U2970\Documents\ArcGIS')
reader = open('converted_dataset_01_13_2014_added_top_new_data_01_29_14.csv', 'rb')
from data_printer import printer
class function_calls(object):
if __name__=='__main__':
data_set = printer(reader)
printer.start_data_printer() ## this is where it says the error is
In your code printer is a class. You are trying to call printer method directly with class instead of object and you are not passing argument data to that method.
# create printer object
my_printer = printer()
# call method using object
my_printer.start_data_printer()
This will fix method calling issue. Now methods should be defined as:
class Printer(data):
def start_data_printer(self, generator):
generator_start = generator.get_start()
self.calculate_something()
...
I'll do my best to describe the issue I am having. I am building a Python program that is built on multiple classes and uses the unittest framework. In a nutshell, the Main.py file has a "ValidateDriver" class that defines a "driver" variable as an ElementTree type. If I point this directly to the XML file I need to parse, (i.e. driver = ElementTree.parse(rC:\test.xml)) then I can access it from another class. However, in reality I don't have the actual XML file that is passed in from the command-line until you get to the Main function in the ValidateDriver class. So under the ValidateDriver class driver would really be driver = ElementTree and then in the main function I would reassign that variable to ValidateDriver.driver = ElementTree.parse(args.driver). However, this is the crux. When I go to the other class and try to call ValidateDriver.driver I don't have the "findall" method/attribute available. Again, the only way it will work is to do something like: ElementTree.parse(rC:\test.xml)). If I did this in C# it would work, but I am new to Python and this is kicking my butt. Any help/suggestions is appreciated. I've included the code for both classes.
Main Function:
import sys
import argparse
import xml.etree.ElementTree as ElementTree
import unittest
import Tests.TestManufacturer
class ValidateDriver:
driver = ElementTree
def main(argv):
parser = argparse.ArgumentParser(description='Validation.')
parser.add_argument('-d', '--driver', help='Path and file name xml file', required=True)
parser.add_argument('-v', '--verbosity',
help='Verbosity for test output. 1 for terse, 2 for verbose. Default is verbose',
default=2, type=int)
#args = parser.parse_args()
args = r'C:\test.c4i'
#print ("Validate Driver: %s" % args.driver)
#print ("Verbosity Level: %s" % args.verbosity)
ValidateDriver.driver = ElementTree.parse(r'C:\test.c4i')
loader = unittest.TestLoader()
suite = loader.loadTestsFromModule(Tests.TestManufacturer)
runner = unittest.TextTestRunner(verbosity=2) # TODO Remove this...
# TODO Uncomment this...
runner = unittest.TextTestRunner(verbosity=args.verbosity)
result = runner.run(suite)
if __name__ == "__main__":
main(sys.argv[1:])
Other Class, Test Manufacturer:
import unittest
import Main
manufacturer = ['']
class Tests(unittest.TestCase):
# Test to see if Manufacturer exists.
def test_manufacturer_exists(self):
for m in Main.ValidateDriver.driver.findall('./manufacturer'):
print m.text
Producing the following error:
C:\Python27\python.exe C:\Users\test\PycharmProjects\Validator\Main.py
Traceback (most recent call last):
File "C:\Users\test\PycharmProjects\Validator\Main.py", line 22, in <module>
class ValidateDriver:
File "C:\Users\test\PycharmProjects\Validator\Main.py", line 65, in ValidateDriver
main(sys.argv[1:])
File "C:\Users\test\PycharmProjects\Validator\Main.py", line 36, in main
ValidateDriver.driver = ElementTree.parse(r'C:\test.c4i')
NameError: global name 'ValidateDriver' is not defined
Process finished with exit code 1
The main problem seems to be that your main script is wrapped in a class. There's really no reason for this, and is quite confusing.
if __name__ == "__main__":
main_object = ValidateDriver()
main_object.main(sys.argv[1:])
This should go outside the class definition
This has nothing to do with "findall" being available. The issue is that the class itself hasn't yet been completely declared at the time you try to access it. In python, the file is read top to bottom. For example, this is not allowed:
if __name__ == "__main__":
f()
def f():
...
The call to f must happen at the bottom of the file after it is declared.
What you're doing with ValidateDriver is similar, because the class isn't defined until the statements directly in its body are executed (this is different from functions, whose bodies of course aren't executed until they are called). You call main(sys.argv[1:]) inside the class body, which in turn tries to access ValidateDriver.driver, which doesn't exist yet.
Preferably, the main function, as well as the code which calls it, should be outside the class. As far as I can tell, the class doesn't need to exist at all (this isn't C# or Java -- you can put code directly at the module level without a class container). If you insist on putting it in a class as a static method, it must be defined as a class method:
#classmethod
def main(cls, argv):
...
which can then be called (outside the class definition) like:
ValidateDriver.main(sys.argv[1:])
But I stress that this is non-standard and should not be necessary.
Let's say I've a file a.py and a has a variable var.
In file b.py, I imported, a.py and set a.var = "hello".
Then I imported a.py in c.py and tried to access a.var but I get None.
How to reflect the change in data? It is obvious that two different instances are getting called, but how do I change it?
Edit:
What I am trying to do here is create a config file which constitutes of this:
CONFIG = {
'client_id': 'XX',
'client_secret': 'XX',
'redirect_uri': 'XX'
}
auth_token = ""
auth_url = ""
access_point = ""
Now, let's say I use config.py in the script a.py and set config.access_point = "web"
So, if I import config.py in another file, I want the change to reflect and not return "".
Edit:
Text file seems like an easy way out. I can also use ConfigParser module. But isn't it a bit too much if reading form a file needs to be done in every server request?
As a preliminary, a second import statement, even from another module, does not re-execute code in the source file for the imported module if it has been loaded previously. Instead, importing an already existing module just gives you access to the namespace of that module.
Thus, if you dynamically change variables in your module a, even from code in another module, other modules should in fact see the changed variables.
Consider this test example:
testa.py:
print "Importing module a"
var = ""
testb.py:
import testa
testa.var = "test"
testc.py:
import testa
print testa.var
Now in the python interpreter (or the main script, if you prefer):
>>> import testb
Importing module a
>>> import testc
test
>>>
So you see that the change in var made when importing b is actually seen in c.
I would suspect that your problem lies in whether and in what order your code is actually executed.
In file a.py define a class:
class A:
class_var = False
def __init__(self):
self.object_var = False
Then in b.py import this and instantiate an object of class A:
from a import A
a = A()
Now you can access the attributes of the instance of a.
a.object_var = True
And you can access variables for the class A:
A.class_var = True
If you now check for:
a.class_var
-> True
a.object_var
-> True
another_instance = A()
another_instance.object_var
->False
another_instance.class_var
->True
well , i'd use an text file to set values there,
a.py :
with open("values.txt") as f:
var = f.read()#you can set certain bytes for read
so whenever you import it , it will initialise new value to the var according to the values in the text file , and whenever you want to change the value of var just change the value of the text file
I am trying to access an object which was passed to my function (defined inside my class).
Essentially I am invoking a function publish_alert defined inside class AlertPublishInterface.
caller passes into publish_alert an instance of a class called AlertVO
once I receive this passed argument instance via publish_alert, I am simply trying to access the data members of the passed argument instance inside class AlertPublishInterface (in which called function publish_alert is defined.
I get AttributeError in step 2, i.e., when accessing members of the passed argument instance as:
AttributeError: AlertPublishInterface instance has no attribute 'alert_name'
Here is code snippet:
AlertPublishInterface file:
import datetime
import logging.config
import django_model_importer
logging.config.fileConfig('logging.conf')
logger = logging.getLogger('alert_publish_interface')
from alert.models import AlertRule #Database table objects defined in the model file
from alert.models import AlertType #Database table objects defined in the model file
import AlertVO #This is instance whose members am trying to simple access below...!
class AlertPublishInterface:
def publish_alert(o_alert_vo, dummy_remove):
print o_alert_vo.alert_name #-----1----#
alerttype_id = AlertType.objects.filter(o_alert_vo.alert_name,
o_alert_vo.alert_category, active_exact=1) #-----2----#
return
AlertVO is defined as:
class AlertVO:
def __init__(self, alert_name, alert_category, notes,
monitor_item_id, monitor_item_type, payload):
self.alert_name = alert_name
self.alert_category = alert_category
self.notes = notes
self.monitor_item_id = monitor_item_id
self.monitor_item_type = monitor_item_type
self.payload = payload
calling code snippet (which invokes AlertPublishInterface's publish_alert function):
from AlertVO import AlertVO
from AlertPublishInterface import AlertPublishInterface;
o_alert_vo = AlertVO(alert_name='BATCH_SLA', alert_category='B',
notes="some notes", monitor_item_id=2, monitor_item_type='B',
payload='actual=2, expected=1')
print o_alert_vo.alert_name
print o_alert_vo.alert_category
print o_alert_vo.notes
print o_alert_vo.payload
alert_publish_i = AlertPublishInterface()
alert_publish_i.publish_alert(o_alert_vo)
However it fails at lines marked #-----1----# and #-----2---# above with type error, seems like it's associating AlertVO object (the o_alert_vo instance) with AlertPublishInterface class:
complete block of screen output at run:
python test_publisher.py
In test_publisher
BATCH_SLA
B
some notes
actual=2, expected=1
Traceback (most recent call last):
File "test_publisher.py", line 17, in
alert_publish_i.publish_alert(o_alert_vo.alert_name)
File "/home/achmon/data_process/AlertPublishInterface.py", line 26, in publish_alert
print o_alert_vo.alert_name
AttributeError: AlertPublishInterface instance has no attribute 'alert_name'
Can't rid of above error after a lot of searching around...can someone please help...?
Thanks...!(kinda urgent too...!)
The reason you are getting this error is because the first argument is the class itself. Normally, this is called self.
I can also identify this as being django (in which case, you should also be inheriting, if not from some other django class, then from object to make it a new style class)
Anyway, just add self as your first argument in publish_ alert and it will probably stop throwing that error.
def publish_alert(o_alert_vo, dummy_remove): should be def publish_alert(self, o_alert_vo, dummy_remove):