How to get all class methods - python

I have the following classes:
class DBManagerInterface:
#abstractmethod
def __init__(self, table_name): raise NotImplementedError
#abstractmethod
def create_table(self): raise NotImplementedError
#abstractmethod
def drop_table(self): raise NotImplementedError
class DataBaseManager(DBManagerInterface):
def __init__(self, table_name):
self.table_name = table_name
def drop_table(self):
None
def create_table(self):
None
class Example:
def __init__(self, db_manager):
self.db_manager = db_manager
def test(self):
self.db_manager.create_table() # can't see the db_manager methods
In Example class I'm getting the DataBaseManager pointer.
I wan't to be able to see all the DataBaseManager methods (without the need to search them manually in DataBaseManager.py file)
I'm using python 3.5.2 and pycharm editor
Is it possible ?

PyCharm has no idea what db_manager could be, so it can't give you edit hints.
If your environment supports it, annotate the argument and PyCharm can do type inference from there:
def __init__(self, db_manager: DBManagerInterface):
self.db_manager = db_manager
or if that's not supported, you can add an annotation in a docstring:
def __init__(self, db_manager):
"""
:type db_manager: DBManagerInterface
"""
self.db_manager = db_manager

The reason you are not able to see the methods of the DataBaseManager class in the attribute db_manager in Example class, is because there is no reason why the variable db_manager in the __init__ method is supposed to be an instance of DataBaseManager.
You can either specify the type directly: https://docs.python.org/3/library/typing.html
Or you can check the instance type in the __init__ method:
class Example:
def __init__(self, db_manager):
if not isinstance(db_manager, DataBaseManager):
raise ValueError
self.db_manager = db_manager
Pycharm will afterwards understand the type of the attribute and show you all the possible methods for the object.

Try
print(dir(DataBaseManager))
From the docs:
Without arguments, return the list of names in the current local scope. With an argument, attempt to return a list of valid attributes for that object.
dir([object])

Related

mypy error: Cannot instantiate abstract class with abstract attributes when adding types to an abstract method

