AttributeError: module 'matplotlib' has no attribute 'AxesSubplot' - python

When looking at the documentation of the pandas method .hist(), it is written that it returns a matplotlib.AxesSubplot or numpy.ndarray. However when trying to type hint with hist: matplotlib.AxesSubplot = df.hist() it doesn't work (cf. error message in the title of the post).
When printing type() Python returns: Out[1]: matplotlib.axes._subplots.AxesSubplot. Should I type hint my variable hist with this (matplotlib.axes._subplots.AxesSubplot)?

Lovely question, made me dive into some new stuff I did not know. Here is my understanding of it:
It is not actually a class but a dynamic class created by a class factory, checking the mro (like type(df.hist()).mro()) of it you can see the whole inheritance.
Looking at the inheritance of AxesSubplot we see SubplotBase and Axes, so it inherits from both of these but essentially it is an Axes in a Subplot. Based on this I would have gone for matplotlib.axes._axes.Axes for type hinting.
Here is a good discussing that I derived these results from:
https://github.com/matplotlib/matplotlib/issues/18222

Related

How to make pyreverse accept and priotize type hints?

I want to automatically generate a UML class diagram based on my Python(3) source code. The challenge in this case is that not all information is available at the time of instantiation of the object. Some attributes have to be assigned later, therefore when the object is initially created, some attributes are of type None. Later they will have the type that is hinted at. Now I want the UML to show the type of the hinting not the type that is initially assigned at object creation.
The following source:
from typing import List
class Test:
def __init__(self):
self.a: int = 0
self.b: List[str] = None
produces the following UML:
Now I want for attribute b to have the type List[str] in the UML and override what pylint thinks will be the type of b. Is there a way to achive this or do I have to manually draw my UML?
Thank you very much :).
Works now, maybe 12 months ago it didn't
Second off, that is an invalid type, run mypy and it will tell you. At best it should be Optional[List[str]]. Even better is to initialize it to []
As for what is going on behind the scenes-
Some tools that work directly with python source code will import or run the code and then manipulate live objects. Pydoc is an example.
As far as I can tell, pyreverse uses astroid, which just parse the code and doesn't attempt to run it, instead it makes certain "inferences". So it wouldn't be expected to pick up everything dynamic, such a variable whose type changes while the app is running.

Why does the python help class interpret sub-classes of the str class as module names?

When the python help function is invoked with an argument of string type, it is interpreted by pydoc.Helper.help as a request for information on the topic, symbol, keyword or module identified by the value of the string. For other arguments, help on the object itself is provided, unless the object is an instance of a subclass of str. In this latter case, the pydoc.resolve function looks for a module with a name matching the value of the object and raises an exception if none is found.
To illustrate this, consider the example code:
class Extra(object):
def NewMethod(): return 'New'
Cls1 = type( 'FirstClass', (str,Extra), {'__doc__':'My new class','extra':'An extra attribute'})
inst1 = Cls1('METHODS')
help( 'METHODS' )
help( inst1 )
The first invocation of help produces information on the topic "METHODS", the 2nd produces an error message because the pydoc.resolve function is trying to find a module called "METHODS".
This means that it is difficult to provide effective documentation for user defined sub-classes of str. Would it not be possible for pydoc.resolve to use a test on the type of the object, as is done in pydoc.Helper.help, and allow instances of user defined sub-classes to be treated as other class instances?
This question follows from earlier discussion of a related question here.
The simple answer is that making user-defined subclasses of str is not the most common case—partly because the user-defined data but not the string data would be mutable. By the time you have to deal with such, it’s imagined that you know how to write help(type(x)), and using isinstance rather than type(…) is … is the correct default in general. (The other way, you’d have to use help(str(x)) if you wanted to use it, like any other string, to select a help topic, but that’s surely even rarer.)

Python - curly braces in type hints

