Issues with 'self' argument and python requests module - python

Having an issue calling function dynamic_exit from class dynamic, called from an imported python file within the project file. Only including enough code to depict an efficient example of my issue.
Call example below:
from lib.core import dynamic
import ...
if requests.get(url).status_code != 200:
clear()
print(" xxxxx \n\n\n")
print("[ !! | Invalid URL ] Status code: {0}".format(
str(requests.get(url).status_code)))
time.sleep(1)
print("\n\n Please enter a valid URL.\nExiting...")
dynamic.dynamic_exit(self=dynamic())
time.sleep(3)
exit()
Lib.core contains:
class dynamic:
def __init__(self):
self.loadSwitch = False
self.analyzeSwitch = False
self.exitSwitch = False
def dynamic_load(self, loadSwitch=True):
self.loadSwitch = loadSwitch
done = False
for c in itertools.cycle(['[ | ]', '[ / ]', '[ - ]', '[ \\ ]']):
if done:
break
sys.stdout.write('\rLoading ' + c)
sys.stdout.flush()
time.sleep(0.1)
# Further along...
if dynamic.dynamic_analyze(): # Separate function -- Irrelevant
t = threading.Thread(target=dynamic_analyze())
t.start()
elif dynamic_exit(): # Separate function -- Irrelevant
t2 = threading.Thread(target=dynamic_exit())
t2.start()
else: # dynamic_load -- Example function
t3 = threading.Thread(target=dynamic_load())
t3.start()
sys.stdout.write('\r[ ✓ ] Process Complete ')
time.sleep(4.5)
done = True
loadSwitch = False
exitSwitch = False
analyzeSwitch = False
Lord, I know it's a mess. First time actually working with classes like this.
Error is as follows:
File "~/test-delete.py", line 11, in <module>
from lib.core import dynamic
File "~/lib/core.py", line 55, in <module>
if dynamic.dynamic_analyze():
TypeError: dynamic_analyze() missing 1 required positional argument: 'self'
The IDE is wanting more than a simple self parameter, it is recommending self=. So unsure of how to handle this.
Basically, need help under the context of the __init__ function and using the self parameter. Trying to call the function setting either exitSwitch, analyzeSwitch, or loadSwitch = True, ifswitch == True, perform either function dynamic_load, dynamic_exit, or dynamic_analyze. Post-completion, set all switches back to False.

The problem is that you are calling instance methods as if they are static methods. In other words, you call the methods as dynamic.dynamic_analyse() where dynamic is a reference to the class, not to an instance of that class.
So proceed as follows:
Name your class with PascalCase -- a common practice to distinguish classes from other things. So yours should be named Dynamic.
Create an instance and assign it to a variable. This one could actually get the name dynamic with lower case initial letter.
Don't pass an instance as argument when calling methods on the instance. Because in the notation a.b(), b will be called with the value for self set to a.
So define the class as:
class Dynamic:
def __init__(self):
self.loadSwitch = False
self.analyzeSwitch = False
self.exitSwitch = False
# ...etc.
Import the class and create an instance like this:
from lib.core import Dynamic
# ...
dynamic = Dynamic() # Create instance
# ...
if dynamic.dynamic_analyze(): # Call method on the instance
# ..etc
Your exit code should have:
dynamic.dynamic_exit() # No argument.
I cannot comment on the rest of your code, as it is hard to tell what it is doing. For instance, I do wonder why you call dynamic_analyse() twice... but this at least will solve the problem with the error you got.

Related

Python: How to use methods from another file