I have a class I would like to add typehints to that looks as following:
import yaml
class TestClass(dict):
#classmethod
def load(cls, fname) -> "TestClass":
return cls(yaml.safe_load(""))
#property
#abc.abstractmethod
def test(self):
raise
when I run mypy on a module containing only this class I get the following error message:
error: Cannot instantiate abstract class 'TestClass' with abstract attribute 'test'
From what I have understood from other posts this has something to do with when the 'test' method is instantiated when executing the load method. Is there a way to fix this issue using typehints alone or would I need to adjust my code here?
What mypy is telling you is that TestClass.load(...) will fail, because it will try to create an instance of the abstract class TestClass.
We can fix this by requiring that cls can be called with whatever yaml.safe_load returns (I'm assuming dict here), and returns an instance of TestClass:
from typing import Callable
import abc
import yaml
class TestClass(dict):
#classmethod
def load(cls: Callable[[dict], TestClass], fname) -> "TestClass":
return cls(yaml.safe_load(""))
#property
#abc.abstractmethod
def test(self):
raise
Note that TestClass.load("foo") will now also pass type checking. This is fair to some extent, because it's also fine at runtime, until you call test() on the created instance. I think this might be a limitation of how mypy implements protocols.

How to add hint to a factory method?

I'm looking for a way to annotate return type of a factory function.
It returns random child of 'AlgorithmBase'.
class AlgorithmFactory:
_algorithm_types = AlgorithmBase.__subclasses__()
def select_random_algorithm(self) -> AlgorithmBase:
# Select random algorithm
algorithm_class = self._random_generator.choice(AlgorithmFactory._algorithm_types)
algorithm = algorithm_class()
return algorithm
I get error from mypy:
The error I'm getting is:
Cannot instantiate abstract class 'AlgorithmBase' with abstract attributes 'get_constraints' and 'satisfy_constraints'
There is no way to instantiate class 'AlgorithmBase' in this code, how to make mypy understand it?
I want to avoid specifying actual sub-classes with 'Union' in return type. Any suggestions?
The problem here wasn't return type, but '_algorithm_types'. mypy has no way to understand what type it is, so it assumed that it is like return type and got error.
The following code fix the issue:
_algorithm_types: List[Type[AlgorithmBase]] = AlgorithmBase.__subclasses__()
As far as I can tell this should work, but it seems like one or more of your AlgorithmBase subclasses doesn't implement these two abstract methods.
Running MyPy for
import abc
class AlgorithmBase(abc.ABC):
#abc.abstractmethod
def get_constraints(self):
raise NotImplementedError
#abc.abstractmethod
def satisfy_constraints(self):
raise NotImplementedError
class SomeAlgorithm(AlgorithmBase):
pass
class AlgorithmFactory:
def get(self) -> AlgorithmBase:
algorithm = SomeAlgorithm()
return algorithm
yields the same error you get, and it runs without any error once the methods are implemented.
import abc
class AlgorithmBase(abc.ABC):
#abc.abstractmethod
def get_constraints(self):
raise NotImplementedError
#abc.abstractmethod
def satisfy_constraints(self):
raise NotImplementedError
class SomeAlgorithm(AlgorithmBase):
def get_constraints(self):
pass
def satisfy_constraints(self):
pass
class AlgorithmFactory:
def get(self) -> AlgorithmBase:
algorithm = SomeAlgorithm()
return algorithm

Python: Call derived class method from another class

I have searched all the related this stackoverflow question but its not satisfied my issue.
BaseHandler.py
class BaseHandler(object):
def __init__(self, rHandler, path, param):
self._rHandler = rHandler
self._server = self._rHandler.server
self._path = path
self._param = param
def _getElement(self, name):
return name + "append"
MyClass.py
class MyClass(BaseHandler.BaseHandler):
def getA(self):
print "Some info"
def getB(self):
el = self._getElement("T") #baseclass method
print ebl
I wanted to call getB from the below class.
RThread.py
import MyClass
class RThread(object):
def someMethod(self):
clr = MyClass.MyClass
clr.getB()
I am getting the following error:
TypeError: unbound method getB() must be called with MyClass instance as first argument (got nothing instead)
When I try the following:
clr = MyClass.MyClass()
I am getting the following error:
init() takes exactly 4 arguments (1 given)
So kindly help me how to call this method from different class.
You need to instantiate the class in order to call a method on it.
def someMethod(self):
clr = MyClass.MyClass(*args)
clr.getB()
In the case you want the method to be callable from the class you need to use either #staticmethod or #classmethod
#staticmethod
def getB():
return self._getElement("T")
However, you are using the self. notation which requires an instance. So you would need to flag the _getElement method with #staticmethod as well. Static methods do not have access to the parent class. You can use the #classmethod decorator to do so.
#classmethod
def getB(cls):
return cls._getElement("T")
You're not calling the method correctly; you need to create an object. This is how you create an object, which is what you were doing, except you weren't passing in enough parameters.
clr = MyClass.MyClass()
Since MyClass inherits from BaseHandler and you did not override its constructor, you're using the constructor from BaseHandler, which has four arguments, one of which is self.
def __init__(self, rHandler, path, param):
...
So, try something like this:
clr = MyClass.MyClass(arg1, arg2, arg3)
clr.getB()

How to incorporate type checking in an abstract base class in Python

When I define a class, I like to include type checking (using assert) of the input variables. I am now defining a 'specialized' class Rule which inherits from an abstract base class (ABC) BaseRule, similar to the following:
import abc
class BaseRule(object):
__metaclass__ = abc.ABCMeta
#abc.abstractproperty
def resources(self):
pass
class Rule(BaseRule):
def __init__(self, resources):
assert all(isinstance(resource, Resource) for resource in resources) # type checking
self._resources = resources
#property
def resources(self):
return self._resources
class Resource(object):
def __init__(self, domain):
self.domain = domain
if __name__ == "__main__":
resources = [Resource("facebook.com")]
rule = Rule(resources)
The assert statement in the __init__ function of the Rule class ensures that the resources input is a list (or other iterable) of Resource objects. However, this would also be the case for other classes which inherit from BaseRule, so I would like to incorporate this assertion in the abstractproperty somehow. How might I go about this?
See this documentation on abc Type annotations with mypy-lang https://mypy.readthedocs.io/en/latest/class_basics.html#abstract-base-classes-and-multiple-inheritance
Make your base class have a non-abstract property that calls separate abstract getter and setter methods. The property can do the validation you want before calling the setter. Other code (such as the __init__ method of a derived class) that wants to trigger the validation can do so by doing its assignment via the property:
class BaseRule(object):
__metaclass__ = abc.ABCMeta
#property
def resources(self): # this property isn't abstract and shouldn't be overridden
return self._get_resources()
#resources.setter
def resources(self, value):
assert all(isinstance(resource, Resources) for resource in value)
self._set_resources(value)
#abstractmethod
def _get_resources(self): # these methods should be, instead
pass
#abstractmethod
def _set_resources(self, value):
pass
class Rule(BaseRule):
def __init__(self, resources):
self.resources = resources # assign via the property to get type-checking!
def _get_resources(self):
return self._resources
def _set_resources(self, value):
self._resources = value
You might even consider moving the __init__ method from Rule into the BaseRule class, since it doesn't need any knowledge about Rule's concrete implementation.

python can't use a property defined in the super (father) class

This is my code
class ElasticsearchController(object):
def __init__(self):
self.es = Elasticsearch(['blabla'], port=9200)
class MasterDataIndexController(ElasticsearchController):
def __init__(self):
self.indexName = "bbbbb"
def search(self, query):
return super.es.search(index=self.indexName, docuemntType = self.documentType, query = query)
I got this error:
AttributeError: type object 'super' has no attribute 'es'
though the super does have it.
Any idea please?
You are not initialising your super classes.
class ElasticsearchController(object):
def __init__(self):
self.es = Elasticsearch(['a.b.c.d'], port=1234)
class MasterDataIndexController(ElasticsearchController):
def __init__(self):
super(MasterDataIndexController, self).__init__()
#^^^^^^^^^^^
self.indexName = "bbbbb"
def search(self, query):
return self.es.search(index=self.indexName, docuemntType = self.documentType, query = query)
# ^^^^^ self should be fine.
You can't use super like that. super will give you access to the super class, but you should not use it as a shortcut for self. Depending if you use python or python 3, you can call super(MyClass, self) or just super(). You can use this during initialization to call the __init__ method of your superclass.
However, in most simple class hierarchies, it is not necessary to call super and your code will be clearer if you just called SuperClass.__init__(self).
After this you should be able to just use self and attribute access.

Categories

Resources