What do these mean?
def f(a: {int, float}):
pass
I've seen this syntax used in some standard Python modules when fetching documentation via PyCharm, and I have no idea what it means. What's the hinted type for a in my example? What types can I pass to this function?
The particular example where I've seen this is in tkinter's Frame __init__ method, where the master parameter is of type {tk, _w}.
It's a hint telling you it wants an object with the named attributes 'int' and 'float' -- or more specifically for tkinter 'tk' and '_w'
I coded up a minimal example in pycharm:
Inpecting the python library sources -- You can see that there are attempted accesses to master.tk and master._w. That's all that pycharm was able to infer about the type of the parameter master so it floated it up to the IDE in this manner.

Seemingly immutable dict in object instance

If I run the following cartopy code:
import cartopy.crs as ccrs
globe = ccrs.LambertCylindrical()
print(globe.proj4_params)
globe.proj4_params['a'] = 5
print(globe.proj4_params)
I get:
{'proj': 'cea', 'lon_0': 0.0, 'a': 57.29577951308232, 'ellps': 'WGS84'}
{'proj': 'cea', 'lon_0': 0.0, 'a': 57.29577951308232, 'ellps': 'WGS84'}
Impying that the proj4_params property is immutable.
But it's just a bog standard dict:
print(type(globe.proj4_params))
<class 'dict'>
Which, since it's implemented in C, can't be overwritten to have this kind of behavior (at least not safely).
Ok, but the code for this class is dead simple, so there's something wrong with my understanding. Can someone explain to me why I am getting this behavior?
Edit:
The following:
projection.proj4_params = dict(projection.proj4_params)
Results in:
*** AttributeError: attribute 'proj4_params' of 'cartopy._crs.CRS' objects is not writable
You could ensure your params are a dictionary by converting it to one first.
params = dict(globe.proj4_params)
Then if you print
print type(params)
<type 'dict'>
Notice the <type 'dict'> instead of the <class 'dict'> in your question. The dict you're using may be a custom class that's immutable but uses the same dict name.
The proj4_params object is finally defined in Projection's superclass CRS, which is supplied by the private, cython module _crs.pyx within cartopy. When a cartopy CRS' proj4_params is defined, it's just defined as a variable within the class rather than as a class variable (that is, it isn't defined as self.proj4_params). This is a fair part of the reason why you can't modify the values of the proj4 params.
For what it's worth, I believe this is the correct way for cartopy CRS' to behave. The proj4_params element of each CRS is a direct reference to a canonical definition of the underlying projection that cartopy is providing within Python. These canonical definitions are maintained by the proj.4 organisation (for example, Lambert Cylindrical is here), so modifying the proj4_params would mean your projection is no longer a Lambert Cylindrical projection.
If you particularly need a cartopy CRS that's almost a Lambert Cylindrical, you could always create your own crs by duplicating the code in cartopy's own LambertCylindrical class. So long as you maintain the inheritance in your own class you should be able to use it as you would one of cartopy's built-in CRS'. Note if you do modify the proj4_params for your own class it might not work because your specified params do not match to anything in proj.4 itself. In this case you could look into modifying your CRS' globe attribute to make the projection changes you need.

Python "property object has no attribute" Exception

confirmation = property(_get_confirmation, _set_confirmation)
confirmation.short_description = "Confirmation"
When I try the above I get an Exception I don't quite understand:
AttributeError: 'property' object has no attribute 'short_description'
This was an answer to another question on here but I couldn't comment on it as I don't have enough points or something. :-(
In other tests I've also got this error under similar circumstances:
TypeError: 'property' object has only read-only attributes (assign to .short_description)
Any ideas anybody?
The result of property() is an object where you can't add new fields or methods. It's immutable which is why you get the error.
One way to achieve what you want is with using four arguments to property():
confirmation = property(_get_confirmation, _set_confirmation, None, "Confirmation.")
or put the explanation into the docstring of _get_confirmation.
(see docs here, also supported in Python 2)
[EDIT] As for the answer, you refer to: I think the indentation of the example was completely wrong when you looked at it. This has been fixed, now.

Categories