Need a little help understanding what I am doing wrong. Probably pretty basic, but I haven't wrapped my brain around it.
My code is this:
class baseElement(object):
def __init__(self):
self.Portal = ''
self.locator = ''
def present(self):
return self.Portal.PTF.Presence_of_Element(self.locator)
def visible(self):
return self.Portal.PTF.Is_Element_Visible(self.locator)
class baseActiveElement(baseElement):
def hover(self):
self.Portal.PTF.Mouse_over_element(self.locator)
def click(self):
self.Portal.PTF.Click_on_Element(self.locator)
def get(self):
return self.locator
I define the Portal when I instantiate objects from these bases and it includes some functions to perform the specified actions. This works. No problems there.
But pylint complains thusly:
E1101: 8,15:baseElement.present: Instance of 'str' has no 'PTF' member
E1101: 11,15:baseElement.visible: Instance of 'str' has no 'PTF' member
E1101: 15,8:baseActiveElement.hover: Instance of 'str' has no 'PTF' member
E1101: 18,8:baseActiveElement.click: Instance of 'str' has no 'PTF' member
What should I be doing to not cause this error?
Edit:
If I change my init to this:
class baseElement(object):
def __init__(self):
self.Portal = object
self.Portal.PTF = self.Portal.PTF
self.locator = ''
The pylint objection goes away, and I can see the value of defining portal as a base object, since it will eventually be a real object, but defining Portal.PTF as itself looks like nonsense to me.
The recommended python way is to initialize self.Portal and self.locator to None in __init__ if your API does not require client code to supply values for these attributes to the __int__ method (in which case, your class API is probably lacking a method to set the value of these two attributes).
Pylint tries to do type inference: if the only affectation to self.Portal it can see in your code is with a string, it will infer that the type of the attribute is str, and use this to check calls performed on self.Portal.
If you write:
class baseElement(object):
def __init__(self, portal, locator):
self.Portal = portal
self.locator = locator
It will try know that it knows nothing about the type of portal and locator.
If you have in the same module code such as:
from somewhere import PortalClass, LocatorClass
# [...]
element = SomeClassDerivingFromBaseElement(PortalClass(), LocatorClass())
then Pylint will be able to use this to gather some knowledge about the possible type of portal and locator, and it will be able to analyze the definitions of PortalClass and LocatorClass for attributes such as PTF, and probably check the prototype of Presence_of_Element.
Sidenote: I suggest to try to achieve some consistency in the naming of your classes, attributes and methods. Pylint will help you and you can customize the regexps it uses to match the naming conventions you use.
Related
I'm creating a structure of classes for a wrapper of an API I'm currently writing.
I have multiple classes defined inside my models file. I want to assign the default value of some attributes of classes to other classes. When I do this, I get a NameError because sometimes I try to use classes that are defined below the current class, thus Python does not know these classes yet. I've tried multiple solutions but none of them seem to work. Does anybody know an alternative or has experience with this?
my classes I've defined:
class RateResponse(BaseModel):
def __init__(self,
provider=Provider()
):
self.provider = provider
class Provider(ObjectListModel):
def __init__(self):
super(Provider, self).__init__(list=[], listObject=ProviderItem)
#property
def providerItems(self):
return self.list
class ProviderItem(BaseModel):
def __init__(self,
code=None,
notification=Notification(),
service=Service()
):
self.code = code
self.notification = notification
self.service = service
As you can see above, I'm initialising the attribute 'provider' on the class RateResponse with the an empty object of the class Provider, which is defined below it. I'm getting a NameError on this line because it's defined below RateResponse.
provider=Provider()
NameError: name 'Provider' is not defined
The simple solution to above would be to shift the places of the classes. However, this is only a snippet of my file that is currently 400 lines long, all with these types of classes and initializations. It would be impossible to order them all correctly.
I've looked up some solutions where I thought I could return an empty object of a class by a string. I thought the function would only evaluate after all the classes were defined, but I was wrong. This is what I tried:
def getInstanceByString(classStr):
return globals()[classStr]()
class RateResponse(BaseModel):
def __init__(self,
provider=getInstanceByString('Provider')
):
self.provider = provider
But to no avail. Does anybody have experience with this? Is this even possible within Python? Is my structure just wrong? Any help is appreciated. Thanks.
This code might not mean what you want it to mean:
class RateResponse(BaseModel):
def __init__(self,
provider=Provider()
):
...
This code is saying that when this class is declared you want to make an instance of Provider which will be the default value for the provider parameter.
You may have meant that the default argument should be a new instance of Provider for each client that makes an instance of RateResponse.
You can use the Mutable Default Argument pattern to get the latter:
class RateResponse(BaseModel):
def __init__(self, provider=None):
if provider is None:
provider = Provider()
...
However, if you really do want a single instance when the client wants the default you could add a single instance below the Provider definition:
class Provider(ObjectListModel):
...
Singleton_Provider = Provider()
Then the RateResponse class could still use the current pattern, but instead perform this assignment inside the if:
if provider is None:
provider = Singleton_Provider
At the time that the assignment is performed, the Singleton_Provider will have been created.
I have two classes that look like this:
class BaseClass:
def the_dct(self):
return self.THE_DCT
class Kid(BaseClass):
THE_DCT = {'key': 'value'}
# Code i ll be running
inst = Kid()
print(inst.the_dct())
Inheritance has to be this way; second class containing THE_DCT and first class containing def the_dct.
It works just fine, but my problem is that i get a warning in Pycharm (unresolved attribute reference), about THE_DCT in BaseClass.
Is there a reason why it's warning me (as in why i should avoid it)?
Is there something i should do differently?
Within BaseClass you reference self.THE_DCT, yet when PyCharm looks at this class, it sees that THE_DCT doesn't exist.
Assuming you are treating this as an Abstract Class, PyCharm doesn't know that that is your intention. All it sees is a class accessing an attribute, which doesn't exist, and therefore it displays the warning.
Although your code will run perfectly fine (as long as you never instantiate BaseClass), you should really change it to:
class BaseClass(object):
THE_DCT = {}
def the_dct(self):
return self.THE_DCT
In addition to the existing answers, or as an alternative, you can use Type Hints. This satisfies PyCharm's warnings and also distinguishes the attribute as being inherited (or at least not native to the class). It's as simple as adding THE_DCT: dict at the very top of your class (before anything else).
class BaseClass(object):
THE_DCT: dict # Add a type-hint at the top of the class, before anything else
def the_dct(self):
return self.THE_DCT
class Kid(BaseClass):
THE_DCT = {'vars': 'values'}
I prefer this approach because it negates the need to unnecessarily add a placeholder attribute (self.THE_DCT = {}) and, because it's visually different than declaring an attribute, it can also negate the need for adding a comment next to the placeholder attribute to explain that it's inherited.
I have two classes that look like this:
class BaseClass:
def the_dct(self):
return self.THE_DCT
class Kid(BaseClass):
THE_DCT = {'key': 'value'}
# Code i ll be running
inst = Kid()
print(inst.the_dct())
Inheritance has to be this way; second class containing THE_DCT and first class containing def the_dct.
It works just fine, but my problem is that i get a warning in Pycharm (unresolved attribute reference), about THE_DCT in BaseClass.
Is there a reason why it's warning me (as in why i should avoid it)?
Is there something i should do differently?
Within BaseClass you reference self.THE_DCT, yet when PyCharm looks at this class, it sees that THE_DCT doesn't exist.
Assuming you are treating this as an Abstract Class, PyCharm doesn't know that that is your intention. All it sees is a class accessing an attribute, which doesn't exist, and therefore it displays the warning.
Although your code will run perfectly fine (as long as you never instantiate BaseClass), you should really change it to:
class BaseClass(object):
THE_DCT = {}
def the_dct(self):
return self.THE_DCT
In addition to the existing answers, or as an alternative, you can use Type Hints. This satisfies PyCharm's warnings and also distinguishes the attribute as being inherited (or at least not native to the class). It's as simple as adding THE_DCT: dict at the very top of your class (before anything else).
class BaseClass(object):
THE_DCT: dict # Add a type-hint at the top of the class, before anything else
def the_dct(self):
return self.THE_DCT
class Kid(BaseClass):
THE_DCT = {'vars': 'values'}
I prefer this approach because it negates the need to unnecessarily add a placeholder attribute (self.THE_DCT = {}) and, because it's visually different than declaring an attribute, it can also negate the need for adding a comment next to the placeholder attribute to explain that it's inherited.
Can someone explain why this code crashes? What I think should happen is that it should not crash if it is using fully qualified trait names, which it is in this case.
from traits.api import *
from traitsui.api import *
class Struct(HasTraits): pass
class Struct1(Struct):
some_data=Int(4)
some_more_data=Str('pizza')
class Struct2(Struct):
some_data=Int(5)
some_more_data=Str('wossar')
class Subwindow(Handler):
struct1=Instance(Struct1)
struct2=Instance(Struct2)
which_struct=Enum(1,2)
cur_struct=Any
def _struct1_default(self): return Struct1()
def _struct2_default(self): return Struct2()
def _cur_struct(self): return self.struct1
#on_trait_change('which_struct')
def switch_views(self): NotImplemented #switch views here
traits_view=View(
Item(name='which_struct'),
Item(name='object.cur_struct.some_data'),
Item(name='object.cur_struct.some_more_data'),
)
Subwindow().configure_traits()
When I run this, I get
AttributeError: 'Subwindow' object has no attribute 'object.cur_struct.some_data'
but it does, if you inspect the object.
I was fiddling with this example and I made it work correctly if I replace cur_struct with a Property trait, and I don't know why. However, that isn't feasible for my real application, where another class listens for events from an entirely different class and switches cur_struct.
Ah, don't use Item(name=...). Just pass the name as the first positional argument. The constructor does some special processing on the value passed to it before assigning it to the name trait. Explicitly using name is only used internally when we need to avoid that processing.
I have a set of related classes that all inherit from one base class. I would like to use a factory method to instantiate objects for these classes. I want to do this because then I can store the objects in a dictionary keyed by the class name before returning the object to the caller. Then if there is a request for an object of a particular class, I can check to see whether one already exists in my dictionary. If not, I'll instantiate it and add it to the dictionary. If so, then I'll return the existing object from the dictionary. This will essentially turn all the classes in my module into singletons.
I want to do this because the base class that they all inherit from does some automatic wrapping of the functions in the subclasses, and I don't want to the functions to get wrapped more than once, which is what happens currently if two objects of the same class are created.
The only way I can think of doing this is to check the stacktrace in the __init__() method of the base class, which will always be called, and to throw an exception if the stacktrace does not show that the request to make the object is coming from the factory function.
Is this a good idea?
Edit: Here is the source code for my base class. I've been told that I need to figure out metaclasses to accomplish this more elegantly, but this is what I have for now. All Page objects use the same Selenium Webdriver instance, which is in the driver module imported at the top. This driver is very expensive to initialize -- it is initialized the first time a LoginPage is created. After it is initialized the initialize() method will return the existing driver instead of creating a new one. The idea is that the user must begin by creating a LoginPage. There will eventually be dozens of Page classes defined and they will be used by unit testing code to verify that the behavior of a website is correct.
from driver import get_driver, urlpath, initialize
from settings import urlpaths
class DriverPageMismatchException(Exception):
pass
class URLVerifyingPage(object):
# we add logic in __init__() to check the expected urlpath for the page
# against the urlpath that the driver is showing - we only want the page's
# methods to be invokable if the driver is actualy at the appropriate page.
# If the driver shows a different urlpath than the page is supposed to
# have, the method should throw a DriverPageMismatchException
def __init__(self):
self.driver = get_driver()
self._adjust_methods(self.__class__)
def _adjust_methods(self, cls):
for attr, val in cls.__dict__.iteritems():
if callable(val) and not attr.startswith("_"):
print "adjusting:"+str(attr)+" - "+str(val)
setattr(
cls,
attr,
self._add_wrapper_to_confirm_page_matches_driver(val)
)
for base in cls.__bases__:
if base.__name__ == 'URLVerifyingPage': break
self._adjust_methods(base)
def _add_wrapper_to_confirm_page_matches_driver(self, page_method):
def _wrapper(self, *args, **kwargs):
if urlpath() != urlpaths[self.__class__.__name__]:
raise DriverPageMismatchException(
"path is '"+urlpath()+
"' but '"+urlpaths[self.__class.__name__]+"' expected "+
"for "+self.__class.__name__
)
return page_method(self, *args, **kwargs)
return _wrapper
class LoginPage(URLVerifyingPage):
def __init__(self, username=username, password=password, baseurl="http://example.com/"):
self.username = username
self.password = password
self.driver = initialize(baseurl)
super(LoginPage, self).__init__()
def login(self):
driver.find_element_by_id("username").clear()
driver.find_element_by_id("username").send_keys(self.username)
driver.find_element_by_id("password").clear()
driver.find_element_by_id("password").send_keys(self.password)
driver.find_element_by_id("login_button").click()
return HomePage()
class HomePage(URLVerifyingPage):
def some_method(self):
...
return SomePage()
def many_more_methods(self):
...
return ManyMorePages()
It's no big deal if a page gets instantiated a handful of times -- the methods will just get wrapped a handful of times and a handful of unnecessary checks will take place, but everything will still work. But it would be bad if a page was instantiated dozens or hundreds or tens of thousands of times. I could just put a flag in the class definition for each page and check to see if the methods have already been wrapped, but I like the idea of keeping the class definitions pure and clean and shoving all the hocus-pocus into a deep corner of my system where no one can see it and it just works.
In Python, it's almost never worth trying to "force" anything. Whatever you come up with, someone can get around it by monkeypatching your class, copying and editing the source, fooling around with bytecode, etc.
So, just write your factory, and document that as the right way to get an instance of your class, and expect anyone who writes code using your classes to understand TOOWTDI, and not violate it unless she really knows what she's doing and is willing to figure out and deal with the consequences.
If you're just trying to prevent accidents, rather than intentional "misuse", that's a different story. In fact, it's just standard design-by-contract: check the invariant. Of course at this point, SillyBaseClass is already screwed up, and it's too late to repair it, and all you can do is assert, raise, log, or whatever else is appropriate. But that's what you want: it's a logic error in the application, and the only thing to do is get the programmer to fix it, so assert is probably exactly what you want.
So:
class SillyBaseClass:
singletons = {}
class Foo(SillyBaseClass):
def __init__(self):
assert self.__class__ not in SillyBaseClass.singletons
def get_foo():
if Foo not in SillyBaseClass.singletons:
SillyBaseClass.singletons[Foo] = Foo()
return SillyBaseClass.singletons[Foo]
If you really do want to stop things from getting this far, you can check the invariant earlier, in the __new__ method, but unless "SillyBaseClass got screwed up" is equivalent to "launch the nukes", why bother?
it sounds like you want to provide a __new__ implementation: Something like:
class MySingledtonBase(object):
instance_cache = {}
def __new__(cls, arg1, arg2):
if cls in MySingletonBase.instance_cache:
return MySingletonBase.instance_cache[cls]
self = super(MySingletonBase, cls).__new__(arg1, arg2)
MySingletonBase.instance_cache[cls] = self
return self
Rather than adding complex code to catch mistakes at runtime, I'd first try to use convention to guide users of your module to do the right thing on their own.
Give your classes "private" names (prefixed by an underscore), give them names that suggest they shouldn't be instantiated (eg _Internal...) and make your factory function "public".
That is, something like this:
class _InternalSubClassOne(_BaseClass):
...
class _InternalSubClassTwo(_BaseClass):
...
# An example factory function.
def new_object(arg):
return _InternalSubClassOne() if arg == 'one' else _InternalSubClassTwo()
I'd also add docstrings or comments to each class, like "Don't instantiate this class by hand, use the factory method new_object."
You can also just nest classes in factory method, as described here:
https://python-3-patterns-idioms-test.readthedocs.io/en/latest/Factory.html#preventing-direct-creation
Working example from mentioned source:
# Factory/shapefact1/NestedShapeFactory.py
import random
class Shape(object):
types = []
def factory(type):
class Circle(Shape):
def draw(self): print("Circle.draw")
def erase(self): print("Circle.erase")
class Square(Shape):
def draw(self): print("Square.draw")
def erase(self): print("Square.erase")
if type == "Circle": return Circle()
if type == "Square": return Square()
assert 0, "Bad shape creation: " + type
def shapeNameGen(n):
for i in range(n):
yield factory(random.choice(["Circle", "Square"]))
# Circle() # Not defined
for shape in shapeNameGen(7):
shape.draw()
shape.erase()
I'm not fan of this solution, just want to add this as one more option.