Function does not return expected instance - python

I have a very specific problem in my code and I just can't figure it out why.
select_desire_tool() returns None.
It seems that when it arrives at return self._associated_instance(value), somehow it finishes some process in the else statement of the for loop and the supposed returned instance is lost.
why is that?
Return specific instance
def _associated_instance(self, argument):
if RegionConstants.SETTINGS == argument:
return Settings()
else:
test.fail("No such instance found.")
raise
## Clicks on desired map tools option
# #param[in] self The self object pointer.
# #param[in] value Map tools option to be selected
# #return specific class instance class instance
def select_desire_tool(self, value):
items_from_list = self.items
for item in items_from_list:
if item.name == value:
while True:
try:
item.click_button()
return self._associated_instance(value)
except LookupError:
Base().Scrollbar().scroll_down()
else:
if not Base().Scrollbar().at_y_end:
Base().Scrollbar().scroll_down()
self.select_desire_tool(value)
else:
test.fail("Option was not found in map tools")
raise

Related

How to make a polymorphic dataclass constructor method

I have 3 dataclass objects say:
class Message1:
def __init__(a):
...
class Message2:
def __init__(d,e,f):
...
class Message3:
def __init__(g,i):
...
For these 3 messages I want to make a factory type method which can return one of the three objects if it succeeds and if not it should return either the one it identified as the correct message to be created but failed at creation or it should notify the user that it could not create any of the messages. Are there any OOP patterns for this?
My initial thought was to do a:
def factory_method(**parameters):
try:
Message1(**parameters)
except TypeError:
try:
Message2(**parameters)
except:
try:
Message3(**parameters)
except:
print("Could not deduce message type")
My issue with this idea is that:
It's not a dynamically scalable solution, with each new message class I introduce I need to add a new try catch block
If the whole nested block structure fails, I have no feedback as to why, was the parameters correct for one of the message but wrong value, or was it plain gibberish?
I realize this might be a bit opinion based on what the best outcome is. At the same time it might be the solution is not too elegant and the simplest way is to just tell the factory_method what kind of message to initialize. Any suggestions or ideas would be appreciated.
If you can't join them all in a single class and you can't point a call to a single class, i would match the arguments to the posible class. To make it work a type hint and a "proxy" class is required. This example asumes that any of the classes wont contain a __init__(*args, **kwargs), and to add a new class you just add it to Message.msg_cls, you can eval the global scope if you don't want to add manually each class.
class Message1:
def __init__(self, a: int, alt=None, num=10):
print('Message 1')
class Message2:
def __init__(self, d: str, e: str, f: int):
print('Message 2')
class Message3:
def __init__(self, g: int, i: any):
print('Message 3')
class Message:
msg_cls = (
Message1,
Message2,
Message3
)
#staticmethod
def eq_kwargs(cls, kwargs):
cls_kwargs = cls.__init__.__defaults__
if cls_kwargs is None:
if len(kwargs) > 0:
return False
else:
return True
cls_astr = cls.__init__.__code__
kw_types = [type(t) for t in cls_kwargs]
for k in kwargs:
if k in cls_astr.co_varnames:
if type(kwargs[k]) in kw_types:
kw_types.remove(type(kwargs[k]))
else:
if type(None) in kw_types:
kw_types.remove(type(None))
else:
return False
else:
return False
return True
#staticmethod
def eq_args(cls, args):
cls_args = cls.__init__.__annotations__
if len(cls_args) != len(args):
return False
for a, b in zip(args, cls_args):
if type(a) != cls_args[b] and cls_args[b] != any:
return False
return True
def __new__(cls, *args, **kwargs):
for mc in Message.msg_cls:
if Message.eq_args(mc, args):
if Message.eq_kwargs(mc, kwargs):
return mc(*args, **kwargs)
raise ValueError('Message.__new__, no match')
if __name__ == '__main__':
ms_1_a = Message(1, alt='a')
ms_1_b = Message(2, alt='a', num=5)
ms_2 = Message('X', 'Y', 5)
ms_3_a = Message(1, [1, 4])
ms_3_b = Message(2, Message(10))

Rasa FormAction doens't get the values

I have been working with rasa, and there are things of the formAction that I still do not understand very well, my question today is why? my formAction is activated but it does not store any slotvalue, if I am using it incorrectly?
Here's my code:
class HotelForm(FormAction):
def name(self):
# type: () -> Text
return "formaejemplo"
#staticmethod
def required_slots(tracker):
return ["tipo_habitacion"]
def slot_mappings(self):
return {'tipo_habitacion':[self.from_entity(entity='tipo_habitacion',intent=['gethabitacion','peticion_habitacion'])]}
#staticmethod
def habitaciones_db():
return ["individual","doble","suite","suite doble"]
def submit(self, dispatcher, tracker, domain):
dispatcher.utter_template('utter_listo', tracker)
return []
def validate(self,dispatcher: CollectingDispatcher,tracker: Tracker,domain: Dict[Text, Any]) -> List[Dict]:
slot_values = self.extract_other_slots(dispatcher, tracker, domain)
print('slot values:',slot_values)
slot_to_fill = tracker.get_slot(REQUESTED_SLOT)
if slot_to_fill:
print('slot values:',slot_values)
slot_values.update(self.extract_requested_slot(dispatcher,tracker, domain))
if not slot_values:
try:
return super().validate(dispatcher, tracker, domain)
except ActionExecutionRejection as e:
# could not extract entity
dispatcher.utter_message(
"Sorry, I could not parse the value correctly. \n"
"Please double check your entry otherwise I will ask you this forever"
)
return []
for slot, value in slot_values.items():
print('Slot: ',slot)
print('valor: ',values)
if slot == 'tipo_habitacion':
if value.lower() not in self.habitaciones_db():
dispatcher.utter_template('utter_wrong_tipo_habitacion', tracker)
# validation failed, set slot to None
slot_values[slot] = None
# validation succeed, set the slots values to the extracted values
return [SlotSet(slot, value) for slot, value in slot_values.items()]
when i print the values (slotvalues) on the console it always empty.
when you print('slot values:',slot_values) the first time, it's only collected extra slots (entities for required slots that it didn't ask for, but picked up anyway). You shouldn't have any of these since you only have one required slot.
As for the second time you print('slot values:',slot_values), you're doing it before slot_values.update(self.extract_requested_slot(dispatcher,tracker, domain)), so it's exactly the same values as before. Try printing it after the updating happens. If you didn't run into the if not slot_values logic, then it should correctly print if you move it to after the update.
Did it correctly print when you did these lines?
print('Slot: ',slot)
print('valor: ',values)

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 :)

