Decorator inside a class throw warning in Pycharm - python

I am using PyCharm IDE and below is a fragment of code where I am using a decorator. The decorator is basically checking whether the argument extract is an integer >= 0.
This code is working as far as I can tell however I noticed some syntax error in PyCharm.
class MyClass(object):
def _argument_test_extract(func):
def _helper(*args, **kwargs):
kwargs = inspect.getcallargs(func, *args, **kwargs)
if 'rule' in kwargs:
extract = kwargs['rule']['extract']
if type(extract) == int and extract >= 0:
return func(**kwargs)
else:
raise Exception("Argument `extract` is not an integer")
return _helper
#_argument_test_extract
def _perform_split_model_string(self, rule):
# do some stuff
PyCharm indicates the following message for the line where I decorate the function with #_argument_test_extract:
Function '_argument_test_extract' lacks a positional argument
The line where the decorator function is defined def _argument_test_extract(func): indicates the following message
Usually first parameter of a function is 'self'
Finally the line return func(**kwargs) indicates the following message:
'MyClass' is not callable
Obviously, if I decorate the function _argument_test_extract with #staticmethod all the warning of PyCharm disappear but the code is not working anymore because of this error, TypeError: 'staticmethod' object is not callable.
Is there something wrong with my syntax? Thanks

