Hi Pierre,
Thanks. I will look at this more closely and the
register_module_extender().
Cheers,
Dave
On 5/10/21 11:56 pm, Pierre Sassoulas wrote:
Hello David,
It look like you're trying to create a brain for astroid. Here's a
recent example for signal directly in astroid recently :
https://github.com/PyCQA/astroid/pull/1172/files
<https://github.com/PyCQA/astroid/pull/1172/files>
Hope this helps :)
Le mar. 5 oct. 2021 à 14:26, David Rajaratnam <da...@gemarex.com.au
<mailto:da...@gemarex.com.au>> a écrit :
Hi all,
I'm trying to write a transform plugin to better work with a
library that I maintain. For background my library extends a
third-party library and uses some dynamic typing to add new
features and wrappers on top of the third-party library. Because
it uses dynamically created classes pylint complains about having
missing members (E1101) and unexpected keyword arguments in the
constructor (E1123).
The class that is being dynamically generated only gets generated
once when the module is imported and provides a proxy/wrapper
around an existing class from the third-party library. The wrapper
mirrors the member functions from the original class, as well as
overriding and adding some new member functions. So the structure
is something like:
tpmodule.py
# third-party library
class Control:
....
mymodule.py
# my library
import tpmodule
def _make_wrapper(towrap):
.... # dynamically create new class
Control = _make_wrapper(tpmodule.Control)
user.py
# user code to run pylint on
import mymodule
ctrl = Control(...)
ctrl.original_func(...)
ctrl.new_func(...)
My plan with the transform plugin is to use
'astroid.MANAGER.register_transform()' to detect the
'astroid.Module' calls and turn 'mymodule.py' into something more
palatable for pylint; in particular to replace 'mymodule.Control'
with an 'astroid.ClassDef' that has the correct initializer and
member functions. Unfortunately, things are not working the way I
would like and I'm still getting the missing member and bad
constructor arguments errors, even though, as far as I can see, I
am returning the appropriately modified module.
However, there are many things that I don't understand:
1) Relating to the above example, pylint seems to be treating the
'ctrl' variable in 'user.py' 'ctrl' as being of type
'tpmodule.Control' so doesn't complain about things that are
common to 'tpmodule.Control' and 'mymodule.Control'. But I cannot
understand how pylint could possibly detect the relationship
between 'tpmodule.Control' and 'mymodule.Control' without getting
into the guts of the 'mymodule._make_wrapper()' function.
2) It is not clear to me how pylint treats imports from external
libraries? In my example tpmodule.py and mymodule.py are not
things that I want pylint to report on. But presumably it still
needs to follow some of the chain of dependencies to work out the
signature of what is exposed by the module so I understand why it
would parse 'mymodule.py', but I don't understand why it would
parse 'tpmodule.py'.
In fact, another curious thing is that I created a cut down
example to highlight the problem and while it has some of the same
errors it also behaves slightly differently. In the cut-down
example pylint DOESN'T actually parse 'tpmodule.py' so
'tpmodule.Control' doesn't trigger the 'register_transform()' the
way it does in the real system. Even though this makes more sense
to me than what is happening in the actual code, it is unfortunate
because I wanted to dynamically construct the signature of
'tpmodule.Control' so was relying on pylint parsing 'tpmodule.py'.
Note for clarification, in the real system 'mymodule.py' and
'tpmodule.py' are more complex and both use functions from their
respective internal modules. 'tpmodule.py' is actually written in
C++ and is using CFFI to generate the Python API, so maybe that
can explain some difference in the behaviour to the pylint expert?
Anyway, I'm sorry for the long winded questions. However, I'm
hoping someone has someone insight or can point me to some docs or
a specific example that solves a similar issue. I can also post a
zip file of my cut down example if it is appropriate to do so. It
consists of four short files ('mymodule.py', 'tpmodule.py',
'user.py', and 'plugin.py').
Regards,
Dave
To be clear I'm not using pylint on the library itself, instead I
want pylint to work nicely with users of the library; although at
some point I will try to configure pylint to help me with
refactoring some of the code as well.
My library extends an existing library with some new feature. and
does some dynamic typing.
I'm new to the group and
_______________________________________________
code-quality mailing list -- code-quality@python.org
<mailto:code-quality@python.org>
To unsubscribe send an email to code-quality-le...@python.org
<mailto:code-quality-le...@python.org>
https://mail.python.org/mailman3/lists/code-quality.python.org/
<https://mail.python.org/mailman3/lists/code-quality.python.org/>
Member address: pierre.sassou...@gmail.com
<mailto:pierre.sassou...@gmail.com>
_______________________________________________
code-quality mailing list -- code-quality@python.org
To unsubscribe send an email to code-quality-le...@python.org
https://mail.python.org/mailman3/lists/code-quality.python.org/
Member address: da...@gemarex.com.au
_______________________________________________
code-quality mailing list -- code-quality@python.org
To unsubscribe send an email to code-quality-le...@python.org
https://mail.python.org/mailman3/lists/code-quality.python.org/
Member address: arch...@mail-archive.com