I am kind of a beginner in python and stuck with the part where I have to access methods from a class which reside in a different file.
Here, in File1 i am trying to access find_method from file2 to and do some operation and return values. But somehow its not accessing "find_method" from file2.
id_1.py (File1):
from base_file import base_file
class id_1:
def condition():
day_part_response = ...some response...
current_time = ...some value...
abc = basefile.find_method(x=day_part_response, y=current_time)
base_file.py (File2)
class basefile:
def find_method(self, x, y):
for day in day_response:
start = day["start_time"]
end = day["end_time"]
if (condition): -->(consider this condition is satisfied)
self.start_time = start
self.end_time = end
day_id = day["_id"]
self.entity_ID = day["entity_id"]
self.restore = True
self.create_entity()
return self.start_time, self.end_time, day_id, self.day_part_entity_ID, self.restore
You will need to import using from base_file import basefile. Make sure to use above import statement, your both files 1 & 2 are in same directory.
In base_file.py, check if for your given input satisfies the condition -
if start < end and start < store_time < end or \
end < start and not (end < store_time < start):
otherwise it won't return any result and None will get returned as default.
In id_1.py, check if you are creating instance of the class id_1 like -
id_1_instance = id_1()
and then call the condition method on the instance
id_1_instance.condition()
Since above call receives a returned value, make sure to print it so you can see the output.
You should be doing: from base_file import basefile
If 'base_file.py' is in the same directory as id_1.py
then the import will work. If you put the class in a
different directory, you need to add a line of code
before the import, something like:
sys.path.append("/home/username/python/classes")
You should also take a look at https://peps.python.org/pep-0008/#class-names
which gives you the recommended naming conventions such as:
methods should be in the 'snake' format: def my_method().
Class names should follow the 'camelcase'.
The class MyNewClass() should be saved in a file named: myNewClass.py
So, you would do the import as: from myNewClass import MyNewClass.
I save all my classes in a single 'class' directory.
Of course if you are using Windows, you would have to specify
"C:\whatever".
Hope this helps!

How to update variables passed between classes?

I'm trying to pass variables between different classes. In order to accompish this task, I have created an info class (here called 'declaration') so that the code reads:
class declaration():
def __init__(self):
self.info1 = 999
self.info2 = 'something_else'
print ('At declaration ')
class controller():
def __init__(self):
instance = declaration()
print ('Initial number ',instance.info1, instance.info2)
modifier(declaration)
print ('MIDDLE ',instance.info1,declaration.info1)
instance = declaration()
print ('Final number ',instance.info1)
class modifier():
def __init__(self,aux):
print ('MODIFIER')
self.info=aux
self.info.info1=55555
controller()
The output is:
At declaration
Initial number 999
something else
MODIFIER
MIDDLE 999 55555
At declaration
Final number 999
However, I'm not really sure about some of the inners of the code. I have one major question and a minor one. My main question is that when the class 'modifier' is modified according to:
class modifier():
def __init__(self,aux):
self.info=aux
print ('MODIFIER',self.info.info1)
self.info.info1=55555
it produces the error AttributeError: type object 'declaration' has no attribute 'info1' [Flipping the last 2 lines fixes the error]. It's confusing (at least to me) whether the class attributes are not passed or they have to be reinitialized.
The second question is how to update instance once its class has been updated. The second call to instance = declaration() seems to accomplish nothing.
Quick side note: Yes I do realise, I just want to say please try to follow the PEP8 python guide as it makes your code look cooler (and easier to read) and all the cool kids use it.
There are a few things wrong with your code, calling modifier(declaration) actually makes the aux parameter an uninitilized class, you want to call modifier(instance) as the init function has already been ran.
Also it would be easier to drop the self.info = aux as you can just call aux.info1 and it looks cleaner and is actually faster (Because you are calling one less Fast Store command in bytecode).
Lastly at print ('MIDDLE ',instance.info1,declaration.info1) you again parse declaration uninitilized therefore you get the error AttributeError: type object 'declaration' has no attribute 'info1', to fix this simply put declaration().info1 as that calls the init function (it is the same as saying declaration.__init__().info1).
So finally you get:
class declaration():
def __init__(self):
self.info1 = 999
self.info2 = 'something_else'
print ('At declaration ')
class controller():
def __init__(self):
instance = declaration()
print ('Initial number ', instance.info1, instance.info2)
modifier(instance)
print ('MIDDLE ', instance.info1, declaration().info1)
instance = declaration()
print ('Final number ',instance.info1)
class modifier():
def __init__(self, aux):
print ('MODIFIER')
aux.info1 = 55555
controller()
Hope this helped.

How do I run two or more methods in a class like a chain?