Is there something wrong with my syntax
well ... if it works, apparently not :-). There's probably something wrong with pycharm's static analysis.
With that said, there is something weird about what you're doing. PyCharm is noticing that (after class creation), _argument_test_abstract is going to become a method of the class. As a method of the class, _argument_test_abstract will require an argument. However, during class creation, _argument_test_abstract isn't yet a method and this is when the decoration occurs -- So it works. (as you've noted, #staticmethod doesn't solve the problem because the staticmethod descriptor itself isn't callable, only the function that it returns from __get__).
So, where does that leave us? You can continue with what you have and just ignore pycharm, or you can move the decorator out of the class and make it module level. It really doesn't need to be in the class in the first place :-). I would argue that moving it out of the class is the better solution because lots of people reading your code are going to wonder where self is and how this whole thing doesn't blow up every time you try to execute it, etc.

Related

How can i make a method available only from within the class

Good evening, i need an advice, googling i couldn't find a proper direction.
I need to make a method available only within the class (i.e other methods or functions), if called from the program as a method of the object referring to the class i want:
the method to be invisible/not available to the intellisense
if i'm stubborn, and code it anyway, must raise an error.
Attaching a screenshot to make it more clear.
Any advice is appreciated, Thank you.
Screenshot of the problem
There's no private methods in python. Common usage dictates to precede a method that's only supposed to be used internally with one or two underscores, depending on the case. See here: What is the meaning of single and double underscore before an object name?
As others have mentioned there are no private methods in Python. I also don't know how to make it invisible for intelisense (probably there is some setting), but what you could theoretically do is this:
import re
def make_private(func):
def inner(*args, **kwargs):
name = func.__name__
pattern = re.compile(fr'(.*)\.{name}')
with open(__file__) as file:
for line in file:
lst = pattern.findall(line)
if (lst and not line.strip().startswith('#')
and not all(g.strip() == 'self' for g in lst)):
raise Exception()
return func(*args, **kwargs)
return inner
class MyClass:
#make_private
def some_method(self):
pass
def some_other_method(self):
self.some_method()
m = MyClass()
# m.some_method()
m.some_other_method()
It (make_private) is a decorator which basically when you call the function it is decorating, it first reads the entire file line by line and tries to find if in all of the file this method is called without being prefixed with self.. So if it is not then it is considered to be called from outside the class and an Exception is raised (probably add some message to it tho).
Issues could start once you have multiple files and this wouldn't entirely prevent someone from calling it if they really wanted for example if they did it like this:
self = MyClass()
self.some_method()
But mostly this would raise an exception.
OK Solved, to hide the method to the ide's Intellisense i added the double underscore (works fine with pycharm, not with vscode) then i used the accessify module to prevent forced execution calling myobj._myclass__somemethod()
from accessify import private
class myclass:
#private
def __somemethod(self)

How to use getattr or getattribute to correctly raise ImportError while calling some methods

Hello their thanks in advance for helping me,
Please see below code:
import types
_MSG = ("Failed importing {name}. Please install {name}."
" Using pip install {name}")
class Empty(): # pylint: disable=too-few-public-methods
"""Empty class for beam API."""
def __call__(self, *args, **kwargs):
return None
class DummyBeam(types.ModuleType): # pylint: disable=too-few-public-methods
DoFn = Empty
Pipeline = Empty
def __init__(self, name="apache_beam"):
super(DummyBeam, self).__init__(name)
def __getattribute__(self, _):
if getattr(DummyBeam, _, None) is Empty:
err_msg = _MSG.format(name=self.__name__)
raise ImportError(err_msg)
What I want to check if apache_beam was not installed it will successfully load all beam classes like DoFn and pipeline but calling some function raises error please see below code to see above code in use.
try:
import apache_beam as beam
except ImportError:
beam = DummyBeam()
class SomeFn(beam.DoFn):
pass
class SomeOtherFn(beam.Pipeline):
pass
SomeFn()
In above code for now accessing beam.DoFn raises error but what I want it to not raise error when accessing beam.DoFn although it raises error when calling SomeFn(). Also tried to replace getattribute with getattr and it not gives me results as i expected it wont raise error when calling SomeFn() although it runs fine for all codes.
Thanks for looking into this.
As shown in the traceback (that you should have posted FWIW), your error is not in calling SomeFn() but in accessing beam.DoFn in the SomeFn class definition. And the reason is quite obvious: you very explicitely instructed Python to do so by plain overriding Beam.__getattribute__.
Note that object.__getattribute__ is the official default implementation of attribute lookup (it's invoked each time Python sees either obj.name or getattr(obj, "name"), and that it's a method that is better left alone unless you fully understand the implications of overriding it AND have no better solution.
In this case the very obvious solution is to instead implempent __getattr__, which is only invoked by __getattribute__ as a last resort if the attribute couldn't be resolved in any other way. You say that:
Also replace getattribute with getattr was not working
but I just tried it on your code snippet and it (of course) yield the result I expected. Whether this is what you expected is another question, but since you neither posted this version of your code nor cared to explain how it "was not working", you can't expect any answer on this point (hint: "is not working" is a totally useless description of an issue).
As a last note:
it will successfully load all beam methods like DoFn and pipeline
...
In above code for now calling beam.DoFn
It seems you're a bit confused about terminology. DoFn and Pipeline are classes, not methods, and (as already mentionned) your error is raised when accessing beam.DoFn, not when calling it.
EDIT:
by was not working I meant it not gives me error either when i am trying to access beam.DoFn or SomeFn() when use getattr instead getattribute
(...)
what i want is to raise error when calling someFn no accessing beam.DoFn
Ok, it looks that you don't quite get the execution order of a method call expression. When you do
obj.method()
this is actually a shortcut for
method = obj.__getattribute__("method")
method.__call__()
So overriding __getattribute__ isn't the proper solution (cf above), and defining __getattr__ is useless here - your DummyBeam class HAS DoFn and Pipeline attributes so __getattr__ will just not be invoked for those names.
Now the reason you don't get any exception when calling beam.DoFn or beam.Pipeline is that those name are bound to your Empty class, not instances of that class, so you actually never invoke Empty.__call__. Rhe __call__ method defined in a class is only used when an instance of that class is called, not when you instanciate the class (in which case it's the metaclass's __call__ method which is invoked):
>>> class MyCallable:
... def __init__(self):
... print("in MyCallable.__init__")
... def __call__(self):
... print("in MyCallable.__call__")
...
>>>
... c = MyCallable()
in MyCallable.__init__
>>> c()
in MyCallable.__call__
>>>
So if what you want is to raise your exception when someone tries to instanciate DoFn or ̀Pipelineyou either have to make them instances ofEmptyor keep them as they are and renameEmpty.calltoEmpty.newwhich is the first method called bytype.call(type` being the default metaclass for all classes).

Python 2.7 warning: __init__ not compatible to __new__

I have a class defined in Python 2.7 like this:
from future.builtins import object
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
In PyCharm, this gives a warning in the __init__ line:
Signature is not compatible to __new__.
I don't understand what this warning is telling me. Can someone give an example where this warning would rightfully catch an error or can this warning be turned off?
There's a PyCharm thread for this, but it doesn't help me: https://intellij-support.jetbrains.com/hc/en-us/community/posts/115000254530-PyCharm-init-Signature-is-not-compatible-to-new-
I suffered from the same problem and found the solution in here.
As discussed in the above link, a direct solution is to remove your Pycharm config directory ("/home/username/.PyCharm2018.3" for me). However, it would remove all your other configs too. Finally, I just fix the problem by removing the rule from inspections. You can find the rule in the Pycharm Setting window (see the figure as follow).
This is a PyCharm bug; you can disable the warning via Xiong-Hui's post. Basically __new__ is a method that is called before __init__ with the same arguments when a class is constructed, so their signatures must be compatible (both functions must be able to be invoked with the same arguments) or the class cannot be instantiated. For example, here is a code snippet for which PyCharm correctly applies the warning:
class Test(object):
def __new__(cls, arg1):
return super().__new__(cls)
def __init__(self):
pass
Attempting to create the class with Test() will throw a TypeError since __new__ expects an argument, but creating the class with Test('something') will also throw a TypeError since __init__ doesn't expect any arguments, making it impossible to construct the class. Normally this is never an issue because the default implementation of __new__ in object accepts an arbitrary number of arguments, but if you define __new__ yourself you will need to be careful that the signatures remain compatible so the class can actually be constructed, which is the purpose of the warning.

don't understand "self" error

Please forgive the noob question. I don't understand this "self" stuff in relation to this:
from selenium.common.exceptions import NoSuchElementException
def is_element_present(self, how, what):
try:
self.driver.find_element(by=how, value=what)
except NoSuchElementException:
return False
return True
#### navigate to the web page with a bunch of code here, then continue
text_present = self.assertTrue(self.is_element_present(By.LINK_TEXT, "Click Here"))
When I run this, here's the error I get:
test_link = self.assertTrue(self.is_element_present(By.LINK_TEXT, "Click Here"))
NameError: name 'self' is not defined
I understand "self" is used by convention as the first argument in a function but I don't understand the error. How do I define self?
Edit 1: I stand corrected on where "self" is used by convention (see comments/answers below). However, I still don't know what I should be doing to satisfy the Python interpreter.
self is "used by convention as the first argument" in a method, which is associated with a class. self in this context represents the instance of the class that is calling the method. A function, however, is not associated with a class, and thus no initial self argument is required. This is one of the fundamental differences between functions and methods--methods are associated with a class, and are called as instanceOfClass.methodName(args), where functions simply exist in the namespace and are called as functionName(args). Also note that when calling a method, self is not passed to the call: it is only used when defining the method.
You might know about the this pointer in C++. In priciple, Python's self is quite similar (but is more a reference than a pointer). It is the current object you apply the function to.
class MyClass:
def my_method(self, arg):
pass
my_object = MyClass()
my_object.my__method("whatever")
is actually like (not exactly identical to):
def my_func(the_object, arg):
pass
class MyClass:
pass
my_object = MyClass()
my_func(my_object, "whatever")
As there is actually more involved, the other way round will not work:
my_object.my_func("whatever")
Will raise an exception (an error), just try it. That is because my_func is an unbound function (not related to any object/class). my_method actually is bound (to my_object).
While this is passed implicitly (you do not have to specify it as an argument) to a method in C++, Python requires it to be listed explicitly as the first argument. The name self is actually just convention, a method will always get its object as the first argument, so it could also be named "thats_me". However, stick to `self', as many tools rely on this (syntax highlighting editors, debuggers, ...).
In the method itself, all members of the object are then accessed explicitly by self.my_member or self.my_func(). While in C++ one would writemy_memberorthis->my_member`, etcetera. The latter is basically similar to Python's way.
Please read more here and in the tutorial in general.
Background: Passing the object expliticly as the first argument is due to one of Pythons major guidelines: "explicit is better than implicit".

Using the self-parameter in python objects

I've got a question about defining functions and the self-parameter in python.
There is following code.
class Dictionaries(object):
__CSVDescription = ["ID", "States", "FilterTime", "Reaction", "DTC", "ActiveDischarge"]
def __makeDict(Lst):
return dict(zip(Lst, range(len(Lst))))
def getDict(self):
return self.__makeDict(self.__CSVDescription)
CSVDescription = __makeDict(__CSVDescription)
x = Dictionaries()
print x.CSVDescription
print x.getDict()
x.CSVDescription works fine. But print x.getDict() returns an error.
TypeError: __makeDict() takes exactly 1 argument (2 given)
I can add the self-parameter to the __makeDict() method, but then print x.CSVDescription wouldn't work.
How do I use the self-parameter correctly?
In python, the self parameter is implicitly passed to instance methods, unless the method is decorated with #staticmethod.
In this case, __makeDict doesn't need a reference to the object itself, so it can be made a static method so you can omit the self:
#staticmethod
def __makeDict(Lst): # ...
def getDict(self):
return self.__makeDict(self.__CSVDescription)
A solution using #staticmethod won't work here because calling the method from the class body itself doesn't invoke the descriptor protocol (this would also be a problem for normal methods if they were descriptors - but that isn't the case until after the class definition has been compiled). There are four major options here - but most of them could be seen as some level of code obfuscation, and would really need a comment to answer the question "why not just use a staticmethod?".
The first is, as #Marcus suggests, to always call the method from the class, not from an instance. That is, every time you would do self.__makeDict, do self.__class__.__makeDict instead. This will look strange, because it is a strange thing to do - in Python, you almost never need to call a method as Class.method, and the only time you do (in code written before super became available), using self.__class__ would be wrong.
In similar vein, but the other way around, you could make it a staticmethod and invoke the descriptor protocol manually in the class body - do: __makeDict.__get__(None, Dictionaries)(__lst).
Or, you could detect yourself what context its being called from by getting fancy with optional arguments:
def __makeDict(self, Lst=None):
if Lst is None:
Lst = self
...
But, by far the best way is to realise you're working in Python and not Java - put it outside the class.
def _makeDict(Lst):
...
class Dictionaries(object):
def getDict(self):
return _makeDict(self.__CSVDescription)
CSVDescription = _makeDict(__CSVDescription)

Categories