Use of arguments with property.deleter

I'm trying to define a property deleter with a parameter for an attribute of Character class as follows:
class Character(object):
_status = None
#property
def status(self):
""" Return _status if it exists or False if not."""
return self._status
#status.setter
def status(self, status_value):
"""
Receive the status and the duration(continous or not) and add
it for the _status.
"""
if not self._status:
self._status = []
self._status.append(status_value)
#status.deleter
def status(self, status_value):
"""
Delete the specified object from the _status list.
"""
status = [value for value in self._status
if status_value in value.keys()]
if status:
self._status.remove(self._status.index(status[0]))
I'm trying to delete a specific object from the status.
>>>a = Character()
>>>a.status = 'Test'
Would return a list with 1 element:
>>>a.status
['Test']
If i set the status again, the old value persists and new one is added to the list:
>>>a.status = 'Dazed'
>>>a.status
['Test', 'Dazed']
As well I want to delete only a specific value from the list:
>>>del a.status('Dazed')
And the expected result should be:
>>> a.status
['Test']
The problem is that hen I try:
del a.status('Dazed')
The following error occurs:
SyntaxError: can't delete function call
Is there any way to use arguments with a property.deleter?
This is odd behaviour you are trying to create, and would likely trip up users of your class. I certainly wouldn't expect:
self.status = "happy"
to add the new string to an existing list.
As far as I'm aware there is no way to pass an argument to a #property.deleter.
A better approach might be to make the character.status a set (I am assuming that you meant this to be an instance attribute, but this all stands for class attributes too):
class Character(object):
def __init__(self, ..., status=None):
if status is None:
self.status = set()
else:
self.status = set(status)
...
conan = Character(..., status=("happy", "cold"))
conan.status.add("tired")
conan.status.remove("happy")
One advantage of a set is that it prevents duplicates. Also, it provides for very fast membership tests (e.g. if "warm" in conan.status:) and you can find out if two Character instances have any of the same status easily:
if conan.status.intersection(other_character.status):

TypeError: 'NoneType' object is not callable when creating an instance of object

Hi next thing is bothering me:
I'm trying to use the next class:
class GameStatus(object):
"""Enum of possible Game statuses."""
__init__ = None
NotStarted, InProgress, Win, Lose = range(4)
def getStatus(number):
return{
0: "NotStarted",
1: "InProgress",
2: "Win",
3: "Lose",
}
in another class(both in same py file).
In this another class in his method init i do next thing:
class Game(object):
"""Handles a game of minesweeper by supplying UI to Board object."""
gameBoard = []
gs = ''
def __init__(self, board):
self.gameBoard = board
gs = GameStatus() //THIS IS THE LINE
And when i try to run the game i get next error message:
File "C:\Users\Dron6\Desktop\Study\Python\ex6\wp-proj06.py", line 423, in __init__
gs = GameStatus()
TypeError: 'NoneType' object is not callable
What am i doing wrong?
You are setting the GameStatus initializer to None:
class GameStatus(object):
__init__ = None
Don't do that. Python expects that to be a method. If you do not want to have a __init__ method, do not specify it at all. At most, make it an empty function:
class GameStatus(object):
def __init__(self, *args, **kw):
# Guaranteed to do nothing. Whatsoever. Whatever arguments you pass in.
pass
If you wanted to create an enum-like object, take a look at How can I represent an 'Enum' in Python?
For Python 2.7, you could use:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
reverse = dict((value, key) for key, value in enums.iteritems())
enums['reverse_mapping'] = reverse
return type('Enum', (), enums)
GameStatus = enum('NotStarted', 'InProgress', 'Win', 'Lose')
print GameStatus.NotStarted # 0
print GameStatus.reverse_mapping[0] # NotStarted
Ok so after small research i found the problem.
The code i got was:
class GameStatus(object):
"""Enum of possible Game statuses."""
__init__ = None
NotStarted, InProgress, Win, Lose = range(4)
I needed to convert nymbers to their value.
So i build:
def getStatus(number):
return{
0: "NotStarted",
1: "InProgress",
2: "Win",
3: "Lose",
}
And couldnt use it, because i couldn't create an object, and this mothod wasn't static.
The solution: Add #staticmethod before the method.
Plus i had one small error with the return switch, the correct version which works is:
#staticmethod
def getStatus(number):
return{
0: "NotStarted",
1: "InProgress",
2: "Win",
3: "Lose",
}[number]
Thanks for all who tried to help.

Categories

Resources