I'm trying to learn OOP but I'm getting very confused with how I'm supposed to run the methods or return values. In the following code I want to run read_chapters() first, then sendData() with some string content that comes from read_chapters(). Some of the solutions I found did not use __init__ but I want to use it (just to see/learn how i can use them).
How do I run them? Without using __init__, why do you only return 'self'?
import datetime
class PrinceMail:
def __init__(self):
self.date2 = datetime.date(2020, 2, 6)
self.date1 = datetime.date.today()
self.days = (self.date1 - self.date2).days
self.file = 'The_Name.txt'
self.chapter = '' # Not sure if it would be better if i initialize chapter here-
# or if i can just use a normal variable later
def read_chapters(self):
with open(self.file, 'r') as book:
content = book.readlines()
indexes = [x for x in range(len(content)) if 'CHAPTER' in content[x]]
indexes = indexes[self.days:]
heading = content[indexes[0]]
try:
for i in (content[indexes[0]:indexes[1]]):
self.chapter += i # can i use normal var and return that instead?
print(self.chapter)
except IndexError:
for i in (content[indexes[0]:]):
self.chapter += i
print(self.chapter)
return self????? # what am i supposed to return? i want to return chapter
# The print works here but returns nothing.
# sendData has to run after readChapters automatically
def sendData(self):
pass
#i want to get the chapter into this and do something with it
def run(self):
self.read_chapters().sendData()
# I tried this method but it doesn't work for sendData
# Is there anyother way to run the two methods?
obj = PrinceMail()
print(obj.run())
#This is kinda confusing as well
Chaining methods is just a way to shorten this code:
temp = self.read_chapters()
temp.sendData()
So, whatever is returned by read_chapters has to have the method sendData. You should put whatever you want to return in read_chapters in a field of the object itself (aka self) in order to use it after chaining.
First of all, __init__ has nothing to do with what you want to achieve here. You can consider it as a constructor for other languages, this is the first function that is called when you create an object of the class.
Now to answer your question, if I am correct you just want to use the output of read_chapters in sendData. One of the way you can do that is by making the read_chapters a private method (that is if you don't want it to use through the object) using __ in the starting of the name like __read_chapters then make a call to the function inside the sendData function.
Another point to consider here is, when you are using self and don't intend to use the function through the object you don't need to return anything. self assigns the value to the attribute of the current instance. So, you can leave the function read_chapters at self.chapter = i and access the same in sendData.
Ex -
def sendData(self):
print(self.chapter)
I'm not an expert but, the reason to return self is because it is the instance of the class you're working with and that's what allows you to chain methods.
For what you're trying to do, method chaining doesn't seem to be the best approach. You want to sendData() for each iteration of the loop in read_chapters()? (you have self.chapter = i which is always overwritten)
Instead, you can store the chapters in a list and send it after all the processing.
Also, and I don't know if this is a good practice but, you can have a getter to return the data if you want to do something different with (return self.chapter instead of self)
I'd change your code for:
import datetime
class PrinceMail:
def __init__(self):
self.date2 = datetime.date(2020, 2, 6)
self.date1 = datetime.date.today()
self.days = (self.date1 - self.date2).days
self.file = 'The_Name.txt'
self.chapter = []
def read_chapters(self):
with open(self.file, 'r') as book:
content = book.readlines()
indexes = [x for x in range(len(content)) if 'CHAPTER' in content[x]]
indexes = indexes[self.days:]
heading = content[indexes[0]]
try:
for i in (content[indexes[0]:indexes[1]]):
self.chapter.append(i)
except IndexError:
#not shure what you want to do here
for i in (content[indexes[0]:]):
self.chapter.append(i)
return self
# sendData has to run after readChapters automatically
def sendData(self):
pass
#do what ever with self.chapter
def get_raw_chapters(self):
return self.chapter
Also, check PEP 8 Style Guide for naming conventions (https://www.python.org/dev/peps/pep-0008/#function-and-variable-names)
More reading in
Method chaining - why is it a good practice, or not?
What __init__ and self do on Python?

python - class calls require me to send self, SpeechEngine.test_choice(SpeechEngine)

I'm having some issues where whenever I make a call to one of my classes methods it's requiring me to specifically send the containing class with the call, where I would expect it to already know about it self. I'm sure this is user error but can not track it down.
I've referenced python - self - required positional argument but i think i've got that covered.
class SpeechEngine():
def __init__(self):
self.conn = sqlite3.connect('../twbot.db')
self.c = self.conn.cursor()
#staticmethod
def choose(choice):
num_choices = len(choice)
selection = random.randrange(0, num_choices)
return selection
def initial_contact_msg(self, userId, screenName):
hello = self.c.execute("SELECT text, id FROM speechConstructs WHERE type='salutation'").fetchall()
tagline = self.c.execute("SELECT text, id FROM speechConstructs WHERE type='tagline'").fetchall()
c1 = self.choose(hello)
c2 = self.choose(tagline)
msg_string = str(hello[c1][0]) + ' #' + screenName + ' ' + tagline[c2][0]
# print(msg_string) # For Testing Only
# print(hello[c1][1]) # For Testing Only
return msg_string
And then I would expect to call
SpeechEngine.initial_contact_msg(0, 'somename')
But that returns the following
missing 1 required positional argument: 'self'
Where as if i do it implicitly
SpeechEngine.initial_contact_msg(SpeechEngine, 0, 'somename')
It returns the expected results no questions asked.
I should also point out the same happens when i would assign it as follows.
test = SpeechEngine
test.initial_contact_msg(0, 'somename')
Since initial_contact_msg is a method, you need to call it from an instance, not the Type. Your last attempt is almost right. To instantiate it, you need to do the following:
test = SpeechEngine()
test.initial_contact_msg(0, 'sometime')
"SpeechEngine" is the type class. When you create a new instance you need to call it like a function. This is similar to using the "new" keyword in other languages.
When you have a static method, this can be called directly from the Type object:
SpeechEngine.choose()
You can read more in the Python Documentation.

How can I split a long function into separate steps while maintaining the relationship between said steps?

I have a very long function func which takes a browser handle and performs a bunch of requests and reads a bunch of responses in a specific order:
def func(browser):
# make sure we are logged in otherwise log in
# make request to /search and check that the page has loaded
# fill form in /search and submit it
# read table of response and return the result as list of objects
Each operation require a large amount of code due to the complexity of the DOM and they tend to grow really fast.
What would be the best way to refactor this function into smaller components so that the following properties still hold:
the execution flow of the operations and/or their preconditions is guaranteed just like in the current version
the preconditions are not checked with asserts against the state, as this is a very costly operation
func can be called multiple times on the browser
?
Just wrap the three helper methods in a class, and track which methods are allowed to run in an instance.
class Helper(object):
def __init__(self):
self.a = True
self.b = False
self.c = False
def funcA(self):
if not self.A:
raise Error("Cannot run funcA now")
# do stuff here
self.a = False
self.b = True
return whatever
def funcB(self):
if not self.B:
raise Error("Cannot run funcB now")
# do stuff here
self.b = False
self.c = True
return whatever
def funcC(self):
if not self.C:
raise Error("Cannot run funcC now")
# do stuff here
self.c = False
self.a = True
return whatever
def func(...):
h = Helper()
h.funcA()
h.funcB()
h.funcC()
# etc
The only way to call a method is if its flag is true, and each method clears its own flag and sets the next method's flag before exiting. As long as you don't touch h.a et al. directly, this ensures that each method can only be called in the proper order.
Alternately, you can use a single flag that is a reference to the function currently allowed to run.
class Helper(object):
def __init__(self):
self.allowed = self.funcA
def funcA(self):
if self.allowed is not self.funcA:
raise Error("Cannot run funcA now")
# do stuff
self.allowed = self.funcB
return whatever
# etc
Here's the solution I came up with. I used a decorator (closely related to the one in this blog post) which only allows for a function to be called once.
def call_only_once(func):
def new_func(*args, **kwargs):
if not new_func._called:
try:
return func(*args, **kwargs)
finally:
new_func._called = True
else:
raise Exception("Already called this once.")
new_func._called = False
return new_func
#call_only_once
def stateA():
print 'Calling stateA only this time'
#call_only_once
def stateB():
print 'Calling stateB only this time'
#call_only_once
def stateC():
print 'Calling stateC only this time'
def state():
stateA()
stateB()
stateC()
if __name__ == "__main__":
state()
You'll see that if you re-call any of the functions, the function will throw an Exception stating that the functions have already been called.
The problem with this is that if you ever need to call state() again, you're hosed. Unless you implement these functions as private functions, I don't think you can do exactly what you want due to the nature of Python's scoping rules.
Edit
You can also remove the else in the decorator and your function will always return None.
Here a snippet I used once for my state machine
class StateMachine(object):
def __init__(self):
self.handlers = {}
self.start_state = None
self.end_states = []
def add_state(self, name, handler, end_state=0):
name = name.upper()
self.handlers[name] = handler
if end_state:
self.end_states.append(name)
def set_start(self, name):
# startup state
self.start_state = name
def run(self, **kw):
"""
Run
:param kw:
:return:
"""
# the first .run call call the first handler with kw keywords
# each registered handler should returns the following handler and the needed kw
try:
handler = self.handlers[self.start_state]
except:
raise InitializationError("must call .set_start() before .run()")
while True:
(new_state, kw) = handler(**kw)
if isinstance(new_state, str):
if new_state in self.end_states:
print("reached ", new_state)
break
else:
handler = self.handlers[new_state]
elif hasattr(new_state, "__call__"):
handler = new_state
else:
return
The use
class MyParser(StateMachine):
def __init__(self):
super().__init__()
# define handlers
# we can define many handler as we want
self.handlers["begin_parse"] = self.begin_parse
# define the startup handler
self.set_start("begin_parse")
def end(self, **kw):
logging.info("End of parsing ")
# no callable handler => end
return None, None
def second(self, **kw):
logging.info("second ")
# do something
# if condition is reach the call `self.end` handler
if ...:
return self.end, {}
def begin_parse(self, **kw):
logging.info("start of parsing ")
# long process until the condition is reach then call the `self.second` handler with kw new keywords
while True:
kw = {}
if ...:
return self.second, kw
# elif other cond:
# return self.other_handler, kw
# elif other cond 2:
# return self.other_handler 2, kw
else:
return self.end, kw
# start the state machine
MyParser().run()
will print
INFO:root:start of parsing
INFO:root:second
INFO:root:End of parsing
You could use local functions in your func function. Ok, they are still declared inside one single global function, but Python is nice enough to still give you access to them for tests.
Here is one example of one function declaring and executing 3 (supposedly heavy) subfunctions. It takes one optional parameter test that when set to TEST prevent actual execution but instead gives external access to individual sub-functions and to a local variable:
def func(test=None):
glob = []
def partA():
glob.append('A')
def partB():
glob.append('B')
def partC():
glob.append('C')
if (test == 'TEST'):
global testA, testB, testC, testCR
testA, testB, testC, testCR = partA, partB, partC, glob
return None
partA()
partB()
partC()
return glob
When you call func, the 3 parts are executed in sequence. But if you first call func('TEST'), you can then access the local glob variable as testCR, and the 3 subfunctions as testA, testB and testC. This way you can still test individually the 3 parts with well defined input and control their output.
I would insist on the suggestion given by #user3159253 in his comment on the original question:
If the sole purpose is readability I would split the func into three "private" > or "protected" ones (i.e. _func1 or __func1) and a private or protected property > which keeps the state shared between the functions.
This makes a lot of sense to me and seems more usual amongst object oriented programming than the other options. Consider this example as an alternative:
Your class (teste.py):
class Test:
def __init__(self):
self.__environment = {} # Protected information to be shared
self.public_stuff = 'public info' # Accessible to outside callers
def func(self):
print "Main function"
self.__func_a()
self.__func_b()
self.__func_c()
print self.__environment
def __func_a(self):
self.__environment['function a says'] = 'hi'
def __func_b(self):
self.__environment['function b says'] = 'hello'
def __func_c(self):
self.__environment['function c says'] = 'hey'
Other file:
from teste import Test
t = Test()
t.func()
This will output:
Main function says hey guys
{'function a says': 'hi', 'function b says': 'hello', 'function c says': 'hey'}
If you try to call one of the protected functions, an error occurs:
Traceback (most recent call last):
File "C:/Users/Lucas/PycharmProjects/testes/other.py", line 6, in <module>
t.__func_a()
AttributeError: Test instance has no attribute '__func_a'
Same thing if you try to access the protected environment variable:
Traceback (most recent call last):
File "C:/Users/Lucas/PycharmProjects/testes/other.py", line 5, in <module>
print t.__environment
AttributeError: Test instance has no attribute '__environment'
In my view this is the most elegant, simple and readable way to solve your problem, let me know if it fits your needs :)

Categories

Resources