Remove debug prints

This commit is contained in:
Guille Gutierrez 2020-06-26 10:06:43 -04:00
parent 683f5c1438
commit af22f7aaa9
1212 changed files with 29131 additions and 800286 deletions

View File

@ -21,6 +21,8 @@ class Polyhedron:
self._faces = None self._faces = None
self._vertices = None self._vertices = None
self._mesh = None self._mesh = None
self._centroid = None
self._max_z = None
self._geometry = GeometryHelper() self._geometry = GeometryHelper()
def _position_of(self, point): def _position_of(self, point):
@ -65,16 +67,14 @@ class Polyhedron:
for point in points: for point in points:
face.append(self._position_of(point)) face.append(self._position_of(point))
self._faces.append(face) self._faces.append(face)
self._faces = np.asarray(self._faces) #self._faces = np.asarray(self._faces)
return self._faces return self._faces
@property @property
def _polyhedron_mesh(self): def _polyhedron_mesh(self):
if self._mesh is None: if self._mesh is None:
self._mesh = Trimesh(vertices=np.asarray(self.vertices), faces=np.asarray(self.faces)) self._mesh = Trimesh(vertices=self.vertices, faces=self.faces)
if not self._mesh.is_volume:
print('The geometry is not a closed volume')
return None
return self._mesh return self._mesh
@property @property
@ -84,7 +84,11 @@ class Polyhedron:
:return: float :return: float
""" """
if self._volume is None: if self._volume is None:
self._volume = self._polyhedron_mesh.volume if not self._polyhedron_mesh.is_volume:
print('The geometry is not a closed volume')
self._volume = np.inf
else:
self._volume = self._polyhedron_mesh.volume
return self._volume return self._volume
@property @property

View File

@ -81,7 +81,7 @@ class CityGml:
surface_type = next(iter(bound)) surface_type = next(iter(bound))
if 'lod2MultiSurface' in bound[surface_type]: if 'lod2MultiSurface' in bound[surface_type]:
lod = 2 lod = 2
surfaces = CityGml._lod2(bound) surfaces = surfaces + CityGml._lod2(bound)
if 'lod3Solid' in o['Building']: if 'lod3Solid' in o['Building']:
lod += 4 lod += 4
if 'lod4Solid' in o['Building']: if 'lod4Solid' in o['Building']:
@ -142,13 +142,13 @@ class CityGml:
def _lod2(bound): def _lod2(bound):
surfaces = [] surfaces = []
for surface_type in iter(bound): for surface_type in iter(bound):
for s in bound[surface_type]['lod2MultiSurface']['MultiSurface']['surfaceMember']: try:
try: print(bound)
surfaces = [Surface(s['Polygon']['exterior']['LinearRing']['posList']['#text'], surfaces = [Surface(s['Polygon']['exterior']['LinearRing']['posList']['#text'],
surface_type=GeometryHelper.gml_surface_to_libs(surface_type)) surface_type=GeometryHelper.gml_surface_to_libs(surface_type))
for s in bound[surface_type]['lod2MultiSurface']['MultiSurface']['surfaceMember']] for s in bound[surface_type]['lod2MultiSurface']['MultiSurface']['surfaceMember']]
except TypeError: except TypeError:
surfaces = [Surface(s['Polygon']['exterior']['LinearRing']['posList'], surfaces = [Surface(s['Polygon']['exterior']['LinearRing']['posList'],
surface_type=GeometryHelper.gml_surface_to_libs(surface_type)) surface_type=GeometryHelper.gml_surface_to_libs(surface_type))
for s in bound[surface_type]['lod2MultiSurface']['MultiSurface']['surfaceMember']] for s in bound[surface_type]['lod2MultiSurface']['MultiSurface']['surfaceMember']]
return surfaces return surfaces

View File

@ -17,10 +17,10 @@ class UsBasePhysicsParameters:
""" """
UsBasePhysicsParameters class UsBasePhysicsParameters class
""" """
def __init__(self, climate_zone, city_objects, function_to_type, base_path): def __init__(self, climate_zone, buildings, function_to_type, base_path):
self._climate_zone = climate_zone self._climate_zone = climate_zone
self._city_objects = city_objects self._buildings = buildings
print(buildings)
# load US Library # load US Library
path = str(Path.cwd() / base_path / 'us_constructions.xml') path = str(Path.cwd() / base_path / 'us_constructions.xml')
with open(path) as xml: with open(path) as xml:
@ -30,24 +30,25 @@ class UsBasePhysicsParameters:
path = str(Path.cwd() / base_path / 'us_archetypes.xml') path = str(Path.cwd() / base_path / 'us_archetypes.xml')
with open(path) as xml: with open(path) as xml:
self._archetypes = xmltodict.parse(xml.read(), force_list='layer') self._archetypes = xmltodict.parse(xml.read(), force_list='layer')
for city_object in self._city_objects: for building in self._buildings:
building_type = function_to_type(city_object.function)
building_type = function_to_type(building.function)
if building_type is None: if building_type is None:
return return
archetype = self._search_archetype(building_type, archetype = self._search_archetype(building_type,
UsToLibraryTypes.yoc_to_standard(city_object.year_of_construction), UsToLibraryTypes.yoc_to_standard(building.year_of_construction),
self._climate_zone) self._climate_zone)
# ToDo: remove this in the future # ToDo: remove this in the future
# ToDo: Raise WrongArchetype if not all the surface types are defined for the given city_object # ToDo: Raise WrongArchetype if not all the surface types are defined for the given city_object
if archetype is None: if archetype is None:
print(building_type, UsToLibraryTypes.yoc_to_standard(city_object.year_of_construction), print(building_type, UsToLibraryTypes.yoc_to_standard(building.year_of_construction),
self._climate_zone) self._climate_zone)
raise Exception('Archetype not found for building') raise Exception('Archetype not found for building')
city_object.average_storey_height = archetype['average_storey_height']['#text'] building.average_storey_height = archetype['average_storey_height']['#text']
city_object.storeys_above_ground = archetype['number_of_storeys']['#text'] building.storeys_above_ground = archetype['number_of_storeys']['#text']
for thermal_zone in city_object.thermal_zones: for thermal_zone in building.thermal_zones:
thermal_zone.effective_thermal_capacity = archetype['thermal_capacity']['#text'] thermal_zone.effective_thermal_capacity = archetype['thermal_capacity']['#text']
thermal_zone.additional_thermal_bridge_u_value = archetype['extra_loses_due_to_thermal_bridges']['#text'] thermal_zone.additional_thermal_bridge_u_value = archetype['extra_loses_due_to_thermal_bridges']['#text']
thermal_zone.indirectly_heated_area_ratio = archetype['indirect_heated_ratio']['#text'] thermal_zone.indirectly_heated_area_ratio = archetype['indirect_heated_ratio']['#text']

View File

@ -6,9 +6,6 @@ pyproj~=2.6.1.post1
pyny3d~=0.2 pyny3d~=0.2
matplotlib~=3.2.1 matplotlib~=3.2.1
Shapely~=1.7.0 Shapely~=1.7.0
# MonthlyEnergyBalance
pandas~=1.0.4 pandas~=1.0.4
pip~=20.1.1 pip~=20.1.1
pyzmq~=19.0.1 pyzmq~=19.0.1
@ -53,3 +50,4 @@ pyrsistent~=0.16.0
cycler~=0.10.0 cycler~=0.10.0
kiwisolver~=1.2.0 kiwisolver~=1.2.0
zipp~=3.1.0 zipp~=3.1.0
reverse_geocoder~=1.5.1

View File

@ -24,7 +24,7 @@ class TestGeometryFactory(TestCase):
def _get_citygml(self): def _get_citygml(self):
if self._city_gml is None: if self._city_gml is None:
file_path = (self._example_path / 'lod2_buildings.gml').resolve() file_path = (self._example_path / 'buildings.gml').resolve()
self._city_gml = GeometryFactory('citygml', file_path).city self._city_gml = GeometryFactory('citygml', file_path).city
self.assertIsNotNone(self._city_gml, 'city is none') self.assertIsNotNone(self._city_gml, 'city is none')
return self._city_gml return self._city_gml
@ -36,8 +36,8 @@ class TestGeometryFactory(TestCase):
""" """
city = self._get_citygml() city = self._get_citygml()
self.assertIsNotNone(city.city_objects, 'city_objects is none') self.assertIsNotNone(city.city_objects, 'city_objects is none')
for city_object in city.city_objects: for building in city.buildings:
self.assertIsNotNone(city.city_object(city_object.name), 'city_object return none') self.assertIsNotNone(city.city_object(building.name), 'city_object return none')
self.assertIsNotNone(city.srs_name, 'srs_name is none') self.assertIsNotNone(city.srs_name, 'srs_name is none')
self.assertIsNotNone(city.lower_corner, 'lower_corner is none') self.assertIsNotNone(city.lower_corner, 'lower_corner is none')
self.assertIsNotNone(city.upper_corner, 'upper_corner is none') self.assertIsNotNone(city.upper_corner, 'upper_corner is none')
@ -79,8 +79,8 @@ class TestGeometryFactory(TestCase):
:return: None :return: None
""" """
city = self._get_citygml() city = self._get_citygml()
for city_object in city.buildings: for building in city.buildings:
for surface in city_object.surfaces: for surface in building.surfaces:
self.assertIsNotNone(surface.name, 'surface name is none') self.assertIsNotNone(surface.name, 'surface name is none')
self.assertIsNotNone(surface.area, 'surface area is none') self.assertIsNotNone(surface.area, 'surface area is none')
self.assertIsNotNone(surface.type, 'surface type is none') self.assertIsNotNone(surface.type, 'surface type is none')
@ -110,8 +110,8 @@ class TestGeometryFactory(TestCase):
:return: None :return: None
""" """
city = self._get_citygml() city = self._get_citygml()
for city_object in city.buildings: for building in city.buildings:
for thermal_zone in city_object.thermal_zones: for thermal_zone in building.thermal_zones:
self.assertIsNotNone(thermal_zone.surfaces, 'thermal_zone surfaces is none') self.assertIsNotNone(thermal_zone.surfaces, 'thermal_zone surfaces is none')
self.assertIsNotNone(thermal_zone.bounded, 'thermal_zone bounded is none') self.assertIsNotNone(thermal_zone.bounded, 'thermal_zone bounded is none')
self.assertIsNotNone(thermal_zone.floor_area, 'thermal_zone floor_area is none') self.assertIsNotNone(thermal_zone.floor_area, 'thermal_zone floor_area is none')
@ -136,8 +136,8 @@ class TestGeometryFactory(TestCase):
:return: None :return: None
""" """
city = self._get_citygml() city = self._get_citygml()
for city_object in city.buildings: for building in city.buildings:
for thermal_zone in city_object.thermal_zones: for thermal_zone in building.thermal_zones:
for thermal_boundary in thermal_zone.bounded: for thermal_boundary in thermal_zone.bounded:
self.assertIsNotNone(thermal_boundary.type, 'thermal_boundary type is none') self.assertIsNotNone(thermal_boundary.type, 'thermal_boundary type is none')
self.assertIsNotNone(thermal_boundary.area, 'thermal_boundary area is none') self.assertIsNotNone(thermal_boundary.area, 'thermal_boundary area is none')
@ -166,8 +166,8 @@ class TestGeometryFactory(TestCase):
:return: None :return: None
""" """
city = self._get_citygml() city = self._get_citygml()
for city_object in city.buildings: for building in city.buildings:
for thermal_zone in city_object.thermal_zones: for thermal_zone in building.thermal_zones:
for thermal_boundary in thermal_zone.bounded: for thermal_boundary in thermal_zone.bounded:
for thermal_opening in thermal_boundary.thermal_openings: for thermal_opening in thermal_boundary.thermal_openings:
self.assertTrue(thermal_opening.frame_ratio == 0, 'thermal_opening frame_ratio was not 0') self.assertTrue(thermal_opening.frame_ratio == 0, 'thermal_opening frame_ratio was not 0')

View File

@ -25,7 +25,7 @@ class TestPhysicsFactory(TestCase):
def _get_citygml(self): def _get_citygml(self):
if self._city_gml is None: if self._city_gml is None:
file_path = (self._example_path / 'lod2_buildings.gml').resolve() file_path = (self._example_path / 'buildings.gml').resolve()
self._city_gml = GeometryFactory('citygml', file_path).city self._city_gml = GeometryFactory('citygml', file_path).city
self.assertIsNotNone(self._city_gml, 'city is none') self.assertIsNotNone(self._city_gml, 'city is none')
return self._city_gml return self._city_gml
@ -33,6 +33,7 @@ class TestPhysicsFactory(TestCase):
def _get_city_with_physics(self): def _get_city_with_physics(self):
if self._nyc_with_physics is None: if self._nyc_with_physics is None:
self._nyc_with_physics = self._get_citygml() self._nyc_with_physics = self._get_citygml()
print(self._nyc_with_physics)
PhysicsFactory('us_new_york_city', self._nyc_with_physics, base_path=self._example_path) PhysicsFactory('us_new_york_city', self._nyc_with_physics, base_path=self._example_path)
return self._nyc_with_physics return self._nyc_with_physics
@ -42,10 +43,10 @@ class TestPhysicsFactory(TestCase):
:return: None :return: None
""" """
city = self._get_city_with_physics() city = self._get_city_with_physics()
for city_object in city.buildings: for building in city.buildings:
self.assertIsNotNone(city_object.average_storey_height, 'average_storey_height is none') self.assertIsNotNone(building.average_storey_height, 'average_storey_height is none')
self.assertIsNotNone(city_object.storeys_above_ground, 'storeys_above_ground is none') self.assertIsNotNone(building.storeys_above_ground, 'storeys_above_ground is none')
for thermal_zone in city_object.thermal_zones: for thermal_zone in building.thermal_zones:
self.assertIsNotNone(thermal_zone.effective_thermal_capacity, 'effective_thermal_capacity is none') self.assertIsNotNone(thermal_zone.effective_thermal_capacity, 'effective_thermal_capacity is none')
self.assertIsNotNone(thermal_zone.additional_thermal_bridge_u_value, self.assertIsNotNone(thermal_zone.additional_thermal_bridge_u_value,
'additional_thermal_bridge_u_value is none') 'additional_thermal_bridge_u_value is none')

File diff suppressed because it is too large Load Diff

View File

@ -39,7 +39,6 @@ class UsBaseUsageParameters:
city_object.usage_zones = [UsBaseUsageParameters._parse_zone_usage_type(zone_usage_type, usage_zone)] city_object.usage_zones = [UsBaseUsageParameters._parse_zone_usage_type(zone_usage_type, usage_zone)]
break break
if city_object.usage_zones is None: if city_object.usage_zones is None:
print(city_object.function)
raise Exception('Usage not found for building function') raise Exception('Usage not found for building function')
@staticmethod @staticmethod

View File

@ -1,469 +0,0 @@
####################################################################################
Jedi - an awesome autocompletion, static analysis and refactoring library for Python
####################################################################################
.. image:: http://isitmaintained.com/badge/open/davidhalter/jedi.svg
:target: https://github.com/davidhalter/jedi/issues
:alt: The percentage of open issues and pull requests
.. image:: http://isitmaintained.com/badge/resolution/davidhalter/jedi.svg
:target: https://github.com/davidhalter/jedi/issues
:alt: The resolution time is the median time an issue or pull request stays open.
.. image:: https://travis-ci.org/davidhalter/jedi.svg?branch=master
:target: https://travis-ci.org/davidhalter/jedi
:alt: Linux Tests
.. image:: https://ci.appveyor.com/api/projects/status/mgva3bbawyma1new/branch/master?svg=true
:target: https://ci.appveyor.com/project/davidhalter/jedi/branch/master
:alt: Windows Tests
.. image:: https://coveralls.io/repos/davidhalter/jedi/badge.svg?branch=master
:target: https://coveralls.io/r/davidhalter/jedi
:alt: Coverage status
Jedi is a static analysis tool for Python that is typically used in
IDEs/editors plugins. Jedi has a focus on autocompletion and goto
functionality. Other features include refactoring, code search and finding
references.
Jedi has a simple API to work with. There is a reference implementation as a
`VIM-Plugin <https://github.com/davidhalter/jedi-vim>`_. Autocompletion in your
REPL is also possible, IPython uses it natively and for the CPython REPL you
can install it. Jedi is well tested and bugs should be rare.
Jedi can currently be used with the following editors/projects:
- Vim (jedi-vim_, YouCompleteMe_, deoplete-jedi_, completor.vim_)
- `Visual Studio Code`_ (via `Python Extension <https://marketplace.visualstudio.com/items?itemName=ms-python.python>`_)
- Emacs (Jedi.el_, company-mode_, elpy_, anaconda-mode_, ycmd_)
- Sublime Text (SublimeJEDI_ [ST2 + ST3], anaconda_ [only ST3])
- TextMate_ (Not sure if it's actually working)
- Kate_ version 4.13+ supports it natively, you have to enable it, though. [`see
<https://projects.kde.org/projects/kde/applications/kate/repository/show?rev=KDE%2F4.13>`_]
- Atom_ (autocomplete-python-jedi_)
- `GNOME Builder`_ (with support for GObject Introspection)
- Gedit (gedi_)
- wdb_ - Web Debugger
- `Eric IDE`_ (Available as a plugin)
- `IPython 6.0.0+ <https://ipython.readthedocs.io/en/stable/whatsnew/version6.html>`_
and many more!
Here are some pictures taken from jedi-vim_:
.. image:: https://github.com/davidhalter/jedi/raw/master/docs/_screenshots/screenshot_complete.png
Completion for almost anything:
.. image:: https://github.com/davidhalter/jedi/raw/master/docs/_screenshots/screenshot_function.png
Documentation:
.. image:: https://github.com/davidhalter/jedi/raw/master/docs/_screenshots/screenshot_pydoc.png
Get the latest version from `github <https://github.com/davidhalter/jedi>`_
(master branch should always be kind of stable/working).
Docs are available at `https://jedi.readthedocs.org/en/latest/
<https://jedi.readthedocs.org/en/latest/>`_. Pull requests with enhancements
and/or fixes are awesome and most welcome. Jedi uses `semantic versioning
<https://semver.org/>`_.
If you want to stay up-to-date (News / RFCs), please subscribe to this `github
thread <https://github.com/davidhalter/jedi/issues/1063>`_.:
Issues & Questions
==================
You can file issues and questions in the `issue tracker
<https://github.com/davidhalter/jedi/>`. Alternatively you can also ask on
`Stack Overflow <https://stackoverflow.com/questions/tagged/python-jedi>`_ with
the label ``python-jedi``.
Installation
============
`Check out the docs <https://jedi.readthedocs.org/en/latest/docs/installation.html>`_.
Features and Limitations
========================
Jedi's features are listed here:
`Features <https://jedi.readthedocs.org/en/latest/docs/features.html>`_.
You can run Jedi on CPython 2.7 or 3.5+ but it should also
understand code that is older than those versions. Additionally you should be
able to use `Virtualenvs <https://jedi.readthedocs.org/en/latest/docs/api.html#environments>`_
very well.
Tips on how to use Jedi efficiently can be found `here
<https://jedi.readthedocs.org/en/latest/docs/features.html#recipes>`_.
API
---
You can find a comprehensive documentation for the
`API here <https://jedi.readthedocs.org/en/latest/docs/api.html>`_.
Autocompletion / Goto / Documentation
-------------------------------------
There are the following commands:
- ``jedi.Script.goto``
- ``jedi.Script.infer``
- ``jedi.Script.help``
- ``jedi.Script.complete``
- ``jedi.Script.get_references``
- ``jedi.Script.get_signatures``
- ``jedi.Script.get_context``
The returned objects are very powerful and are really all you might need.
Autocompletion in your REPL (IPython, etc.)
-------------------------------------------
Jedi is a dependency of IPython. Autocompletion in IPython with Jedi is
therefore possible without additional configuration.
Here is an `example video <https://vimeo.com/122332037>`_ how REPL completion
can look like.
For the ``python`` shell you can enable tab completion in a `REPL
<https://jedi.readthedocs.org/en/latest/docs/usage.html#tab-completion-in-the-python-shell>`_.
Static Analysis
---------------
For a lot of forms of static analysis, you can try to use
``jedi.Script(...).get_names``. It will return a list of names that you can
then filter and work with. There is also a way to list the syntax errors in a
file: ``jedi.Script.get_syntax_errors``.
Refactoring
-----------
Jedi supports the following refactorings:
- ``jedi.Script.inline``
- ``jedi.Script.rename``
- ``jedi.Script.extract_function``
- ``jedi.Script.extract_variable``
Code Search
-----------
There is support for module search with ``jedi.Script.search``, and project
search for ``jedi.Project.search``. The way to search is either by providing a
name like ``foo`` or by using dotted syntax like ``foo.bar``. Additionally you
can provide the API type like ``class foo.bar.Bar``. There are also the
functions ``jedi.Script.complete_search`` and ``jedi.Project.complete_search``.
Development
===========
There's a pretty good and extensive `development documentation
<https://jedi.readthedocs.org/en/latest/docs/development.html>`_.
Testing
=======
The test suite uses ``pytest``::
pip install pytest
If you want to test only a specific Python version (e.g. Python 3.8), it is as
easy as::
python3.8 -m pytest
For more detailed information visit the `testing documentation
<https://jedi.readthedocs.org/en/latest/docs/testing.html>`_.
Acknowledgements
================
Thanks a lot to all the
`contributors <https://jedi.readthedocs.org/en/latest/docs/acknowledgements.html>`_!
.. _jedi-vim: https://github.com/davidhalter/jedi-vim
.. _youcompleteme: https://github.com/ycm-core/YouCompleteMe
.. _deoplete-jedi: https://github.com/zchee/deoplete-jedi
.. _completor.vim: https://github.com/maralla/completor.vim
.. _Jedi.el: https://github.com/tkf/emacs-jedi
.. _company-mode: https://github.com/syohex/emacs-company-jedi
.. _elpy: https://github.com/jorgenschaefer/elpy
.. _anaconda-mode: https://github.com/proofit404/anaconda-mode
.. _ycmd: https://github.com/abingham/emacs-ycmd
.. _sublimejedi: https://github.com/srusskih/SublimeJEDI
.. _anaconda: https://github.com/DamnWidget/anaconda
.. _wdb: https://github.com/Kozea/wdb
.. _TextMate: https://github.com/lawrenceakka/python-jedi.tmbundle
.. _Kate: https://kate-editor.org
.. _Atom: https://atom.io/
.. _autocomplete-python-jedi: https://atom.io/packages/autocomplete-python-jedi
.. _GNOME Builder: https://wiki.gnome.org/Apps/Builder
.. _Visual Studio Code: https://code.visualstudio.com/
.. _gedi: https://github.com/isamert/gedi
.. _Eric IDE: https://eric-ide.python-projects.org
.. :changelog:
Changelog
---------
0.17.0 (2020-04-14)
+++++++++++++++++++
- Added ``Project`` support. This allows a user to specify which folders Jedi
should work with.
- Added support for Refactoring. The following refactorings have been
implemented: ``Script.rename``, ``Script.inline``,
``Script.extract_variable`` and ``Script.extract_function``.
- Added ``Script.get_syntax_errors`` to display syntax errors in the current
script.
- Added code search capabilities both for individual files and projects. The
new functions are ``Project.search``, ``Project.complete_search``,
``Script.search`` and ``Script.complete_search``.
- Added ``Script.help`` to make it easier to display a help window to people.
Now returns pydoc information as well for Python keywords/operators. This
means that on the class keyword it will now return the docstring of Python's
builtin function ``help('class')``.
- The API documentation is now way more readable and complete. Check it out
under https://jedi.readthedocs.io. A lot of it has been rewritten.
- Removed Python 3.4 support
- Many bugfixes
This is likely going to be the last minor version that supports Python 2 and
Python3.5. Bugfixes will be provided in 0.17.1+. The next minor/major version
will probably be Jedi 1.0.0.
0.16.0 (2020-01-26)
+++++++++++++++++++
- **Added** ``Script.get_context`` to get information where you currently are.
- Completions/type inference of **Pytest fixtures**.
- Tensorflow, Numpy and Pandas completions should now be about **4-10x faster**
after the first time they are used.
- Dict key completions are working now. e.g. ``d = {1000: 3}; d[10`` will
expand to ``1000``.
- Completion for "proxies" works now. These are classes that have a
``__getattr__(self, name)`` method that does a ``return getattr(x, name)``.
after loading them initially.
- Goto on a function/attribute in a class now goes to the definition in its
super class.
- Big **Script API Changes**:
- The line and column parameters of ``jedi.Script`` are now deprecated
- ``completions`` deprecated, use ``complete`` instead
- ``goto_assignments`` deprecated, use ``goto`` instead
- ``goto_definitions`` deprecated, use ``infer`` instead
- ``call_signatures`` deprecated, use ``get_signatures`` instead
- ``usages`` deprecated, use ``get_references`` instead
- ``jedi.names`` deprecated, use ``jedi.Script(...).get_names()``
- ``BaseName.goto_assignments`` renamed to ``BaseName.goto``
- Add follow_imports to ``Name.goto``. Now its signature matches
``Script.goto``.
- **Python 2 support deprecated**. For this release it is best effort. Python 2
has reached the end of its life and now it's just about a smooth transition.
Bugs for Python 2 will not be fixed anymore and a third of the tests are
already skipped.
- Removed ``settings.no_completion_duplicates``. It wasn't tested and nobody
was probably using it anyway.
- Removed ``settings.use_filesystem_cache`` and
``settings.additional_dynamic_modules``, they have no usage anymore. Pretty
much nobody was probably using them.
0.15.2 (2019-12-20)
+++++++++++++++++++
- Signatures are now detected a lot better
- Add fuzzy completions with ``Script(...).completions(fuzzy=True)``
- Files bigger than one MB (about 20kLOC) get cropped to avoid getting
stuck completely.
- Many small Bugfixes
- A big refactoring around contexts/values
0.15.1 (2019-08-13)
+++++++++++++++++++
- Small bugfix and removal of a print statement
0.15.0 (2019-08-11)
+++++++++++++++++++
- Added file path completions, there's a **new** ``Completion.type`` now:
``path``. Example: ``'/ho`` -> ``'/home/``
- ``*args``/``**kwargs`` resolving. If possible Jedi replaces the parameters
with the actual alternatives.
- Better support for enums/dataclasses
- When using Interpreter, properties are now executed, since a lot of people
have complained about this. Discussion in #1299, #1347.
New APIs:
- ``Name.get_signatures() -> List[Signature]``. Signatures are similar to
``CallSignature``. ``Name.params`` is therefore deprecated.
- ``Signature.to_string()`` to format signatures.
- ``Signature.params -> List[ParamName]``, ParamName has the
following additional attributes ``infer_default()``, ``infer_annotation()``,
``to_string()``, and ``kind``.
- ``Name.execute() -> List[Name]``, makes it possible to infer
return values of functions.
0.14.1 (2019-07-13)
+++++++++++++++++++
- CallSignature.index should now be working a lot better
- A couple of smaller bugfixes
0.14.0 (2019-06-20)
+++++++++++++++++++
- Added ``goto_*(prefer_stubs=True)`` as well as ``goto_*(prefer_stubs=True)``
- Stubs are used now for type inference
- Typeshed is used for better type inference
- Reworked Name.full_name, should have more correct return values
0.13.3 (2019-02-24)
+++++++++++++++++++
- Fixed an issue with embedded Python, see https://github.com/davidhalter/jedi-vim/issues/870
0.13.2 (2018-12-15)
+++++++++++++++++++
- Fixed a bug that led to Jedi spawning a lot of subprocesses.
0.13.1 (2018-10-02)
+++++++++++++++++++
- Bugfixes, because tensorflow completions were still slow.
0.13.0 (2018-10-02)
+++++++++++++++++++
- A small release. Some bug fixes.
- Remove Python 3.3 support. Python 3.3 support has been dropped by the Python
foundation.
- Default environments are now using the same Python version as the Python
process. In 0.12.x, we used to load the latest Python version on the system.
- Added ``include_builtins`` as a parameter to usages.
- ``goto_assignments`` has a new ``follow_builtin_imports`` parameter that
changes the previous behavior slightly.
0.12.1 (2018-06-30)
+++++++++++++++++++
- This release forces you to upgrade parso. If you don't, nothing will work
anymore. Otherwise changes should be limited to bug fixes. Unfortunately Jedi
still uses a few internals of parso that make it hard to keep compatibility
over multiple releases. Parso >=0.3.0 is going to be needed.
0.12.0 (2018-04-15)
+++++++++++++++++++
- Virtualenv/Environment support
- F-String Completion/Goto Support
- Cannot crash with segfaults anymore
- Cleaned up import logic
- Understand async/await and autocomplete it (including async generators)
- Better namespace completions
- Passing tests for Windows (including CI for Windows)
- Remove Python 2.6 support
0.11.1 (2017-12-14)
+++++++++++++++++++
- Parso update - the caching layer was broken
- Better usages - a lot of internal code was ripped out and improved.
0.11.0 (2017-09-20)
+++++++++++++++++++
- Split Jedi's parser into a separate project called ``parso``.
- Avoiding side effects in REPL completion.
- Numpy docstring support should be much better.
- Moved the `settings.*recursion*` away, they are no longer usable.
0.10.2 (2017-04-05)
+++++++++++++++++++
- Python Packaging sucks. Some files were not included in 0.10.1.
0.10.1 (2017-04-05)
+++++++++++++++++++
- Fixed a few very annoying bugs.
- Prepared the parser to be factored out of Jedi.
0.10.0 (2017-02-03)
+++++++++++++++++++
- Actual semantic completions for the complete Python syntax.
- Basic type inference for ``yield from`` PEP 380.
- PEP 484 support (most of the important features of it). Thanks Claude! (@reinhrst)
- Added ``get_line_code`` to ``Name`` and ``Completion`` objects.
- Completely rewritten the type inference engine.
- A new and better parser for (fast) parsing diffs of Python code.
0.9.0 (2015-04-10)
++++++++++++++++++
- The import logic has been rewritten to look more like Python's. There is now
an ``InferState.modules`` import cache, which resembles ``sys.modules``.
- Integrated the parser of 2to3. This will make refactoring possible. It will
also be possible to check for error messages (like compiling an AST would give)
in the future.
- With the new parser, the type inference also completely changed. It's now
simpler and more readable.
- Completely rewritten REPL completion.
- Added ``jedi.names``, a command to do static analysis. Thanks to that
sourcegraph guys for sponsoring this!
- Alpha version of the linter.
0.8.1 (2014-07-23)
+++++++++++++++++++
- Bugfix release, the last release forgot to include files that improve
autocompletion for builtin libraries. Fixed.
0.8.0 (2014-05-05)
+++++++++++++++++++
- Memory Consumption for compiled modules (e.g. builtins, sys) has been reduced
drastically. Loading times are down as well (it takes basically as long as an
import).
- REPL completion is starting to become usable.
- Various small API changes. Generally this release focuses on stability and
refactoring of internal APIs.
- Introducing operator precedence, which makes calculating correct Array
indices and ``__getattr__`` strings possible.
0.7.0 (2013-08-09)
++++++++++++++++++
- Switched from LGPL to MIT license.
- Added an Interpreter class to the API to make autocompletion in REPL
possible.
- Added autocompletion support for namespace packages.
- Add sith.py, a new random testing method.
0.6.0 (2013-05-14)
++++++++++++++++++
- Much faster parser with builtin part caching.
- A test suite, thanks @tkf.
0.5 versions (2012)
+++++++++++++++++++
- Initial development.

View File

@ -1,507 +0,0 @@
Metadata-Version: 2.0
Name: jedi
Version: 0.17.0
Summary: An autocompletion tool for Python that can be used for text editors.
Home-page: https://github.com/davidhalter/jedi
Author: David Halter
Author-email: davidhalter88@gmail.com
Maintainer: David Halter
Maintainer-email: davidhalter88@gmail.com
License: MIT
Keywords: python completion refactoring vim
Platform: any
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Plugins
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Editors :: Integrated Development Environments (IDE)
Classifier: Topic :: Utilities
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
Provides-Extra: qa
Provides-Extra: testing
Requires-Dist: parso (>=0.7.0)
Provides-Extra: qa
Requires-Dist: flake8 (==3.7.9); extra == 'qa'
Provides-Extra: testing
Requires-Dist: colorama; extra == 'testing'
Requires-Dist: docopt; extra == 'testing'
Requires-Dist: pytest (<5.0.0,>=3.9.0); extra == 'testing'
####################################################################################
Jedi - an awesome autocompletion, static analysis and refactoring library for Python
####################################################################################
.. image:: http://isitmaintained.com/badge/open/davidhalter/jedi.svg
:target: https://github.com/davidhalter/jedi/issues
:alt: The percentage of open issues and pull requests
.. image:: http://isitmaintained.com/badge/resolution/davidhalter/jedi.svg
:target: https://github.com/davidhalter/jedi/issues
:alt: The resolution time is the median time an issue or pull request stays open.
.. image:: https://travis-ci.org/davidhalter/jedi.svg?branch=master
:target: https://travis-ci.org/davidhalter/jedi
:alt: Linux Tests
.. image:: https://ci.appveyor.com/api/projects/status/mgva3bbawyma1new/branch/master?svg=true
:target: https://ci.appveyor.com/project/davidhalter/jedi/branch/master
:alt: Windows Tests
.. image:: https://coveralls.io/repos/davidhalter/jedi/badge.svg?branch=master
:target: https://coveralls.io/r/davidhalter/jedi
:alt: Coverage status
Jedi is a static analysis tool for Python that is typically used in
IDEs/editors plugins. Jedi has a focus on autocompletion and goto
functionality. Other features include refactoring, code search and finding
references.
Jedi has a simple API to work with. There is a reference implementation as a
`VIM-Plugin <https://github.com/davidhalter/jedi-vim>`_. Autocompletion in your
REPL is also possible, IPython uses it natively and for the CPython REPL you
can install it. Jedi is well tested and bugs should be rare.
Jedi can currently be used with the following editors/projects:
- Vim (jedi-vim_, YouCompleteMe_, deoplete-jedi_, completor.vim_)
- `Visual Studio Code`_ (via `Python Extension <https://marketplace.visualstudio.com/items?itemName=ms-python.python>`_)
- Emacs (Jedi.el_, company-mode_, elpy_, anaconda-mode_, ycmd_)
- Sublime Text (SublimeJEDI_ [ST2 + ST3], anaconda_ [only ST3])
- TextMate_ (Not sure if it's actually working)
- Kate_ version 4.13+ supports it natively, you have to enable it, though. [`see
<https://projects.kde.org/projects/kde/applications/kate/repository/show?rev=KDE%2F4.13>`_]
- Atom_ (autocomplete-python-jedi_)
- `GNOME Builder`_ (with support for GObject Introspection)
- Gedit (gedi_)
- wdb_ - Web Debugger
- `Eric IDE`_ (Available as a plugin)
- `IPython 6.0.0+ <https://ipython.readthedocs.io/en/stable/whatsnew/version6.html>`_
and many more!
Here are some pictures taken from jedi-vim_:
.. image:: https://github.com/davidhalter/jedi/raw/master/docs/_screenshots/screenshot_complete.png
Completion for almost anything:
.. image:: https://github.com/davidhalter/jedi/raw/master/docs/_screenshots/screenshot_function.png
Documentation:
.. image:: https://github.com/davidhalter/jedi/raw/master/docs/_screenshots/screenshot_pydoc.png
Get the latest version from `github <https://github.com/davidhalter/jedi>`_
(master branch should always be kind of stable/working).
Docs are available at `https://jedi.readthedocs.org/en/latest/
<https://jedi.readthedocs.org/en/latest/>`_. Pull requests with enhancements
and/or fixes are awesome and most welcome. Jedi uses `semantic versioning
<https://semver.org/>`_.
If you want to stay up-to-date (News / RFCs), please subscribe to this `github
thread <https://github.com/davidhalter/jedi/issues/1063>`_.:
Issues & Questions
==================
You can file issues and questions in the `issue tracker
<https://github.com/davidhalter/jedi/>`. Alternatively you can also ask on
`Stack Overflow <https://stackoverflow.com/questions/tagged/python-jedi>`_ with
the label ``python-jedi``.
Installation
============
`Check out the docs <https://jedi.readthedocs.org/en/latest/docs/installation.html>`_.
Features and Limitations
========================
Jedi's features are listed here:
`Features <https://jedi.readthedocs.org/en/latest/docs/features.html>`_.
You can run Jedi on CPython 2.7 or 3.5+ but it should also
understand code that is older than those versions. Additionally you should be
able to use `Virtualenvs <https://jedi.readthedocs.org/en/latest/docs/api.html#environments>`_
very well.
Tips on how to use Jedi efficiently can be found `here
<https://jedi.readthedocs.org/en/latest/docs/features.html#recipes>`_.
API
---
You can find a comprehensive documentation for the
`API here <https://jedi.readthedocs.org/en/latest/docs/api.html>`_.
Autocompletion / Goto / Documentation
-------------------------------------
There are the following commands:
- ``jedi.Script.goto``
- ``jedi.Script.infer``
- ``jedi.Script.help``
- ``jedi.Script.complete``
- ``jedi.Script.get_references``
- ``jedi.Script.get_signatures``
- ``jedi.Script.get_context``
The returned objects are very powerful and are really all you might need.
Autocompletion in your REPL (IPython, etc.)
-------------------------------------------
Jedi is a dependency of IPython. Autocompletion in IPython with Jedi is
therefore possible without additional configuration.
Here is an `example video <https://vimeo.com/122332037>`_ how REPL completion
can look like.
For the ``python`` shell you can enable tab completion in a `REPL
<https://jedi.readthedocs.org/en/latest/docs/usage.html#tab-completion-in-the-python-shell>`_.
Static Analysis
---------------
For a lot of forms of static analysis, you can try to use
``jedi.Script(...).get_names``. It will return a list of names that you can
then filter and work with. There is also a way to list the syntax errors in a
file: ``jedi.Script.get_syntax_errors``.
Refactoring
-----------
Jedi supports the following refactorings:
- ``jedi.Script.inline``
- ``jedi.Script.rename``
- ``jedi.Script.extract_function``
- ``jedi.Script.extract_variable``
Code Search
-----------
There is support for module search with ``jedi.Script.search``, and project
search for ``jedi.Project.search``. The way to search is either by providing a
name like ``foo`` or by using dotted syntax like ``foo.bar``. Additionally you
can provide the API type like ``class foo.bar.Bar``. There are also the
functions ``jedi.Script.complete_search`` and ``jedi.Project.complete_search``.
Development
===========
There's a pretty good and extensive `development documentation
<https://jedi.readthedocs.org/en/latest/docs/development.html>`_.
Testing
=======
The test suite uses ``pytest``::
pip install pytest
If you want to test only a specific Python version (e.g. Python 3.8), it is as
easy as::
python3.8 -m pytest
For more detailed information visit the `testing documentation
<https://jedi.readthedocs.org/en/latest/docs/testing.html>`_.
Acknowledgements
================
Thanks a lot to all the
`contributors <https://jedi.readthedocs.org/en/latest/docs/acknowledgements.html>`_!
.. _jedi-vim: https://github.com/davidhalter/jedi-vim
.. _youcompleteme: https://github.com/ycm-core/YouCompleteMe
.. _deoplete-jedi: https://github.com/zchee/deoplete-jedi
.. _completor.vim: https://github.com/maralla/completor.vim
.. _Jedi.el: https://github.com/tkf/emacs-jedi
.. _company-mode: https://github.com/syohex/emacs-company-jedi
.. _elpy: https://github.com/jorgenschaefer/elpy
.. _anaconda-mode: https://github.com/proofit404/anaconda-mode
.. _ycmd: https://github.com/abingham/emacs-ycmd
.. _sublimejedi: https://github.com/srusskih/SublimeJEDI
.. _anaconda: https://github.com/DamnWidget/anaconda
.. _wdb: https://github.com/Kozea/wdb
.. _TextMate: https://github.com/lawrenceakka/python-jedi.tmbundle
.. _Kate: https://kate-editor.org
.. _Atom: https://atom.io/
.. _autocomplete-python-jedi: https://atom.io/packages/autocomplete-python-jedi
.. _GNOME Builder: https://wiki.gnome.org/Apps/Builder
.. _Visual Studio Code: https://code.visualstudio.com/
.. _gedi: https://github.com/isamert/gedi
.. _Eric IDE: https://eric-ide.python-projects.org
.. :changelog:
Changelog
---------
0.17.0 (2020-04-14)
+++++++++++++++++++
- Added ``Project`` support. This allows a user to specify which folders Jedi
should work with.
- Added support for Refactoring. The following refactorings have been
implemented: ``Script.rename``, ``Script.inline``,
``Script.extract_variable`` and ``Script.extract_function``.
- Added ``Script.get_syntax_errors`` to display syntax errors in the current
script.
- Added code search capabilities both for individual files and projects. The
new functions are ``Project.search``, ``Project.complete_search``,
``Script.search`` and ``Script.complete_search``.
- Added ``Script.help`` to make it easier to display a help window to people.
Now returns pydoc information as well for Python keywords/operators. This
means that on the class keyword it will now return the docstring of Python's
builtin function ``help('class')``.
- The API documentation is now way more readable and complete. Check it out
under https://jedi.readthedocs.io. A lot of it has been rewritten.
- Removed Python 3.4 support
- Many bugfixes
This is likely going to be the last minor version that supports Python 2 and
Python3.5. Bugfixes will be provided in 0.17.1+. The next minor/major version
will probably be Jedi 1.0.0.
0.16.0 (2020-01-26)
+++++++++++++++++++
- **Added** ``Script.get_context`` to get information where you currently are.
- Completions/type inference of **Pytest fixtures**.
- Tensorflow, Numpy and Pandas completions should now be about **4-10x faster**
after the first time they are used.
- Dict key completions are working now. e.g. ``d = {1000: 3}; d[10`` will
expand to ``1000``.
- Completion for "proxies" works now. These are classes that have a
``__getattr__(self, name)`` method that does a ``return getattr(x, name)``.
after loading them initially.
- Goto on a function/attribute in a class now goes to the definition in its
super class.
- Big **Script API Changes**:
- The line and column parameters of ``jedi.Script`` are now deprecated
- ``completions`` deprecated, use ``complete`` instead
- ``goto_assignments`` deprecated, use ``goto`` instead
- ``goto_definitions`` deprecated, use ``infer`` instead
- ``call_signatures`` deprecated, use ``get_signatures`` instead
- ``usages`` deprecated, use ``get_references`` instead
- ``jedi.names`` deprecated, use ``jedi.Script(...).get_names()``
- ``BaseName.goto_assignments`` renamed to ``BaseName.goto``
- Add follow_imports to ``Name.goto``. Now its signature matches
``Script.goto``.
- **Python 2 support deprecated**. For this release it is best effort. Python 2
has reached the end of its life and now it's just about a smooth transition.
Bugs for Python 2 will not be fixed anymore and a third of the tests are
already skipped.
- Removed ``settings.no_completion_duplicates``. It wasn't tested and nobody
was probably using it anyway.
- Removed ``settings.use_filesystem_cache`` and
``settings.additional_dynamic_modules``, they have no usage anymore. Pretty
much nobody was probably using them.
0.15.2 (2019-12-20)
+++++++++++++++++++
- Signatures are now detected a lot better
- Add fuzzy completions with ``Script(...).completions(fuzzy=True)``
- Files bigger than one MB (about 20kLOC) get cropped to avoid getting
stuck completely.
- Many small Bugfixes
- A big refactoring around contexts/values
0.15.1 (2019-08-13)
+++++++++++++++++++
- Small bugfix and removal of a print statement
0.15.0 (2019-08-11)
+++++++++++++++++++
- Added file path completions, there's a **new** ``Completion.type`` now:
``path``. Example: ``'/ho`` -> ``'/home/``
- ``*args``/``**kwargs`` resolving. If possible Jedi replaces the parameters
with the actual alternatives.
- Better support for enums/dataclasses
- When using Interpreter, properties are now executed, since a lot of people
have complained about this. Discussion in #1299, #1347.
New APIs:
- ``Name.get_signatures() -> List[Signature]``. Signatures are similar to
``CallSignature``. ``Name.params`` is therefore deprecated.
- ``Signature.to_string()`` to format signatures.
- ``Signature.params -> List[ParamName]``, ParamName has the
following additional attributes ``infer_default()``, ``infer_annotation()``,
``to_string()``, and ``kind``.
- ``Name.execute() -> List[Name]``, makes it possible to infer
return values of functions.
0.14.1 (2019-07-13)
+++++++++++++++++++
- CallSignature.index should now be working a lot better
- A couple of smaller bugfixes
0.14.0 (2019-06-20)
+++++++++++++++++++
- Added ``goto_*(prefer_stubs=True)`` as well as ``goto_*(prefer_stubs=True)``
- Stubs are used now for type inference
- Typeshed is used for better type inference
- Reworked Name.full_name, should have more correct return values
0.13.3 (2019-02-24)
+++++++++++++++++++
- Fixed an issue with embedded Python, see https://github.com/davidhalter/jedi-vim/issues/870
0.13.2 (2018-12-15)
+++++++++++++++++++
- Fixed a bug that led to Jedi spawning a lot of subprocesses.
0.13.1 (2018-10-02)
+++++++++++++++++++
- Bugfixes, because tensorflow completions were still slow.
0.13.0 (2018-10-02)
+++++++++++++++++++
- A small release. Some bug fixes.
- Remove Python 3.3 support. Python 3.3 support has been dropped by the Python
foundation.
- Default environments are now using the same Python version as the Python
process. In 0.12.x, we used to load the latest Python version on the system.
- Added ``include_builtins`` as a parameter to usages.
- ``goto_assignments`` has a new ``follow_builtin_imports`` parameter that
changes the previous behavior slightly.
0.12.1 (2018-06-30)
+++++++++++++++++++
- This release forces you to upgrade parso. If you don't, nothing will work
anymore. Otherwise changes should be limited to bug fixes. Unfortunately Jedi
still uses a few internals of parso that make it hard to keep compatibility
over multiple releases. Parso >=0.3.0 is going to be needed.
0.12.0 (2018-04-15)
+++++++++++++++++++
- Virtualenv/Environment support
- F-String Completion/Goto Support
- Cannot crash with segfaults anymore
- Cleaned up import logic
- Understand async/await and autocomplete it (including async generators)
- Better namespace completions
- Passing tests for Windows (including CI for Windows)
- Remove Python 2.6 support
0.11.1 (2017-12-14)
+++++++++++++++++++
- Parso update - the caching layer was broken
- Better usages - a lot of internal code was ripped out and improved.
0.11.0 (2017-09-20)
+++++++++++++++++++
- Split Jedi's parser into a separate project called ``parso``.
- Avoiding side effects in REPL completion.
- Numpy docstring support should be much better.
- Moved the `settings.*recursion*` away, they are no longer usable.
0.10.2 (2017-04-05)
+++++++++++++++++++
- Python Packaging sucks. Some files were not included in 0.10.1.
0.10.1 (2017-04-05)
+++++++++++++++++++
- Fixed a few very annoying bugs.
- Prepared the parser to be factored out of Jedi.
0.10.0 (2017-02-03)
+++++++++++++++++++
- Actual semantic completions for the complete Python syntax.
- Basic type inference for ``yield from`` PEP 380.
- PEP 484 support (most of the important features of it). Thanks Claude! (@reinhrst)
- Added ``get_line_code`` to ``Name`` and ``Completion`` objects.
- Completely rewritten the type inference engine.
- A new and better parser for (fast) parsing diffs of Python code.
0.9.0 (2015-04-10)
++++++++++++++++++
- The import logic has been rewritten to look more like Python's. There is now
an ``InferState.modules`` import cache, which resembles ``sys.modules``.
- Integrated the parser of 2to3. This will make refactoring possible. It will
also be possible to check for error messages (like compiling an AST would give)
in the future.
- With the new parser, the type inference also completely changed. It's now
simpler and more readable.
- Completely rewritten REPL completion.
- Added ``jedi.names``, a command to do static analysis. Thanks to that
sourcegraph guys for sponsoring this!
- Alpha version of the linter.
0.8.1 (2014-07-23)
+++++++++++++++++++
- Bugfix release, the last release forgot to include files that improve
autocompletion for builtin libraries. Fixed.
0.8.0 (2014-05-05)
+++++++++++++++++++
- Memory Consumption for compiled modules (e.g. builtins, sys) has been reduced
drastically. Loading times are down as well (it takes basically as long as an
import).
- REPL completion is starting to become usable.
- Various small API changes. Generally this release focuses on stability and
refactoring of internal APIs.
- Introducing operator precedence, which makes calculating correct Array
indices and ``__getattr__`` strings possible.
0.7.0 (2013-08-09)
++++++++++++++++++
- Switched from LGPL to MIT license.
- Added an Interpreter class to the API to make autocompletion in REPL
possible.
- Added autocompletion support for namespace packages.
- Add sith.py, a new random testing method.
0.6.0 (2013-05-14)
++++++++++++++++++
- Much faster parser with builtin part caching.
- A test suite, thanks @tkf.
0.5 versions (2012)
+++++++++++++++++++
- Initial development.

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +0,0 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.29.0)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

View File

@ -1 +0,0 @@
{"classifiers": ["Development Status :: 4 - Beta", "Environment :: Plugins", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Text Editors :: Integrated Development Environments (IDE)", "Topic :: Utilities"], "extensions": {"python.details": {"contacts": [{"email": "davidhalter88@gmail.com", "name": "David Halter", "role": "author"}, {"email": "davidhalter88@gmail.com", "name": "David Halter", "role": "maintainer"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/davidhalter/jedi"}}}, "extras": ["qa", "testing"], "generator": "bdist_wheel (0.29.0)", "keywords": ["python", "completion", "refactoring", "vim"], "license": "MIT", "metadata_version": "2.0", "name": "jedi", "platform": "any", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", "run_requires": [{"extra": "testing", "requires": ["colorama", "docopt", "pytest (<5.0.0,>=3.9.0)"]}, {"extra": "qa", "requires": ["flake8 (==3.7.9)"]}, {"requires": ["parso (>=0.7.0)"]}], "summary": "An autocompletion tool for Python that can be used for text editors.", "version": "0.17.0"}

View File

@ -27,7 +27,7 @@ ad
load load
""" """
__version__ = '0.17.0' __version__ = '0.17.1'
from jedi.api import Script, Interpreter, set_debug_function, \ from jedi.api import Script, Interpreter, set_debug_function, \
preload_module, names preload_module, names

View File

@ -44,20 +44,29 @@ def _complete():
import jedi import jedi
import pdb import pdb
if '-d' in sys.argv:
sys.argv.remove('-d')
jedi.set_debug_function()
try: try:
for c in jedi.Script(sys.argv[2]).complete(): completions = jedi.Script(sys.argv[2]).complete()
for c in completions:
c.docstring() c.docstring()
c.type c.type
except Exception as e: except Exception as e:
print(e) print(repr(e))
pdb.post_mortem() pdb.post_mortem()
else:
print(completions)
if len(sys.argv) == 2 and sys.argv[1] == 'repl': if len(sys.argv) == 2 and sys.argv[1] == 'repl':
# don't want to use __main__ only for repl yet, maybe we want to use it for # don't want to use __main__ only for repl yet, maybe we want to use it for
# something else. So just use the keyword ``repl`` for now. # something else. So just use the keyword ``repl`` for now.
print(join(dirname(abspath(__file__)), 'api', 'replstartup.py')) print(join(dirname(abspath(__file__)), 'api', 'replstartup.py'))
elif len(sys.argv) > 1 and sys.argv[1] == 'linter': elif len(sys.argv) > 1 and sys.argv[1] == '_linter':
_start_linter() _start_linter()
elif len(sys.argv) > 1 and sys.argv[1] == '_complete': elif len(sys.argv) > 1 and sys.argv[1] == '_complete':
_complete() _complete()
else:
print('Command not implemented: %s' % sys.argv[1])

View File

@ -339,6 +339,13 @@ try:
except NameError: except NameError:
PermissionError = IOError PermissionError = IOError
try:
NotADirectoryError = NotADirectoryError
except NameError:
class NotADirectoryError(Exception):
# Don't implement this for Python 2 anymore.
pass
def no_unicode_pprint(dct): def no_unicode_pprint(dct):
""" """

View File

@ -97,7 +97,7 @@ class Script(object):
an issue for people that do more complex stuff with Jedi. an issue for people that do more complex stuff with Jedi.
This is purely a performance optimization and works pretty well for all This is purely a performance optimization and works pretty well for all
typical usages, however consider to turn the setting of if it causes typical usages, however consider to turn the setting off if it causes
you problems. See also you problems. See also
`this discussion <https://github.com/davidhalter/jedi/issues/1240>`_. `this discussion <https://github.com/davidhalter/jedi/issues/1240>`_.
@ -128,15 +128,6 @@ class Script(object):
# An empty path (also empty string) should always result in no path. # An empty path (also empty string) should always result in no path.
self.path = os.path.abspath(path) if path else None self.path = os.path.abspath(path) if path else None
# TODO deprecate and remove sys_path from the Script API.
if sys_path is not None:
project._sys_path = sys_path
warnings.warn(
"Deprecated since version 0.17.0. Use the project API instead, "
"which means Script(project=Project(dir, sys_path=sys_path)) instead.",
DeprecationWarning,
stacklevel=2
)
if encoding is None: if encoding is None:
encoding = 'utf-8' encoding = 'utf-8'
else: else:
@ -180,6 +171,15 @@ class Script(object):
project = get_default_project( project = get_default_project(
os.path.dirname(self.path) if path else None os.path.dirname(self.path) if path else None
) )
# TODO deprecate and remove sys_path from the Script API.
if sys_path is not None:
project._sys_path = sys_path
warnings.warn(
"Deprecated since version 0.17.0. Use the project API instead, "
"which means Script(project=Project(dir, sys_path=sys_path)) instead.",
DeprecationWarning,
stacklevel=2
)
self._inference_state = InferenceState( self._inference_state = InferenceState(
project, environment=environment, script_path=self.path project, environment=environment, script_path=self.path
@ -472,9 +472,20 @@ class Script(object):
if definitions: if definitions:
return definitions return definitions
leaf = self._module_node.get_leaf_for_position((line, column)) leaf = self._module_node.get_leaf_for_position((line, column))
if leaf.type in ('keyword', 'operator', 'error_leaf'): if leaf is not None and leaf.type in ('keyword', 'operator', 'error_leaf'):
reserved = self._inference_state.grammar._pgen_grammar.reserved_syntax_strings.keys() def need_pydoc():
if leaf.value in reserved: if leaf.value in ('(', ')', '[', ']'):
if leaf.parent.type == 'trailer':
return False
if leaf.parent.type == 'atom':
return False
grammar = self._inference_state.grammar
# This parso stuff is not public, but since I control it, this
# is fine :-) ~dave
reserved = grammar._pgen_grammar.reserved_syntax_strings.keys()
return leaf.value in reserved
if need_pydoc():
name = KeywordName(self._inference_state, leaf.value) name = KeywordName(self._inference_state, leaf.value)
return [classes.Name(self._inference_state, name)] return [classes.Name(self._inference_state, name)]
return [] return []
@ -494,21 +505,25 @@ class Script(object):
quite hard to do for Jedi, if it is too complicated, Jedi will stop quite hard to do for Jedi, if it is too complicated, Jedi will stop
searching. searching.
:param include_builtins: Default True, checks if a reference is a :param include_builtins: Default ``True``. If ``False``, checks if a reference
builtin (e.g. ``sys``) and in that case does not return it. is a builtin (e.g. ``sys``) and in that case does not return it.
:param scope: Default ``'project'``. If ``'file'``, include references in
the current module only.
:rtype: list of :class:`.Name` :rtype: list of :class:`.Name`
""" """
def _references(include_builtins=True): def _references(include_builtins=True, scope='project'):
if scope not in ('project', 'file'):
raise ValueError('Only the scopes "file" and "project" are allowed')
tree_name = self._module_node.get_name_of_position((line, column)) tree_name = self._module_node.get_name_of_position((line, column))
if tree_name is None: if tree_name is None:
# Must be syntax # Must be syntax
return [] return []
names = find_references(self._get_module_context(), tree_name) names = find_references(self._get_module_context(), tree_name, scope == 'file')
definitions = [classes.Name(self._inference_state, n) for n in names] definitions = [classes.Name(self._inference_state, n) for n in names]
if not include_builtins: if not include_builtins or scope == 'file':
definitions = [d for d in definitions if not d.in_builtin_module()] definitions = [d for d in definitions if not d.in_builtin_module()]
return helpers.sorted_definitions(definitions) return helpers.sorted_definitions(definitions)
return _references(**kwargs) return _references(**kwargs)
@ -748,10 +763,11 @@ class Script(object):
global_var = 3 global_var = 3
def bar(foo): def bar(foo):
return foo + 1 + global_var return int(foo + 1 + global_var)
def x(foo): def x():
x = int(bar(foo)) foo = 3.1
x = bar(foo)
:param new_name: The expression under the cursor will be replaced with :param new_name: The expression under the cursor will be replaced with
a function with this name. a function with this name.

View File

@ -25,6 +25,7 @@ from jedi.inference.utils import unite
from jedi.cache import memoize_method from jedi.cache import memoize_method
from jedi.inference import imports from jedi.inference import imports
from jedi.inference.imports import ImportName from jedi.inference.imports import ImportName
from jedi.inference.compiled.mixed import MixedName
from jedi.inference.gradual.typeshed import StubModuleValue from jedi.inference.gradual.typeshed import StubModuleValue
from jedi.inference.gradual.conversion import convert_names, convert_values from jedi.inference.gradual.conversion import convert_names, convert_values
from jedi.inference.base_value import ValueSet from jedi.inference.base_value import ValueSet
@ -94,7 +95,11 @@ class BaseName(object):
@property @property
def module_path(self): def module_path(self):
"""Shows the file path of a module. e.g. ``/usr/lib/python2.7/os.py``""" """
Shows the file path of a module. e.g. ``/usr/lib/python2.7/os.py``
:rtype: str or None
"""
module = self._get_module_context() module = self._get_module_context()
if module.is_stub() or not module.is_compiled(): if module.is_stub() or not module.is_compiled():
# Compiled modules should not return a module path even if they # Compiled modules should not return a module path even if they
@ -168,7 +173,7 @@ class BaseName(object):
>>> defs[3] >>> defs[3]
'function' 'function'
Valid values for are ``module``, ``class``, ``instance``, ``function``, Valid values for type are ``module``, ``class``, ``instance``, ``function``,
``param``, ``path``, ``keyword`` and ``statement``. ``param``, ``path``, ``keyword`` and ``statement``.
""" """
@ -226,6 +231,39 @@ class BaseName(object):
return None return None
return start_pos[1] return start_pos[1]
def get_definition_start_position(self):
"""
The (row, column) of the start of the definition range. Rows start with
1, columns start with 0.
:rtype: Optional[Tuple[int, int]]
"""
if self._name.tree_name is None:
return None
definition = self._name.tree_name.get_definition()
if definition is None:
return self._name.start_pos
return definition.start_pos
def get_definition_end_position(self):
"""
The (row, column) of the end of the definition range. Rows start with
1, columns start with 0.
:rtype: Optional[Tuple[int, int]]
"""
if self._name.tree_name is None:
return None
definition = self._name.tree_name.get_definition()
if definition is None:
return self._name.tree_name.end_pos
if self.type in ("function", "class"):
last_leaf = definition.get_last_leaf()
if last_leaf.type == "newline":
return last_leaf.get_previous_leaf().end_pos
return last_leaf.end_pos
return definition.end_pos
def docstring(self, raw=False, fast=True): def docstring(self, raw=False, fast=True):
r""" r"""
Return a document string for this completion object. Return a document string for this completion object.
@ -245,8 +283,8 @@ class BaseName(object):
Document for function f. Document for function f.
Notice that useful extra information is added to the actual Notice that useful extra information is added to the actual
docstring. For function, it is signature. If you need docstring, e.g. function signatures are prepended to their docstrings.
actual docstring, use ``raw=True`` instead. If you need the actual docstring, use ``raw=True`` instead.
>>> print(script.infer(1, len('def f'))[0].docstring(raw=True)) >>> print(script.infer(1, len('def f'))[0].docstring(raw=True))
Document for function f. Document for function f.
@ -557,6 +595,12 @@ class BaseName(object):
# statements and not stubs. This is a speed optimization. # statements and not stubs. This is a speed optimization.
return [] return []
if isinstance(self._name, MixedName):
# While this would eventually happen anyway, it's basically just a
# shortcut to not infer anything tree related, because it's really
# not necessary.
return self._name.infer_compiled_value().get_signatures()
names = convert_names([self._name], prefer_stubs=True) names = convert_names([self._name], prefer_stubs=True)
return [sig for name in names for sig in name.infer().get_signatures()] return [sig for name in names for sig in name.infer().get_signatures()]
@ -665,7 +709,7 @@ class Completion(BaseName):
def docstring(self, raw=False, fast=True): def docstring(self, raw=False, fast=True):
""" """
Documentated under :meth:`BaseName.docstring`. Documented under :meth:`BaseName.docstring`.
""" """
if self._like_name_length >= 3: if self._like_name_length >= 3:
# In this case we can just resolve the like name, because we # In this case we can just resolve the like name, because we
@ -693,9 +737,8 @@ class Completion(BaseName):
return super(Completion, self)._get_docstring_signature() return super(Completion, self)._get_docstring_signature()
def _get_cache(self): def _get_cache(self):
typ = super(Completion, self).type
return ( return (
typ, super(Completion, self).type,
super(Completion, self)._get_docstring_signature(), super(Completion, self)._get_docstring_signature(),
super(Completion, self)._get_docstring(), super(Completion, self)._get_docstring(),
) )
@ -703,7 +746,7 @@ class Completion(BaseName):
@property @property
def type(self): def type(self):
""" """
Documentated under :meth:`BaseName.type`. Documented under :meth:`BaseName.type`.
""" """
# Purely a speed optimization. # Purely a speed optimization.
if self._cached_name is not None: if self._cached_name is not None:
@ -734,8 +777,7 @@ class Name(BaseName):
DeprecationWarning, DeprecationWarning,
stacklevel=2 stacklevel=2
) )
position = '' if self.in_builtin_module else '@%s' % self.line return "%s:%s" % (self.module_name, self.description)
return "%s:%s%s" % (self.module_name, self.description, position)
@memoize_method @memoize_method
def defined_names(self): def defined_names(self):
@ -798,7 +840,7 @@ class BaseSignature(Name):
Returns a text representation of the signature. This could for example Returns a text representation of the signature. This could for example
look like ``foo(bar, baz: int, **kwargs)``. look like ``foo(bar, baz: int, **kwargs)``.
:return str :rtype: str
""" """
return self._signature.to_string() return self._signature.to_string()
@ -865,7 +907,7 @@ class ParamName(Name):
Returns a simple representation of a param, like Returns a simple representation of a param, like
``f: Callable[..., Any]``. ``f: Callable[..., Any]``.
:rtype: :class:`str` :rtype: str
""" """
return self._name.to_string() return self._name.to_string()

View File

@ -30,16 +30,43 @@ class ParamNameWithEquals(ParamNameWrapper):
return self.string_name + '=' return self.string_name + '='
def get_signature_param_names(signatures): def _get_signature_param_names(signatures, positional_count, used_kwargs):
# add named params # Add named params
for call_sig in signatures: for call_sig in signatures:
for p in call_sig.params: for i, p in enumerate(call_sig.params):
# Allow protected access, because it's a public API. # Allow protected access, because it's a public API.
if p._name.get_kind() in (Parameter.POSITIONAL_OR_KEYWORD, # TODO reconsider with Python 2 drop
Parameter.KEYWORD_ONLY): kind = p._name.get_kind()
if i < positional_count and kind == Parameter.POSITIONAL_OR_KEYWORD:
continue
if kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY) \
and p.name not in used_kwargs:
yield ParamNameWithEquals(p._name) yield ParamNameWithEquals(p._name)
def _must_be_kwarg(signatures, positional_count, used_kwargs):
if used_kwargs:
return True
must_be_kwarg = True
for signature in signatures:
for i, p in enumerate(signature.params):
# TODO reconsider with Python 2 drop
kind = p._name.get_kind()
if kind is Parameter.VAR_POSITIONAL:
# In case there were not already kwargs, the next param can
# always be a normal argument.
return False
if i >= positional_count and kind in (Parameter.POSITIONAL_OR_KEYWORD,
Parameter.POSITIONAL_ONLY):
must_be_kwarg = False
break
if not must_be_kwarg:
break
return must_be_kwarg
def filter_names(inference_state, completion_names, stack, like_name, fuzzy, cached_name): def filter_names(inference_state, completion_names, stack, like_name, fuzzy, cached_name):
comp_dct = set() comp_dct = set()
if settings.case_insensitive_completion: if settings.case_insensitive_completion:
@ -229,14 +256,8 @@ class Completion:
allowed_transitions.append('else') allowed_transitions.append('else')
completion_names = [] completion_names = []
current_line = self._code_lines[self._position[0] - 1][:self._position[1]]
completion_names += self._complete_keywords(
allowed_transitions,
only_values=not (not current_line or current_line[-1] in ' \t.;'
and current_line[-3:] != '...')
)
kwargs_only = False
if any(t in allowed_transitions for t in (PythonTokenTypes.NAME, if any(t in allowed_transitions for t in (PythonTokenTypes.NAME,
PythonTokenTypes.INDENT)): PythonTokenTypes.INDENT)):
# This means that we actually have to do type inference. # This means that we actually have to do type inference.
@ -264,20 +285,41 @@ class Completion:
elif self._is_parameter_completion(): elif self._is_parameter_completion():
completion_names += self._complete_params(leaf) completion_names += self._complete_params(leaf)
else: else:
completion_names += self._complete_global_scope() # Apparently this looks like it's good enough to filter most cases
completion_names += self._complete_inherited(is_function=False) # so that signature completions don't randomly appear.
# To understand why this works, three things are important:
# 1. trailer with a `,` in it is either a subscript or an arglist.
# 2. If there's no `,`, it's at the start and only signatures start
# with `(`. Other trailers could start with `.` or `[`.
# 3. Decorators are very primitive and have an optional `(` with
# optional arglist in them.
if nodes[-1] in ['(', ','] \
and nonterminals[-1] in ('trailer', 'arglist', 'decorator'):
signatures = self._signatures_callback(*self._position)
if signatures:
call_details = signatures[0]._call_details
used_kwargs = list(call_details.iter_used_keyword_arguments())
positional_count = call_details.count_positional_arguments()
# Apparently this looks like it's good enough to filter most cases completion_names += _get_signature_param_names(
# so that signature completions don't randomly appear. signatures,
# To understand why this works, three things are important: positional_count,
# 1. trailer with a `,` in it is either a subscript or an arglist. used_kwargs,
# 2. If there's no `,`, it's at the start and only signatures start )
# with `(`. Other trailers could start with `.` or `[`.
# 3. Decorators are very primitive and have an optional `(` with kwargs_only = _must_be_kwarg(signatures, positional_count, used_kwargs)
# optional arglist in them.
if nodes[-1] in ['(', ','] and nonterminals[-1] in ('trailer', 'arglist', 'decorator'): if not kwargs_only:
signatures = self._signatures_callback(*self._position) completion_names += self._complete_global_scope()
completion_names += get_signature_param_names(signatures) completion_names += self._complete_inherited(is_function=False)
if not kwargs_only:
current_line = self._code_lines[self._position[0] - 1][:self._position[1]]
completion_names += self._complete_keywords(
allowed_transitions,
only_values=not (not current_line or current_line[-1] in ' \t.;'
and current_line[-3:] != '...')
)
return cached_name, completion_names return cached_name, completion_names
@ -301,19 +343,20 @@ class Completion:
if stack_node.nonterminal == 'funcdef': if stack_node.nonterminal == 'funcdef':
context = get_user_context(self._module_context, self._position) context = get_user_context(self._module_context, self._position)
node = search_ancestor(leaf, 'error_node', 'funcdef') node = search_ancestor(leaf, 'error_node', 'funcdef')
if node.type == 'error_node': if node is not None:
n = node.children[0] if node.type == 'error_node':
if n.type == 'decorators': n = node.children[0]
decorators = n.children if n.type == 'decorators':
elif n.type == 'decorator': decorators = n.children
decorators = [n] elif n.type == 'decorator':
decorators = [n]
else:
decorators = []
else: else:
decorators = [] decorators = node.get_decorators()
else: function_name = stack_node.nodes[1]
decorators = node.get_decorators()
function_name = stack_node.nodes[1]
return complete_param_names(context, function_name.value, decorators) return complete_param_names(context, function_name.value, decorators)
return [] return []
def _complete_keywords(self, allowed_transitions, only_values): def _complete_keywords(self, allowed_transitions, only_values):
@ -413,7 +456,7 @@ class Completion:
relevant_code_lines = list(iter_relevant_lines(code_lines)) relevant_code_lines = list(iter_relevant_lines(code_lines))
if relevant_code_lines[-1] is not None: if relevant_code_lines[-1] is not None:
# Some code lines might be None, therefore get rid of that. # Some code lines might be None, therefore get rid of that.
relevant_code_lines = [c or '\n' for c in relevant_code_lines] relevant_code_lines = ['\n' if c is None else c for c in relevant_code_lines]
return self._complete_code_lines(relevant_code_lines) return self._complete_code_lines(relevant_code_lines)
match = re.search(r'`([^`\s]+)', code_lines[-1]) match = re.search(r'`([^`\s]+)', code_lines[-1])
if match: if match:
@ -544,6 +587,9 @@ def _complete_getattr(user_context, instance):
) )
for func in functions: for func in functions:
tree_node = func.tree_node tree_node = func.tree_node
if tree_node is None or tree_node.type != 'funcdef':
continue
for return_stmt in tree_node.iter_return_stmts(): for return_stmt in tree_node.iter_return_stmts():
# Basically until the next comment we just try to find out if a # Basically until the next comment we just try to find out if a
# return statement looks exactly like `return getattr(x, name)`. # return statement looks exactly like `return getattr(x, name)`.

View File

@ -35,6 +35,9 @@ class SyntaxError(object):
"""The column where the error ends (starting with 0).""" """The column where the error ends (starting with 0)."""
return self._parso_error.end_pos[1] return self._parso_error.end_pos[1]
def get_message(self):
return self._parso_error.message
def __repr__(self): def __repr__(self):
return '<%s from=%s to=%s>' % ( return '<%s from=%s to=%s>' % (
self.__class__.__name__, self.__class__.__name__,

View File

@ -15,7 +15,7 @@ from jedi.inference.base_value import NO_VALUES
from jedi.inference.syntax_tree import infer_atom from jedi.inference.syntax_tree import infer_atom
from jedi.inference.helpers import infer_call_of_leaf from jedi.inference.helpers import infer_call_of_leaf
from jedi.inference.compiled import get_string_value_set from jedi.inference.compiled import get_string_value_set
from jedi.cache import signature_time_cache from jedi.cache import signature_time_cache, memoize_method
from jedi.parser_utils import get_parent_scope from jedi.parser_utils import get_parent_scope
@ -216,11 +216,15 @@ class CallDetails(object):
def keyword_name_str(self): def keyword_name_str(self):
return _get_index_and_key(self._children, self._position)[1] return _get_index_and_key(self._children, self._position)[1]
@memoize_method
def _list_arguments(self):
return list(_iter_arguments(self._children, self._position))
def calculate_index(self, param_names): def calculate_index(self, param_names):
positional_count = 0 positional_count = 0
used_names = set() used_names = set()
star_count = -1 star_count = -1
args = list(_iter_arguments(self._children, self._position)) args = self._list_arguments()
if not args: if not args:
if param_names: if param_names:
return 0 return 0
@ -267,6 +271,19 @@ class CallDetails(object):
return i return i
return None return None
def iter_used_keyword_arguments(self):
for star_count, key_start, had_equal in list(self._list_arguments()):
if had_equal and key_start:
yield key_start
def count_positional_arguments(self):
count = 0
for star_count, key_start, had_equal in self._list_arguments()[:-1]:
if star_count:
break
count += 1
return count
def _iter_arguments(nodes, position): def _iter_arguments(nodes, position):
def remove_after_pos(name): def remove_after_pos(name):
@ -385,7 +402,7 @@ def get_signature_details(module, position):
# parents for possible function definitions. # parents for possible function definitions.
node = leaf.parent node = leaf.parent
while node is not None: while node is not None:
if node.type in ('funcdef', 'classdef'): if node.type in ('funcdef', 'classdef', 'decorated', 'async_stmt'):
# Don't show signatures if there's stuff before it that just # Don't show signatures if there's stuff before it that just
# makes it feel strange to have a signature. # makes it feel strange to have a signature.
return None return None
@ -405,7 +422,8 @@ def get_signature_details(module, position):
additional_children.insert(0, n) additional_children.insert(0, n)
# Find a valid trailer # Find a valid trailer
if node.type == 'trailer' and node.children[0] == '(': if node.type == 'trailer' and node.children[0] == '(' \
or node.type == 'decorator' and node.children[2] == '(':
# Additionally we have to check that an ending parenthesis isn't # Additionally we have to check that an ending parenthesis isn't
# interpreted wrong. There are two cases: # interpreted wrong. There are two cases:
# 1. Cursor before paren -> The current signature is good # 1. Cursor before paren -> The current signature is good
@ -414,7 +432,11 @@ def get_signature_details(module, position):
leaf = node.get_previous_leaf() leaf = node.get_previous_leaf()
if leaf is None: if leaf is None:
return None return None
return CallDetails(node.children[0], node.children, position) return CallDetails(
node.children[0] if node.type == 'trailer' else node.children[2],
node.children,
position
)
node = node.parent node = node.parent
@ -453,8 +475,8 @@ def validate_line_column(func):
line_string = self._code_lines[line - 1] line_string = self._code_lines[line - 1]
line_len = len(line_string) line_len = len(line_string)
if line_string.endswith('\r\n'): if line_string.endswith('\r\n'):
line_len -= 1 line_len -= 2
if line_string.endswith('\n'): elif line_string.endswith('\n'):
line_len -= 1 line_len -= 1
column = line_len if column is None else column column = line_len if column is None else column

View File

@ -13,7 +13,7 @@ import json
import sys import sys
from jedi._compatibility import FileNotFoundError, PermissionError, \ from jedi._compatibility import FileNotFoundError, PermissionError, \
IsADirectoryError IsADirectoryError, NotADirectoryError
from jedi import debug from jedi import debug
from jedi.api.environment import get_cached_default_environment, create_environment from jedi.api.environment import get_cached_default_environment, create_environment
from jedi.api.exceptions import WrongVersion from jedi.api.exceptions import WrongVersion
@ -26,7 +26,7 @@ from jedi.inference.sys_path import discover_buildout_paths
from jedi.inference.cache import inference_state_as_method_param_cache from jedi.inference.cache import inference_state_as_method_param_cache
from jedi.inference.references import recurse_find_python_folders_and_files, search_in_file_ios from jedi.inference.references import recurse_find_python_folders_and_files, search_in_file_ios
from jedi.file_io import FolderIO from jedi.file_io import FolderIO
from jedi.common.utils import traverse_parents from jedi.common import traverse_parents
_CONFIG_FOLDER = '.jedi' _CONFIG_FOLDER = '.jedi'
_CONTAINS_POTENTIAL_PROJECT = \ _CONTAINS_POTENTIAL_PROJECT = \
@ -383,6 +383,8 @@ def get_default_project(path=None):
return Project.load(dir) return Project.load(dir)
except (FileNotFoundError, IsADirectoryError, PermissionError): except (FileNotFoundError, IsADirectoryError, PermissionError):
pass pass
except NotADirectoryError:
continue
if first_no_init_file is None: if first_no_init_file is None:
if os.path.exists(os.path.join(dir, '__init__.py')): if os.path.exists(os.path.join(dir, '__init__.py')):

View File

@ -25,11 +25,33 @@ class ChangedFile(object):
def get_diff(self): def get_diff(self):
old_lines = split_lines(self._module_node.get_code(), keepends=True) old_lines = split_lines(self._module_node.get_code(), keepends=True)
new_lines = split_lines(self.get_new_code(), keepends=True) new_lines = split_lines(self.get_new_code(), keepends=True)
# Add a newline at the end if it's missing. Otherwise the diff will be
# very weird. A `diff -u file1 file2` would show the string:
#
# \ No newline at end of file
#
# This is not necessary IMO, because Jedi does not really play with
# newlines and the ending newline does not really matter in Python
# files. ~dave
if old_lines[-1] != '':
old_lines[-1] += '\n'
if new_lines[-1] != '':
new_lines[-1] += '\n'
project_path = self._inference_state.project._path project_path = self._inference_state.project._path
if self._from_path is None:
from_p = ''
else:
from_p = relpath(self._from_path, project_path)
if self._to_path is None:
to_p = ''
else:
to_p = relpath(self._to_path, project_path)
diff = difflib.unified_diff( diff = difflib.unified_diff(
old_lines, new_lines, old_lines, new_lines,
fromfile=relpath(self._from_path, project_path), fromfile=from_p,
tofile=relpath(self._to_path, project_path), tofile=to_p,
) )
# Apparently there's a space at the end of the diff - for whatever # Apparently there's a space at the end of the diff - for whatever
# reason. # reason.
@ -151,6 +173,8 @@ def inline(inference_state, names):
raise RefactoringError("No definition found to inline") raise RefactoringError("No definition found to inline")
if len(definitions) > 1: if len(definitions) > 1:
raise RefactoringError("Cannot inline a name with multiple definitions") raise RefactoringError("Cannot inline a name with multiple definitions")
if len(names) == 1:
raise RefactoringError("There are no references to this name")
tree_name = definitions[0].tree_name tree_name = definitions[0].tree_name

View File

@ -5,11 +5,10 @@ from parso import split_lines
from jedi import debug from jedi import debug
from jedi.api.exceptions import RefactoringError from jedi.api.exceptions import RefactoringError
from jedi.api.refactoring import Refactoring, EXPRESSION_PARTS from jedi.api.refactoring import Refactoring, EXPRESSION_PARTS
from jedi.common.utils import indent_block from jedi.common import indent_block
from jedi.parser_utils import function_is_classmethod, function_is_staticmethod from jedi.parser_utils import function_is_classmethod, function_is_staticmethod
_EXTRACT_USE_PARENT = EXPRESSION_PARTS + ['trailer']
_DEFINITION_SCOPES = ('suite', 'file_input') _DEFINITION_SCOPES = ('suite', 'file_input')
_VARIABLE_EXCTRACTABLE = EXPRESSION_PARTS + \ _VARIABLE_EXCTRACTABLE = EXPRESSION_PARTS + \
('atom testlist_star_expr testlist test lambdef lambdef_nocond ' ('atom testlist_star_expr testlist test lambdef lambdef_nocond '
@ -57,7 +56,9 @@ def _find_nodes(module_node, pos, until_pos):
if _is_not_extractable_syntax(start_node): if _is_not_extractable_syntax(start_node):
start_node = start_node.parent start_node = start_node.parent
while start_node.parent.type in _EXTRACT_USE_PARENT: if start_node.parent.type == 'trailer':
start_node = start_node.parent.parent
while start_node.parent.type in EXPRESSION_PARTS:
start_node = start_node.parent start_node = start_node.parent
nodes = [start_node] nodes = [start_node]

View File

@ -1 +0,0 @@
from jedi.common.value import BaseValueSet, BaseValue

View File

@ -1,36 +0,0 @@
import os
from contextlib import contextmanager
def traverse_parents(path, include_current=False):
if not include_current:
path = os.path.dirname(path)
previous = None
while previous != path:
yield path
previous = path
path = os.path.dirname(path)
@contextmanager
def monkeypatch(obj, attribute_name, new_value):
"""
Like pytest's monkeypatch, but as a value manager.
"""
old_value = getattr(obj, attribute_name)
try:
setattr(obj, attribute_name, new_value)
yield
finally:
setattr(obj, attribute_name, old_value)
def indent_block(text, indention=' '):
"""This function indents a text block with a default of four spaces."""
temp = ''
while text and text[-1] == '\n':
temp += text[-1]
text = text[:-1]
lines = text.split('\n')
return '\n'.join(map(lambda s: indention + s, lines)) + temp

View File

@ -1,113 +0,0 @@
class BaseValue(object):
def __init__(self, inference_state, parent_context=None):
self.inference_state = inference_state
self.parent_context = parent_context
def get_root_context(self):
value = self
while True:
if value.parent_context is None:
return value
value = value.parent_context
def infer_type_vars(self, value_set, is_class_value=False):
"""
When the current instance represents a type annotation, this method
tries to find information about undefined type vars and returns a dict
from type var name to value set.
This is for example important to understand what `iter([1])` returns.
According to typeshed, `iter` returns an `Iterator[_T]`:
def iter(iterable: Iterable[_T]) -> Iterator[_T]: ...
This functions would generate `int` for `_T` in this case, because it
unpacks the `Iterable`.
Parameters
----------
`self`: represents the annotation of the current parameter to infer the
value for. In the above example, this would initially be the
`Iterable[_T]` of the `iterable` parameter and then, when recursing,
just the `_T` generic parameter.
`value_set`: represents the actual argument passed to the parameter
we're inferrined for, or (for recursive calls) their types. In the
above example this would first be the representation of the list
`[1]` and then, when recursing, just of `1`.
`is_class_value`: tells us whether or not to treat the `value_set` as
representing the instances or types being passed, which is neccesary
to correctly cope with `Type[T]` annotations. When it is True, this
means that we are being called with a nested portion of an
annotation and that the `value_set` represents the types of the
arguments, rather than their actual instances. Note: not all
recursive calls will neccesarily set this to True.
"""
return {}
class BaseValueSet(object):
def __init__(self, iterable):
self._set = frozenset(iterable)
for value in iterable:
assert not isinstance(value, BaseValueSet)
@classmethod
def _from_frozen_set(cls, frozenset_):
self = cls.__new__(cls)
self._set = frozenset_
return self
@classmethod
def from_sets(cls, sets):
"""
Used to work with an iterable of set.
"""
aggregated = set()
for set_ in sets:
if isinstance(set_, BaseValueSet):
aggregated |= set_._set
else:
aggregated |= frozenset(set_)
return cls._from_frozen_set(frozenset(aggregated))
def __or__(self, other):
return self._from_frozen_set(self._set | other._set)
def __and__(self, other):
return self._from_frozen_set(self._set & other._set)
def __iter__(self):
for element in self._set:
yield element
def __bool__(self):
return bool(self._set)
def __len__(self):
return len(self._set)
def __repr__(self):
return 'S{%s}' % (', '.join(str(s) for s in self._set))
def filter(self, filter_func):
return self.__class__(filter(filter_func, self._set))
def __getattr__(self, name):
def mapper(*args, **kwargs):
return self.from_sets(
getattr(value, name)(*args, **kwargs)
for value in self._set
)
return mapper
def __eq__(self, other):
return self._set == other._set
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash(self._set)

View File

@ -84,17 +84,17 @@ def increase_indent(func):
@contextmanager @contextmanager
def increase_indent_cm(title=None): def increase_indent_cm(title=None, color='MAGENTA'):
global _debug_indent global _debug_indent
if title: if title:
dbg('Start: ' + title, color='MAGENTA') dbg('Start: ' + title, color=color)
_debug_indent += 1 _debug_indent += 1
try: try:
yield yield
finally: finally:
_debug_indent -= 1 _debug_indent -= 1
if title: if title:
dbg('End: ' + title, color='MAGENTA') dbg('End: ' + title, color=color)
def dbg(message, *args, **kwargs): def dbg(message, *args, **kwargs):

View File

@ -35,7 +35,7 @@ class ParamIssue(Exception):
pass pass
def repack_with_argument_clinic(string, keep_arguments_param=False, keep_callback_param=False): def repack_with_argument_clinic(clinic_string):
""" """
Transforms a function or method with arguments to the signature that is Transforms a function or method with arguments to the signature that is
given as an argument clinic notation. given as an argument clinic notation.
@ -46,35 +46,29 @@ def repack_with_argument_clinic(string, keep_arguments_param=False, keep_callbac
str.split.__text_signature__ str.split.__text_signature__
# Results in: '($self, /, sep=None, maxsplit=-1)' # Results in: '($self, /, sep=None, maxsplit=-1)'
""" """
clinic_args = list(_parse_argument_clinic(string))
def decorator(func): def decorator(func):
def wrapper(context, *args, **kwargs): def wrapper(value, arguments):
if keep_arguments_param:
arguments = kwargs['arguments']
else:
arguments = kwargs.pop('arguments')
if not keep_arguments_param:
kwargs.pop('callback', None)
try: try:
args += tuple(_iterate_argument_clinic( args = tuple(iterate_argument_clinic(
context.inference_state, value.inference_state,
arguments, arguments,
clinic_args clinic_string,
)) ))
except ParamIssue: except ParamIssue:
return NO_VALUES return NO_VALUES
else: else:
return func(context, *args, **kwargs) return func(value, *args)
return wrapper return wrapper
return decorator return decorator
def _iterate_argument_clinic(inference_state, arguments, parameters): def iterate_argument_clinic(inference_state, arguments, clinic_string):
"""Uses a list with argument clinic information (see PEP 436).""" """Uses a list with argument clinic information (see PEP 436)."""
clinic_args = list(_parse_argument_clinic(clinic_string))
iterator = PushBackIterator(arguments.unpack()) iterator = PushBackIterator(arguments.unpack())
for i, (name, optional, allow_kwargs, stars) in enumerate(parameters): for i, (name, optional, allow_kwargs, stars) in enumerate(clinic_args):
if stars == 1: if stars == 1:
lazy_values = [] lazy_values = []
for key, argument in iterator: for key, argument in iterator:
@ -94,7 +88,7 @@ def _iterate_argument_clinic(inference_state, arguments, parameters):
raise ParamIssue raise ParamIssue
if argument is None and not optional: if argument is None and not optional:
debug.warning('TypeError: %s expected at least %s arguments, got %s', debug.warning('TypeError: %s expected at least %s arguments, got %s',
name, len(parameters), i) name, len(clinic_args), i)
raise ParamIssue raise ParamIssue
value_set = NO_VALUES if argument is None else argument.infer() value_set = NO_VALUES if argument is None else argument.infer()

View File

@ -13,7 +13,6 @@ from parso.python.tree import Name
from jedi import debug from jedi import debug
from jedi._compatibility import zip_longest, unicode from jedi._compatibility import zip_longest, unicode
from jedi.parser_utils import clean_scope_docstring from jedi.parser_utils import clean_scope_docstring
from jedi.common import BaseValueSet, BaseValue
from jedi.inference.helpers import SimpleGetItemNotFound from jedi.inference.helpers import SimpleGetItemNotFound
from jedi.inference.utils import safe_property from jedi.inference.utils import safe_property
from jedi.inference.cache import inference_state_as_method_param_cache from jedi.inference.cache import inference_state_as_method_param_cache
@ -33,11 +32,6 @@ class HelperValueMixin(object):
return value return value
value = value.parent_context value = value.parent_context
@classmethod
@inference_state_as_method_param_cache()
def create_cached(cls, *args, **kwargs):
return cls(*args, **kwargs)
def execute(self, arguments): def execute(self, arguments):
return self.inference_state.execute(self, arguments=arguments) return self.inference_state.execute(self, arguments=arguments)
@ -120,10 +114,14 @@ class HelperValueMixin(object):
return self.py__iter__(contextualized_node) return self.py__iter__(contextualized_node)
def is_sub_class_of(self, class_value): def is_sub_class_of(self, class_value):
for cls in self.py__mro__(): with debug.increase_indent_cm('subclass matching of %s <=> %s' % (self, class_value),
if cls.is_same_class(class_value): color='BLUE'):
return True for cls in self.py__mro__():
return False if cls.is_same_class(class_value):
debug.dbg('matched subclass True', color='BLUE')
return True
debug.dbg('matched subclass False', color='BLUE')
return False
def is_same_class(self, class2): def is_same_class(self, class2):
# Class matching should prefer comparisons that are not this function. # Class matching should prefer comparisons that are not this function.
@ -136,7 +134,7 @@ class HelperValueMixin(object):
return self._as_context(*args, **kwargs) return self._as_context(*args, **kwargs)
class Value(HelperValueMixin, BaseValue): class Value(HelperValueMixin):
""" """
To be implemented by subclasses. To be implemented by subclasses.
""" """
@ -144,12 +142,11 @@ class Value(HelperValueMixin, BaseValue):
# Possible values: None, tuple, list, dict and set. Here to deal with these # Possible values: None, tuple, list, dict and set. Here to deal with these
# very important containers. # very important containers.
array_type = None array_type = None
api_type = 'not_defined_please_report_bug'
@property def __init__(self, inference_state, parent_context=None):
def api_type(self): self.inference_state = inference_state
# By default just lower name of the class. Can and should be self.parent_context = parent_context
# overwritten.
return self.__class__.__name__.lower()
def py__getitem__(self, index_value_set, contextualized_node): def py__getitem__(self, index_value_set, contextualized_node):
from jedi.inference import analysis from jedi.inference import analysis
@ -181,6 +178,9 @@ class Value(HelperValueMixin, BaseValue):
def is_class(self): def is_class(self):
return False return False
def is_class_mixin(self):
return False
def is_instance(self): def is_instance(self):
return False return False
@ -244,6 +244,9 @@ class Value(HelperValueMixin, BaseValue):
debug.warning("No __get__ defined on %s", self) debug.warning("No __get__ defined on %s", self)
return ValueSet([self]) return ValueSet([self])
def py__get__on_class(self, calling_instance, instance, class_value):
return NotImplemented
def get_qualified_names(self): def get_qualified_names(self):
# Returns Optional[Tuple[str, ...]] # Returns Optional[Tuple[str, ...]]
return None return None
@ -265,6 +268,35 @@ class Value(HelperValueMixin, BaseValue):
def get_type_hint(self, add_class_info=True): def get_type_hint(self, add_class_info=True):
return None return None
def infer_type_vars(self, value_set):
"""
When the current instance represents a type annotation, this method
tries to find information about undefined type vars and returns a dict
from type var name to value set.
This is for example important to understand what `iter([1])` returns.
According to typeshed, `iter` returns an `Iterator[_T]`:
def iter(iterable: Iterable[_T]) -> Iterator[_T]: ...
This functions would generate `int` for `_T` in this case, because it
unpacks the `Iterable`.
Parameters
----------
`self`: represents the annotation of the current parameter to infer the
value for. In the above example, this would initially be the
`Iterable[_T]` of the `iterable` parameter and then, when recursing,
just the `_T` generic parameter.
`value_set`: represents the actual argument passed to the parameter
we're inferrined for, or (for recursive calls) their types. In the
above example this would first be the representation of the list
`[1]` and then, when recursing, just of `1`.
"""
return {}
def iterate_values(values, contextualized_node=None, is_async=False): def iterate_values(values, contextualized_node=None, is_async=False):
""" """
@ -371,7 +403,70 @@ def _getitem(value, index_values, contextualized_node):
return result return result
class ValueSet(BaseValueSet): class ValueSet(object):
def __init__(self, iterable):
self._set = frozenset(iterable)
for value in iterable:
assert not isinstance(value, ValueSet)
@classmethod
def _from_frozen_set(cls, frozenset_):
self = cls.__new__(cls)
self._set = frozenset_
return self
@classmethod
def from_sets(cls, sets):
"""
Used to work with an iterable of set.
"""
aggregated = set()
for set_ in sets:
if isinstance(set_, ValueSet):
aggregated |= set_._set
else:
aggregated |= frozenset(set_)
return cls._from_frozen_set(frozenset(aggregated))
def __or__(self, other):
return self._from_frozen_set(self._set | other._set)
def __and__(self, other):
return self._from_frozen_set(self._set & other._set)
def __iter__(self):
for element in self._set:
yield element
def __bool__(self):
return bool(self._set)
def __len__(self):
return len(self._set)
def __repr__(self):
return 'S{%s}' % (', '.join(str(s) for s in self._set))
def filter(self, filter_func):
return self.__class__(filter(filter_func, self._set))
def __getattr__(self, name):
def mapper(*args, **kwargs):
return self.from_sets(
getattr(value, name)(*args, **kwargs)
for value in self._set
)
return mapper
def __eq__(self, other):
return self._set == other._set
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash(self._set)
def py__class__(self): def py__class__(self):
return ValueSet(c.py__class__() for c in self._set) return ValueSet(c.py__class__() for c in self._set)
@ -435,7 +530,7 @@ class ValueSet(BaseValueSet):
s = 'Optional[%s]' % s s = 'Optional[%s]' % s
return s return s
def infer_type_vars(self, value_set, is_class_value=False): def infer_type_vars(self, value_set):
# Circular # Circular
from jedi.inference.gradual.annotation import merge_type_var_dicts from jedi.inference.gradual.annotation import merge_type_var_dicts
@ -443,7 +538,7 @@ class ValueSet(BaseValueSet):
for value in self._set: for value in self._set:
merge_type_var_dicts( merge_type_var_dicts(
type_var_dict, type_var_dict,
value.infer_type_vars(value_set, is_class_value), value.infer_type_vars(value_set),
) )
return type_var_dict return type_var_dict

View File

@ -3,6 +3,7 @@
default otherwise. default otherwise.
- ``CachedMetaClass`` uses ``_memoize_default`` to do the same with classes. - ``CachedMetaClass`` uses ``_memoize_default`` to do the same with classes.
""" """
from functools import wraps
from jedi import debug from jedi import debug
@ -86,6 +87,7 @@ def inference_state_method_generator_cache():
recursion errors and returns no further iterator elemends in that case. recursion errors and returns no further iterator elemends in that case.
""" """
def func(function): def func(function):
@wraps(function)
def wrapper(obj, *args, **kwargs): def wrapper(obj, *args, **kwargs):
cache = obj.inference_state.memoize_cache cache = obj.inference_state.memoize_cache
try: try:

View File

@ -485,9 +485,9 @@ class DirectObjectAccess(object):
return inspect.isclass(self._obj) and self._obj != type return inspect.isclass(self._obj) and self._obj != type
def _annotation_to_str(self, annotation): def _annotation_to_str(self, annotation):
if isinstance(annotation, type): if py_version < 30:
return str(annotation.__name__) return ''
return str(annotation) return inspect.formatannotation(annotation)
def get_signature_params(self): def get_signature_params(self):
return [ return [

View File

@ -181,6 +181,15 @@ class CompiledSubprocess(object):
os.path.dirname(os.path.dirname(parso_path)), os.path.dirname(os.path.dirname(parso_path)),
'.'.join(str(x) for x in sys.version_info[:3]), '.'.join(str(x) for x in sys.version_info[:3]),
) )
# Use explicit envionment to ensure reliable results (#1540)
env = {}
if os.name == 'nt':
# if SYSTEMROOT (or case variant) exists in environment,
# ensure it goes to subprocess
for k, v in os.environ.items():
if 'SYSTEMROOT' == k.upper():
env.update({k: os.environ[k]})
break # don't risk multiple entries
process = GeneralizedPopen( process = GeneralizedPopen(
args, args,
stdin=subprocess.PIPE, stdin=subprocess.PIPE,
@ -188,7 +197,8 @@ class CompiledSubprocess(object):
stderr=subprocess.PIPE, stderr=subprocess.PIPE,
# Use system default buffering on Python 2 to improve performance # Use system default buffering on Python 2 to improve performance
# (this is already the case on Python 3). # (this is already the case on Python 3).
bufsize=-1 bufsize=-1,
env=env
) )
self._stderr_queue = Queue() self._stderr_queue = Queue()
self._stderr_thread = t = Thread( self._stderr_thread = t = Thread(

View File

@ -23,7 +23,7 @@ from parso import parse, ParserSyntaxError
from jedi._compatibility import u from jedi._compatibility import u
from jedi import debug from jedi import debug
from jedi.common.utils import indent_block from jedi.common import indent_block
from jedi.inference.cache import inference_state_method_cache from jedi.inference.cache import inference_state_method_cache
from jedi.inference.base_value import iterator_to_value_set, ValueSet, \ from jedi.inference.base_value import iterator_to_value_set, ValueSet, \
NO_VALUES NO_VALUES

View File

@ -255,7 +255,7 @@ class _BuiltinMappedMethod(ValueWrapper):
def py__call__(self, arguments): def py__call__(self, arguments):
# TODO add TypeError if params are given/or not correct. # TODO add TypeError if params are given/or not correct.
return self._method(self._value) return self._method(self._value, arguments)
class SpecialMethodFilter(DictFilter): class SpecialMethodFilter(DictFilter):
@ -330,7 +330,7 @@ class _AttributeOverwriteMixin(object):
def get_filters(self, *args, **kwargs): def get_filters(self, *args, **kwargs):
yield SpecialMethodFilter(self, self.overwritten_methods, self._wrapped_value) yield SpecialMethodFilter(self, self.overwritten_methods, self._wrapped_value)
for filter in self._wrapped_value.get_filters(): for filter in self._wrapped_value.get_filters(*args, **kwargs):
yield filter yield filter

View File

@ -12,7 +12,7 @@ from parso import ParserSyntaxError, parse
from jedi._compatibility import force_unicode, Parameter from jedi._compatibility import force_unicode, Parameter
from jedi.inference.cache import inference_state_method_cache from jedi.inference.cache import inference_state_method_cache
from jedi.inference.base_value import ValueSet, NO_VALUES from jedi.inference.base_value import ValueSet, NO_VALUES
from jedi.inference.gradual.base import DefineGenericBase, GenericClass from jedi.inference.gradual.base import DefineGenericBaseClass, GenericClass
from jedi.inference.gradual.generics import TupleGenericManager from jedi.inference.gradual.generics import TupleGenericManager
from jedi.inference.gradual.type_var import TypeVar from jedi.inference.gradual.type_var import TypeVar
from jedi.inference.helpers import is_string from jedi.inference.helpers import is_string
@ -229,7 +229,7 @@ def infer_return_types(function, arguments):
return ValueSet.from_sets( return ValueSet.from_sets(
ann.define_generics(type_var_dict) ann.define_generics(type_var_dict)
if isinstance(ann, (DefineGenericBase, TypeVar)) else ValueSet({ann}) if isinstance(ann, (DefineGenericBaseClass, TypeVar)) else ValueSet({ann})
for ann in annotation_values for ann in annotation_values
).execute_annotation() ).execute_annotation()
@ -276,17 +276,17 @@ def infer_return_for_callable(arguments, param_values, result_values):
all_type_vars = {} all_type_vars = {}
for pv in param_values: for pv in param_values:
if pv.array_type == 'list': if pv.array_type == 'list':
type_var_dict = infer_type_vars_for_callable(arguments, pv.py__iter__()) type_var_dict = _infer_type_vars_for_callable(arguments, pv.py__iter__())
all_type_vars.update(type_var_dict) all_type_vars.update(type_var_dict)
return ValueSet.from_sets( return ValueSet.from_sets(
v.define_generics(all_type_vars) v.define_generics(all_type_vars)
if isinstance(v, (DefineGenericBase, TypeVar)) else ValueSet({v}) if isinstance(v, (DefineGenericBaseClass, TypeVar)) else ValueSet({v})
for v in result_values for v in result_values
).execute_annotation() ).execute_annotation()
def infer_type_vars_for_callable(arguments, lazy_params): def _infer_type_vars_for_callable(arguments, lazy_params):
""" """
Infers type vars for the Calllable class: Infers type vars for the Calllable class:
@ -350,7 +350,7 @@ def merge_pairwise_generics(annotation_value, annotated_argument_class):
type_var_dict = {} type_var_dict = {}
if not isinstance(annotated_argument_class, DefineGenericBase): if not isinstance(annotated_argument_class, DefineGenericBaseClass):
return type_var_dict return type_var_dict
annotation_generics = annotation_value.get_generics() annotation_generics = annotation_value.get_generics()
@ -359,12 +359,7 @@ def merge_pairwise_generics(annotation_value, annotated_argument_class):
for annotation_generics_set, actual_generic_set in zip(annotation_generics, actual_generics): for annotation_generics_set, actual_generic_set in zip(annotation_generics, actual_generics):
merge_type_var_dicts( merge_type_var_dicts(
type_var_dict, type_var_dict,
annotation_generics_set.infer_type_vars( annotation_generics_set.infer_type_vars(actual_generic_set.execute_annotation()),
actual_generic_set,
# This is a note to ourselves that we have already
# converted the instance representation to its class.
is_class_value=True,
),
) )
return type_var_dict return type_var_dict

View File

@ -23,8 +23,8 @@ class _BoundTypeVarName(AbstractNameDefinition):
def iter_(): def iter_():
for value in self._value_set: for value in self._value_set:
# Replace any with the constraints if they are there. # Replace any with the constraints if they are there.
from jedi.inference.gradual.typing import Any from jedi.inference.gradual.typing import AnyClass
if isinstance(value, Any): if isinstance(value, AnyClass):
for constraint in self._type_var.constraints: for constraint in self._type_var.constraints:
yield constraint yield constraint
else: else:
@ -81,7 +81,7 @@ class _AnnotatedClassContext(ClassContext):
yield self._value.get_type_var_filter() yield self._value.get_type_var_filter()
class DefineGenericBase(LazyValueWrapper): class DefineGenericBaseClass(LazyValueWrapper):
def __init__(self, generics_manager): def __init__(self, generics_manager):
self._generics_manager = generics_manager self._generics_manager = generics_manager
@ -99,7 +99,7 @@ class DefineGenericBase(LazyValueWrapper):
for generic_set in self.get_generics(): for generic_set in self.get_generics():
values = NO_VALUES values = NO_VALUES
for generic in generic_set: for generic in generic_set:
if isinstance(generic, (GenericClass, TypeVar)): if isinstance(generic, (DefineGenericBaseClass, TypeVar)):
result = generic.define_generics(type_var_dict) result = generic.define_generics(type_var_dict)
values |= result values |= result
if result != ValueSet({generic}): if result != ValueSet({generic}):
@ -119,7 +119,7 @@ class DefineGenericBase(LazyValueWrapper):
)]) )])
def is_same_class(self, other): def is_same_class(self, other):
if not isinstance(other, DefineGenericBase): if not isinstance(other, DefineGenericBaseClass):
return False return False
if self.tree_node != other.tree_node: if self.tree_node != other.tree_node:
@ -138,8 +138,13 @@ class DefineGenericBase(LazyValueWrapper):
any( any(
# TODO why is this ordering the correct one? # TODO why is this ordering the correct one?
cls2.is_same_class(cls1) cls2.is_same_class(cls1)
for cls1 in class_set1 # TODO I'm still not sure gather_annotation_classes is a good
for cls2 in class_set2 # idea. They are essentially here to avoid comparing Tuple <=>
# tuple and instead compare tuple <=> tuple, but at the moment
# the whole `is_same_class` and `is_sub_class` matching is just
# not in the best shape.
for cls1 in class_set1.gather_annotation_classes()
for cls2 in class_set2.gather_annotation_classes()
) for class_set1, class_set2 in zip(given_params1, given_params2) ) for class_set1, class_set2 in zip(given_params1, given_params2)
) )
@ -151,7 +156,7 @@ class DefineGenericBase(LazyValueWrapper):
) )
class GenericClass(ClassMixin, DefineGenericBase): class GenericClass(DefineGenericBaseClass, ClassMixin):
""" """
A class that is defined with generics, might be something simple like: A class that is defined with generics, might be something simple like:
@ -190,7 +195,7 @@ class GenericClass(ClassMixin, DefineGenericBase):
@to_list @to_list
def py__bases__(self): def py__bases__(self):
for base in self._wrapped_value.py__bases__(): for base in self._wrapped_value.py__bases__():
yield _LazyGenericBaseClass(self, base) yield _LazyGenericBaseClass(self, base, self._generics_manager)
def _create_instance_with_generics(self, generics_manager): def _create_instance_with_generics(self, generics_manager):
return GenericClass(self._class_value, generics_manager) return GenericClass(self._class_value, generics_manager)
@ -200,29 +205,30 @@ class GenericClass(ClassMixin, DefineGenericBase):
return True return True
return self._class_value.is_sub_class_of(class_value) return self._class_value.is_sub_class_of(class_value)
def infer_type_vars(self, value_set, is_class_value=False): def with_generics(self, generics_tuple):
return self._class_value.with_generics(generics_tuple)
def infer_type_vars(self, value_set):
# Circular # Circular
from jedi.inference.gradual.annotation import merge_pairwise_generics, merge_type_var_dicts from jedi.inference.gradual.annotation import merge_pairwise_generics, merge_type_var_dicts
annotation_name = self.py__name__() annotation_name = self.py__name__()
type_var_dict = {} type_var_dict = {}
if annotation_name == 'Iterable' and not is_class_value: if annotation_name == 'Iterable':
annotation_generics = self.get_generics() annotation_generics = self.get_generics()
if annotation_generics: if annotation_generics:
return annotation_generics[0].infer_type_vars( return annotation_generics[0].infer_type_vars(
value_set.merge_types_of_iterate(), value_set.merge_types_of_iterate(),
) )
else: else:
# Note: we need to handle the MRO _in order_, so we need to extract # Note: we need to handle the MRO _in order_, so we need to extract
# the elements from the set first, then handle them, even if we put # the elements from the set first, then handle them, even if we put
# them back in a set afterwards. # them back in a set afterwards.
for py_class in value_set: for py_class in value_set:
if not is_class_value: if py_class.is_instance() and not py_class.is_compiled():
if py_class.is_instance() and not py_class.is_compiled(): py_class = py_class.get_annotated_class_object()
py_class = py_class.get_annotated_class_object() else:
else: continue
continue
if py_class.api_type != u'class': if py_class.api_type != u'class':
# Functions & modules don't have an MRO and we're not # Functions & modules don't have an MRO and we're not
@ -243,9 +249,10 @@ class GenericClass(ClassMixin, DefineGenericBase):
class _LazyGenericBaseClass(object): class _LazyGenericBaseClass(object):
def __init__(self, class_value, lazy_base_class): def __init__(self, class_value, lazy_base_class, generics_manager):
self._class_value = class_value self._class_value = class_value
self._lazy_base_class = lazy_base_class self._lazy_base_class = lazy_base_class
self._generics_manager = generics_manager
@iterator_to_value_set @iterator_to_value_set
def infer(self): def infer(self):
@ -258,7 +265,17 @@ class _LazyGenericBaseClass(object):
TupleGenericManager(tuple(self._remap_type_vars(base))), TupleGenericManager(tuple(self._remap_type_vars(base))),
) )
else: else:
yield base if base.is_class_mixin():
# This case basically allows classes like `class Foo(List)`
# to be used like `Foo[int]`. The generics are not
# necessary and can be used later.
yield GenericClass.create_cached(
base.inference_state,
base,
self._generics_manager,
)
else:
yield base
def _remap_type_vars(self, base): def _remap_type_vars(self, base):
from jedi.inference.gradual.type_var import TypeVar from jedi.inference.gradual.type_var import TypeVar
@ -278,6 +295,9 @@ class _LazyGenericBaseClass(object):
new |= ValueSet([type_var]) new |= ValueSet([type_var])
yield new yield new
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self._lazy_base_class)
class _GenericInstanceWrapper(ValueWrapper): class _GenericInstanceWrapper(ValueWrapper):
def py__stop_iteration_returns(self): def py__stop_iteration_returns(self):
@ -306,6 +326,8 @@ class _PseudoTreeNameClass(Value):
this class. Essentially this class makes it possible to goto that `Tuple` this class. Essentially this class makes it possible to goto that `Tuple`
name, without affecting anything else negatively. name, without affecting anything else negatively.
""" """
api_type = u'class'
def __init__(self, parent_context, tree_name): def __init__(self, parent_context, tree_name):
super(_PseudoTreeNameClass, self).__init__( super(_PseudoTreeNameClass, self).__init__(
parent_context.inference_state, parent_context.inference_state,
@ -332,10 +354,9 @@ class _PseudoTreeNameClass(Value):
yield EmptyFilter() yield EmptyFilter()
def py__class__(self): def py__class__(self):
# TODO this is obviously not correct, but at least gives us a class if # This might not be 100% correct, but it is good enough. The details of
# we have none. Some of these objects don't really have a base class in # the typing library are not really an issue for Jedi.
# typeshed. return builtin_from_name(self.inference_state, u'type')
return builtin_from_name(self.inference_state, u'object')
@property @property
def name(self): def name(self):
@ -365,9 +386,9 @@ class BaseTypingValue(LazyValueWrapper):
return '%s(%s)' % (self.__class__.__name__, self._tree_name.value) return '%s(%s)' % (self.__class__.__name__, self._tree_name.value)
class BaseTypingValueWithGenerics(DefineGenericBase): class BaseTypingClassWithGenerics(DefineGenericBaseClass):
def __init__(self, parent_context, tree_name, generics_manager): def __init__(self, parent_context, tree_name, generics_manager):
super(BaseTypingValueWithGenerics, self).__init__(generics_manager) super(BaseTypingClassWithGenerics, self).__init__(generics_manager)
self.inference_state = parent_context.inference_state self.inference_state = parent_context.inference_state
self.parent_context = parent_context self.parent_context = parent_context
self._tree_name = tree_name self._tree_name = tree_name
@ -378,3 +399,29 @@ class BaseTypingValueWithGenerics(DefineGenericBase):
def __repr__(self): def __repr__(self):
return '%s(%s%s)' % (self.__class__.__name__, self._tree_name.value, return '%s(%s%s)' % (self.__class__.__name__, self._tree_name.value,
self._generics_manager) self._generics_manager)
class BaseTypingInstance(LazyValueWrapper):
def __init__(self, parent_context, class_value, tree_name, generics_manager):
self.inference_state = class_value.inference_state
self.parent_context = parent_context
self._class_value = class_value
self._tree_name = tree_name
self._generics_manager = generics_manager
def py__class__(self):
return self._class_value
def get_annotated_class_object(self):
return self._class_value
@property
def name(self):
return ValueName(self, self._tree_name)
def _get_wrapped_value(self):
object_, = builtin_from_name(self.inference_state, u'object').execute_annotation()
return object_
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self._generics_manager)

View File

@ -1,6 +1,6 @@
from jedi._compatibility import unicode, force_unicode from jedi._compatibility import unicode, force_unicode
from jedi import debug from jedi import debug
from jedi.inference.base_value import ValueSet, NO_VALUES from jedi.inference.base_value import ValueSet, NO_VALUES, ValueWrapper
from jedi.inference.gradual.base import BaseTypingValue from jedi.inference.gradual.base import BaseTypingValue
@ -107,11 +107,25 @@ class TypeVar(BaseTypingValue):
def execute_annotation(self): def execute_annotation(self):
return self._get_classes().execute_annotation() return self._get_classes().execute_annotation()
def infer_type_vars(self, value_set, is_class_value=False): def infer_type_vars(self, value_set):
def iterate():
for v in value_set:
cls = v.py__class__()
if v.is_function() or v.is_class():
cls = TypeWrapper(cls, v)
yield cls
annotation_name = self.py__name__() annotation_name = self.py__name__()
if not is_class_value: return {annotation_name: ValueSet(iterate())}
return {annotation_name: value_set.py__class__()}
return {annotation_name: value_set}
def __repr__(self): def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self.py__name__()) return '<%s: %s>' % (self.__class__.__name__, self.py__name__())
class TypeWrapper(ValueWrapper):
def __init__(self, wrapped_value, original_value):
super(TypeWrapper, self).__init__(wrapped_value)
self._original_value = original_value
def execute_annotation(self):
return ValueSet({self._original_value})

View File

@ -12,6 +12,8 @@ from jedi.inference.value import ModuleValue
_jedi_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) _jedi_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
TYPESHED_PATH = os.path.join(_jedi_path, 'third_party', 'typeshed') TYPESHED_PATH = os.path.join(_jedi_path, 'third_party', 'typeshed')
DJANGO_INIT_PATH = os.path.join(_jedi_path, 'third_party', 'django-stubs',
'django-stubs', '__init__.pyi')
_IMPORT_MAP = dict( _IMPORT_MAP = dict(
_collections='collections', _collections='collections',
@ -173,6 +175,13 @@ def _try_to_load_stub(inference_state, import_names, python_value_set,
) )
if m is not None: if m is not None:
return m return m
if import_names[0] == 'django':
return _try_to_load_stub_from_file(
inference_state,
python_value_set,
file_io=FileIO(DJANGO_INIT_PATH),
import_names=import_names,
)
# 2. Try to load pyi files next to py files. # 2. Try to load pyi files next to py files.
for c in python_value_set: for c in python_value_set:

View File

@ -17,7 +17,8 @@ from jedi.inference.arguments import repack_with_argument_clinic
from jedi.inference.filters import FilterWrapper from jedi.inference.filters import FilterWrapper
from jedi.inference.names import NameWrapper, ValueName from jedi.inference.names import NameWrapper, ValueName
from jedi.inference.value.klass import ClassMixin from jedi.inference.value.klass import ClassMixin
from jedi.inference.gradual.base import BaseTypingValue, BaseTypingValueWithGenerics from jedi.inference.gradual.base import BaseTypingValue, \
BaseTypingClassWithGenerics, BaseTypingInstance
from jedi.inference.gradual.type_var import TypeVarClass from jedi.inference.gradual.type_var import TypeVarClass
from jedi.inference.gradual.generics import LazyGenericManager, TupleGenericManager from jedi.inference.gradual.generics import LazyGenericManager, TupleGenericManager
@ -66,7 +67,7 @@ class TypingModuleName(NameWrapper):
yield TypeVarClass.create_cached( yield TypeVarClass.create_cached(
inference_state, self.parent_context, self.tree_name) inference_state, self.parent_context, self.tree_name)
elif name == 'Any': elif name == 'Any':
yield Any.create_cached( yield AnyClass.create_cached(
inference_state, self.parent_context, self.tree_name) inference_state, self.parent_context, self.tree_name)
elif name == 'TYPE_CHECKING': elif name == 'TYPE_CHECKING':
# This is needed for e.g. imports that are only available for type # This is needed for e.g. imports that are only available for type
@ -84,7 +85,7 @@ class TypingModuleName(NameWrapper):
elif name == 'TypedDict': elif name == 'TypedDict':
# TODO doesn't even exist in typeshed/typing.py, yet. But will be # TODO doesn't even exist in typeshed/typing.py, yet. But will be
# added soon. # added soon.
yield TypedDictBase.create_cached( yield TypedDictClass.create_cached(
inference_state, self.parent_context, self.tree_name) inference_state, self.parent_context, self.tree_name)
elif name in ('no_type_check', 'no_type_check_decorator'): elif name in ('no_type_check', 'no_type_check_decorator'):
# This is not necessary, as long as we are not doing type checking. # This is not necessary, as long as we are not doing type checking.
@ -100,7 +101,7 @@ class TypingModuleFilterWrapper(FilterWrapper):
name_wrapper_class = TypingModuleName name_wrapper_class = TypingModuleName
class TypingValueWithIndex(BaseTypingValueWithGenerics): class ProxyWithGenerics(BaseTypingClassWithGenerics):
def execute_annotation(self): def execute_annotation(self):
string_name = self._tree_name.value string_name = self._tree_name.value
@ -129,6 +130,7 @@ class TypingValueWithIndex(BaseTypingValueWithGenerics):
cls = mapped[string_name] cls = mapped[string_name]
return ValueSet([cls( return ValueSet([cls(
self.parent_context, self.parent_context,
self,
self._tree_name, self._tree_name,
generics_manager=self._generics_manager, generics_manager=self._generics_manager,
)]) )])
@ -137,15 +139,33 @@ class TypingValueWithIndex(BaseTypingValueWithGenerics):
return ValueSet.from_sets(self._generics_manager.to_tuple()) return ValueSet.from_sets(self._generics_manager.to_tuple())
def _create_instance_with_generics(self, generics_manager): def _create_instance_with_generics(self, generics_manager):
return TypingValueWithIndex( return ProxyWithGenerics(
self.parent_context, self.parent_context,
self._tree_name, self._tree_name,
generics_manager generics_manager
) )
def infer_type_vars(self, value_set):
annotation_generics = self.get_generics()
if not annotation_generics:
return {}
annotation_name = self.py__name__()
if annotation_name == 'Optional':
# Optional[T] is equivalent to Union[T, None]. In Jedi unions
# are represented by members within a ValueSet, so we extract
# the T from the Optional[T] by removing the None value.
none = builtin_from_name(self.inference_state, u'None')
return annotation_generics[0].infer_type_vars(
value_set.filter(lambda x: x != none),
)
return {}
class ProxyTypingValue(BaseTypingValue): class ProxyTypingValue(BaseTypingValue):
index_class = TypingValueWithIndex index_class = ProxyWithGenerics
def with_generics(self, generics_tuple): def with_generics(self, generics_tuple):
return self.index_class.create_cached( return self.index_class.create_cached(
@ -183,11 +203,8 @@ class _TypingClassMixin(ClassMixin):
return ValueName(self, self._tree_name) return ValueName(self, self._tree_name)
class TypingClassValueWithIndex(_TypingClassMixin, TypingValueWithIndex): class TypingClassWithGenerics(ProxyWithGenerics, _TypingClassMixin):
def infer_type_vars(self, value_set, is_class_value=False): def infer_type_vars(self, value_set):
# Circular
from jedi.inference.gradual.annotation import merge_pairwise_generics, merge_type_var_dicts
type_var_dict = {} type_var_dict = {}
annotation_generics = self.get_generics() annotation_generics = self.get_generics()
@ -196,24 +213,12 @@ class TypingClassValueWithIndex(_TypingClassMixin, TypingValueWithIndex):
annotation_name = self.py__name__() annotation_name = self.py__name__()
if annotation_name == 'Type': if annotation_name == 'Type':
if is_class_value: return annotation_generics[0].infer_type_vars(
# This only applies if we are comparing something like # This is basically a trick to avoid extra code: We execute the
# List[Type[int]] with Iterable[Type[int]]. First, Jedi tries to # incoming classes to be able to use the normal code for type
# match List/Iterable. After that we will land here, because # var inference.
# is_class_value will be True at that point. Obviously we also value_set.execute_annotation(),
# compare below that both sides are `Type`. )
for element in value_set:
element_name = element.py__name__()
if element_name == 'Type':
merge_type_var_dicts(
type_var_dict,
merge_pairwise_generics(self, element),
)
else:
return annotation_generics[0].infer_type_vars(
value_set,
is_class_value=True,
)
elif annotation_name == 'Callable': elif annotation_name == 'Callable':
if len(annotation_generics) == 2: if len(annotation_generics) == 2:
@ -223,13 +228,20 @@ class TypingClassValueWithIndex(_TypingClassMixin, TypingValueWithIndex):
elif annotation_name == 'Tuple': elif annotation_name == 'Tuple':
tuple_annotation, = self.execute_annotation() tuple_annotation, = self.execute_annotation()
return tuple_annotation.infer_type_vars(value_set, is_class_value) return tuple_annotation.infer_type_vars(value_set)
return type_var_dict return type_var_dict
def _create_instance_with_generics(self, generics_manager):
return TypingClassWithGenerics(
self.parent_context,
self._tree_name,
generics_manager
)
class ProxyTypingClassValue(_TypingClassMixin, ProxyTypingValue):
index_class = TypingClassValueWithIndex class ProxyTypingClassValue(ProxyTypingValue, _TypingClassMixin):
index_class = TypingClassWithGenerics
class TypeAlias(LazyValueWrapper): class TypeAlias(LazyValueWrapper):
@ -269,7 +281,7 @@ class TypeAlias(LazyValueWrapper):
return ValueSet([self._get_wrapped_value()]) return ValueSet([self._get_wrapped_value()])
class Callable(BaseTypingValueWithGenerics): class Callable(BaseTypingInstance):
def py__call__(self, arguments): def py__call__(self, arguments):
""" """
def x() -> Callable[[Callable[..., _T]], _T]: ... def x() -> Callable[[Callable[..., _T]], _T]: ...
@ -286,7 +298,7 @@ class Callable(BaseTypingValueWithGenerics):
return infer_return_for_callable(arguments, param_values, result_values) return infer_return_for_callable(arguments, param_values, result_values)
class Tuple(BaseTypingValueWithGenerics): class Tuple(BaseTypingInstance):
def _is_homogenous(self): def _is_homogenous(self):
# To specify a variable-length tuple of homogeneous type, Tuple[T, ...] # To specify a variable-length tuple of homogeneous type, Tuple[T, ...]
# is used. # is used.
@ -322,16 +334,23 @@ class Tuple(BaseTypingValueWithGenerics):
.py__getattribute__('tuple').execute_annotation() .py__getattribute__('tuple').execute_annotation()
return tuple_ return tuple_
def infer_type_vars(self, value_set, is_class_value=False): @property
def name(self):
return self._wrapped_value.name
def infer_type_vars(self, value_set):
# Circular # Circular
from jedi.inference.gradual.annotation import merge_pairwise_generics, merge_type_var_dicts from jedi.inference.gradual.annotation import merge_pairwise_generics, merge_type_var_dicts
from jedi.inference.gradual.base import GenericClass
value_set = value_set.filter(
lambda x: x.py__name__().lower() == 'tuple',
)
if self._is_homogenous(): if self._is_homogenous():
# The parameter annotation is of the form `Tuple[T, ...]`, # The parameter annotation is of the form `Tuple[T, ...]`,
# so we treat the incoming tuple like a iterable sequence # so we treat the incoming tuple like a iterable sequence
# rather than a positional container of elements. # rather than a positional container of elements.
return self.get_generics()[0].infer_type_vars( return self._class_value.get_generics()[0].infer_type_vars(
value_set.merge_types_of_iterate(), value_set.merge_types_of_iterate(),
) )
@ -343,27 +362,32 @@ class Tuple(BaseTypingValueWithGenerics):
type_var_dict = {} type_var_dict = {}
for element in value_set: for element in value_set:
py_class = element.get_annotated_class_object() try:
if not isinstance(py_class, GenericClass): method = element.get_annotated_class_object
py_class = element except AttributeError:
# This might still happen, because the tuple name matching
# above is not 100% correct, so just catch the remaining
# cases here.
continue
py_class = method()
merge_type_var_dicts( merge_type_var_dicts(
type_var_dict, type_var_dict,
merge_pairwise_generics(self, py_class), merge_pairwise_generics(self._class_value, py_class),
) )
return type_var_dict return type_var_dict
class Generic(BaseTypingValueWithGenerics): class Generic(BaseTypingInstance):
pass pass
class Protocol(BaseTypingValueWithGenerics): class Protocol(BaseTypingInstance):
pass pass
class Any(BaseTypingValue): class AnyClass(BaseTypingValue):
def execute_annotation(self): def execute_annotation(self):
debug.warning('Used Any - returned no results') debug.warning('Used Any - returned no results')
return NO_VALUES return NO_VALUES
@ -398,6 +422,10 @@ class NewType(Value):
self._type_value_set = type_value_set self._type_value_set = type_value_set
self.tree_node = tree_node self.tree_node = tree_node
def py__class__(self):
c, = self._type_value_set.py__class__()
return c
def py__call__(self, arguments): def py__call__(self, arguments):
return self._type_value_set.execute_annotation() return self._type_value_set.execute_annotation()
@ -413,7 +441,7 @@ class CastFunction(BaseTypingValue):
return type_value_set.execute_annotation() return type_value_set.execute_annotation()
class TypedDictBase(BaseTypingValue): class TypedDictClass(BaseTypingValue):
""" """
This class has no responsibilities and is just here to make sure that typed This class has no responsibilities and is just here to make sure that typed
dicts can be identified. dicts can be identified.

View File

@ -1,5 +1,5 @@
from jedi.inference.base_value import ValueSet, NO_VALUES from jedi.inference.base_value import ValueSet, NO_VALUES
from jedi.common.utils import monkeypatch from jedi.common import monkeypatch
class AbstractLazyValue(object): class AbstractLazyValue(object):

View File

@ -3,13 +3,14 @@ import re
from parso import python_bytes_to_unicode from parso import python_bytes_to_unicode
from jedi._compatibility import FileNotFoundError
from jedi.debug import dbg from jedi.debug import dbg
from jedi.file_io import KnownContentFileIO from jedi.file_io import KnownContentFileIO
from jedi.inference.imports import SubModuleName, load_module_from_path from jedi.inference.imports import SubModuleName, load_module_from_path
from jedi.inference.filters import ParserTreeFilter from jedi.inference.filters import ParserTreeFilter
from jedi.inference.gradual.conversion import convert_names from jedi.inference.gradual.conversion import convert_names
_IGNORE_FOLDERS = ('.tox', 'venv', '__pycache__') _IGNORE_FOLDERS = ('.tox', '.venv', 'venv', '__pycache__')
_OPENED_FILE_LIMIT = 2000 _OPENED_FILE_LIMIT = 2000
""" """
@ -113,7 +114,7 @@ def _find_global_variables(names, search_name):
yield n yield n
def find_references(module_context, tree_name): def find_references(module_context, tree_name, only_in_module=False):
inf = module_context.inference_state inf = module_context.inference_state
search_name = tree_name.value search_name = tree_name.value
@ -127,10 +128,14 @@ def find_references(module_context, tree_name):
found_names_dct = _dictionarize(found_names) found_names_dct = _dictionarize(found_names)
module_contexts = set(d.get_root_context() for d in found_names) module_contexts = [module_context]
module_contexts = [module_context] + [m for m in module_contexts if m != module_context] if not only_in_module:
module_contexts.extend(
m for m in set(d.get_root_context() for d in found_names)
if m != module_context and m.tree_node is not None
)
# For param no search for other modules is necessary. # For param no search for other modules is necessary.
if any(n.api_type == 'param' for n in found_names): if only_in_module or any(n.api_type == 'param' for n in found_names):
potential_modules = module_contexts potential_modules = module_contexts
else: else:
potential_modules = get_module_contexts_containing_name( potential_modules = get_module_contexts_containing_name(
@ -157,7 +162,10 @@ def find_references(module_context, tree_name):
else: else:
for name in new: for name in new:
non_matching_reference_maps.setdefault(name, []).append(new) non_matching_reference_maps.setdefault(name, []).append(new)
return found_names_dct.values() result = found_names_dct.values()
if only_in_module:
return [n for n in result if n.get_root_context() == module_context]
return result
def _check_fs(inference_state, file_io, regex): def _check_fs(inference_state, file_io, regex):

View File

@ -31,6 +31,25 @@ from jedi.inference.context import CompForContext
from jedi.inference.value.decorator import Decoratee from jedi.inference.value.decorator import Decoratee
from jedi.plugins import plugin_manager from jedi.plugins import plugin_manager
operator_to_magic_method = {
'+': '__add__',
'-': '__sub__',
'*': '__mul__',
'/': '__truediv__',
'//': '__floordiv__',
'%': '__mod__',
'**': '__pow__',
'<<': '__lshift__',
'>>': '__rshift__',
'&': '__and__',
'|': '__or__',
'^': '__xor__',
}
reverse_operator_to_magic_method = {
k: '__r' + v[2:] for k, v in operator_to_magic_method.items()
}
def _limit_value_infers(func): def _limit_value_infers(func):
""" """
@ -538,12 +557,12 @@ def _is_annotation_name(name):
return False return False
def _is_tuple(value):
return isinstance(value, iterable.Sequence) and value.array_type == 'tuple'
def _is_list(value): def _is_list(value):
return isinstance(value, iterable.Sequence) and value.array_type == 'list' return value.array_type == 'list'
def _is_tuple(value):
return value.array_type == 'tuple'
def _bool_to_value(inference_state, bool_): def _bool_to_value(inference_state, bool_):
@ -584,7 +603,7 @@ def _infer_comparison_part(inference_state, context, left, operator, right):
elif str_operator == '+': elif str_operator == '+':
if l_is_num and r_is_num or is_string(left) and is_string(right): if l_is_num and r_is_num or is_string(left) and is_string(right):
return left.execute_operation(right, str_operator) return left.execute_operation(right, str_operator)
elif _is_tuple(left) and _is_tuple(right) or _is_list(left) and _is_list(right): elif _is_list(left) and _is_list(right) or _is_tuple(left) and _is_tuple(right):
return ValueSet([iterable.MergedArray(inference_state, (left, right))]) return ValueSet([iterable.MergedArray(inference_state, (left, right))])
elif str_operator == '-': elif str_operator == '-':
if l_is_num and r_is_num: if l_is_num and r_is_num:
@ -622,7 +641,7 @@ def _infer_comparison_part(inference_state, context, left, operator, right):
_bool_to_value(inference_state, True), _bool_to_value(inference_state, True),
_bool_to_value(inference_state, False) _bool_to_value(inference_state, False)
]) ])
elif str_operator == 'in': elif str_operator in ('in', 'not in'):
return NO_VALUES return NO_VALUES
def check(obj): def check(obj):
@ -637,6 +656,24 @@ def _infer_comparison_part(inference_state, context, left, operator, right):
analysis.add(context, 'type-error-operation', operator, analysis.add(context, 'type-error-operation', operator,
message % (left, right)) message % (left, right))
if left.is_class() or right.is_class():
return NO_VALUES
method_name = operator_to_magic_method[str_operator]
magic_methods = left.py__getattribute__(method_name)
if magic_methods:
result = magic_methods.execute_with_values(right)
if result:
return result
if not magic_methods:
reverse_method_name = reverse_operator_to_magic_method[str_operator]
magic_methods = right.py__getattribute__(reverse_method_name)
result = magic_methods.execute_with_values(left)
if result:
return result
result = ValueSet([left, right]) result = ValueSet([left, right])
debug.dbg('Used operator %s resulting in %s', operator, result) debug.dbg('Used operator %s resulting in %s', operator, result)
return result return result

View File

@ -5,7 +5,7 @@ from jedi._compatibility import unicode, force_unicode, all_suffixes
from jedi.inference.cache import inference_state_method_cache from jedi.inference.cache import inference_state_method_cache
from jedi.inference.base_value import ContextualizedNode from jedi.inference.base_value import ContextualizedNode
from jedi.inference.helpers import is_string, get_str_or_none from jedi.inference.helpers import is_string, get_str_or_none
from jedi.common.utils import traverse_parents from jedi.common import traverse_parents
from jedi.parser_utils import get_cached_code_lines from jedi.parser_utils import get_cached_code_lines
from jedi.file_io import FileIO from jedi.file_io import FileIO
from jedi import settings from jedi import settings

View File

@ -288,6 +288,11 @@ class _BaseTreeInstance(AbstractInstanceValue):
""" """
# Arguments in __get__ descriptors are obj, class. # Arguments in __get__ descriptors are obj, class.
# `method` is the new parent of the array, don't know if that's good. # `method` is the new parent of the array, don't know if that's good.
for cls in self.class_value.py__mro__():
result = cls.py__get__on_class(self, instance, class_value)
if result is not NotImplemented:
return result
names = self.get_function_slot_names(u'__get__') names = self.get_function_slot_names(u'__get__')
if names: if names:
if instance is None: if instance is None:
@ -332,13 +337,14 @@ class TreeInstance(_BaseTreeInstance):
for signature in self.class_value.py__getattribute__('__init__').get_signatures(): for signature in self.class_value.py__getattribute__('__init__').get_signatures():
# Just take the first result, it should always be one, because we # Just take the first result, it should always be one, because we
# control the typeshed code. # control the typeshed code.
if not signature.matches_signature(args) \ funcdef = signature.value.tree_node
or signature.value.tree_node is None: if funcdef is None or funcdef.type != 'funcdef' \
or not signature.matches_signature(args):
# First check if the signature even matches, if not we don't # First check if the signature even matches, if not we don't
# need to infer anything. # need to infer anything.
continue continue
bound_method = BoundMethod(self, self.class_value.as_context(), signature.value) bound_method = BoundMethod(self, self.class_value.as_context(), signature.value)
all_annotations = py__annotations__(signature.value.tree_node) all_annotations = py__annotations__(funcdef)
type_var_dict = infer_type_vars_for_execution(bound_method, args, all_annotations) type_var_dict = infer_type_vars_for_execution(bound_method, args, all_annotations)
if type_var_dict: if type_var_dict:
defined, = self.class_value.define_generics( defined, = self.class_value.define_generics(

View File

@ -58,13 +58,13 @@ class GeneratorBase(LazyAttributeOverwrite, IterableMixin):
return True return True
@publish_method('__iter__') @publish_method('__iter__')
def py__iter__(self, contextualized_node=None): def _iter(self, arguments):
return ValueSet([self]) return ValueSet([self])
@publish_method('send') @publish_method('send')
@publish_method('next', python_version_match=2) @publish_method('next', python_version_match=2)
@publish_method('__next__', python_version_match=3) @publish_method('__next__', python_version_match=3)
def py__next__(self): def py__next__(self, arguments):
return ValueSet.from_sets(lazy_value.infer() for lazy_value in self.py__iter__()) return ValueSet.from_sets(lazy_value.infer() for lazy_value in self.py__iter__())
def py__stop_iteration_returns(self): def py__stop_iteration_returns(self):
@ -192,13 +192,17 @@ class Sequence(LazyAttributeOverwrite, IterableMixin):
def _get_generics(self): def _get_generics(self):
return (self.merge_types_of_iterate().py__class__(),) return (self.merge_types_of_iterate().py__class__(),)
@inference_state_method_cache(default=())
def _cached_generics(self):
return self._get_generics()
def _get_wrapped_value(self): def _get_wrapped_value(self):
from jedi.inference.gradual.base import GenericClass from jedi.inference.gradual.base import GenericClass
from jedi.inference.gradual.generics import TupleGenericManager from jedi.inference.gradual.generics import TupleGenericManager
klass = compiled.builtin_from_name(self.inference_state, self.array_type) klass = compiled.builtin_from_name(self.inference_state, self.array_type)
c, = GenericClass( c, = GenericClass(
klass, klass,
TupleGenericManager(self._get_generics()) TupleGenericManager(self._cached_generics())
).execute_annotation() ).execute_annotation()
return c return c
@ -286,12 +290,12 @@ class DictComprehension(ComprehensionMixin, Sequence, _DictKeyMixin):
return ValueSet.from_sets(values for keys, values in self._iterate()) return ValueSet.from_sets(values for keys, values in self._iterate())
@publish_method('values') @publish_method('values')
def _imitate_values(self): def _imitate_values(self, arguments):
lazy_value = LazyKnownValues(self._dict_values()) lazy_value = LazyKnownValues(self._dict_values())
return ValueSet([FakeList(self.inference_state, [lazy_value])]) return ValueSet([FakeList(self.inference_state, [lazy_value])])
@publish_method('items') @publish_method('items')
def _imitate_items(self): def _imitate_items(self, arguments):
lazy_values = [ lazy_values = [
LazyKnownValue( LazyKnownValue(
FakeTuple( FakeTuple(
@ -453,12 +457,12 @@ class DictLiteralValue(_DictMixin, SequenceLiteralValue, _DictKeyMixin):
yield LazyKnownValues(types) yield LazyKnownValues(types)
@publish_method('values') @publish_method('values')
def _imitate_values(self): def _imitate_values(self, arguments):
lazy_value = LazyKnownValues(self._dict_values()) lazy_value = LazyKnownValues(self._dict_values())
return ValueSet([FakeList(self.inference_state, [lazy_value])]) return ValueSet([FakeList(self.inference_state, [lazy_value])])
@publish_method('items') @publish_method('items')
def _imitate_items(self): def _imitate_items(self, arguments):
lazy_values = [ lazy_values = [
LazyKnownValue(FakeTuple( LazyKnownValue(FakeTuple(
self.inference_state, self.inference_state,
@ -548,7 +552,7 @@ class FakeDict(_DictMixin, Sequence, _DictKeyMixin):
return lazy_value.infer() return lazy_value.infer()
@publish_method('values') @publish_method('values')
def _values(self): def _values(self, arguments):
return ValueSet([FakeTuple( return ValueSet([FakeTuple(
self.inference_state, self.inference_state,
[LazyKnownValues(self._dict_values())] [LazyKnownValues(self._dict_values())]

View File

@ -114,8 +114,6 @@ class ClassFilter(ParserTreeFilter):
if expr_stmt is not None and expr_stmt.type == 'expr_stmt': if expr_stmt is not None and expr_stmt.type == 'expr_stmt':
annassign = expr_stmt.children[1] annassign = expr_stmt.children[1]
if annassign.type == 'annassign': if annassign.type == 'annassign':
# TODO this is not proper matching
# If there is an =, the variable is obviously also # If there is an =, the variable is obviously also
# defined on the class. # defined on the class.
if 'ClassVar' not in annassign.children[1].get_code() \ if 'ClassVar' not in annassign.children[1].get_code() \
@ -135,7 +133,10 @@ class ClassMixin(object):
def is_class(self): def is_class(self):
return True return True
def py__call__(self, arguments=None): def is_class_mixin(self):
return True
def py__call__(self, arguments):
from jedi.inference.value import TreeInstance from jedi.inference.value import TreeInstance
from jedi.inference.gradual.typing import TypedDict from jedi.inference.gradual.typing import TypedDict
@ -186,11 +187,13 @@ class ClassMixin(object):
mro.append(cls_new) mro.append(cls_new)
yield cls_new yield cls_new
def get_filters(self, origin_scope=None, is_instance=False): def get_filters(self, origin_scope=None, is_instance=False,
metaclasses = self.get_metaclasses() include_metaclasses=True, include_type_when_class=True):
if metaclasses: if include_metaclasses:
for f in self.get_metaclass_filters(metaclasses): metaclasses = self.get_metaclasses()
yield f if metaclasses:
for f in self.get_metaclass_filters(metaclasses, is_instance):
yield f # Python 2..
for cls in self.py__mro__(): for cls in self.py__mro__():
if cls.is_compiled(): if cls.is_compiled():
@ -202,7 +205,7 @@ class ClassMixin(object):
origin_scope=origin_scope, origin_scope=origin_scope,
is_instance=is_instance is_instance=is_instance
) )
if not is_instance: if not is_instance and include_type_when_class:
from jedi.inference.compiled import builtin_from_name from jedi.inference.compiled import builtin_from_name
type_ = builtin_from_name(self.inference_state, u'type') type_ = builtin_from_name(self.inference_state, u'type')
assert isinstance(type_, ClassValue) assert isinstance(type_, ClassValue)
@ -224,6 +227,11 @@ class ClassMixin(object):
# Since calling staticmethod without a function is illegal, the Jedi # Since calling staticmethod without a function is illegal, the Jedi
# plugin doesn't return anything. Therefore call directly and get what # plugin doesn't return anything. Therefore call directly and get what
# we want: An instance of staticmethod. # we want: An instance of staticmethod.
metaclasses = self.get_metaclasses()
if metaclasses:
sigs = self.get_metaclass_signatures(metaclasses)
if sigs:
return sigs
args = ValuesArguments([]) args = ValuesArguments([])
init_funcs = self.py__call__(args).py__getattribute__('__init__') init_funcs = self.py__call__(args).py__getattribute__('__init__')
return [sig.bind(self) for sig in init_funcs.get_signatures()] return [sig.bind(self) for sig in init_funcs.get_signatures()]
@ -240,7 +248,7 @@ class ClassMixin(object):
def is_typeddict(self): def is_typeddict(self):
# TODO Do a proper mro resolution. Currently we are just listing # TODO Do a proper mro resolution. Currently we are just listing
# classes. However, it's a complicated algorithm. # classes. However, it's a complicated algorithm.
from jedi.inference.gradual.typing import TypedDictBase from jedi.inference.gradual.typing import TypedDictClass
for lazy_cls in self.py__bases__(): for lazy_cls in self.py__bases__():
if not isinstance(lazy_cls, LazyTreeValue): if not isinstance(lazy_cls, LazyTreeValue):
return False return False
@ -252,7 +260,7 @@ class ClassMixin(object):
return False return False
for cls in lazy_cls.infer(): for cls in lazy_cls.infer():
if isinstance(cls, TypedDictBase): if isinstance(cls, TypedDictClass):
return True return True
try: try:
method = cls.is_typeddict method = cls.is_typeddict
@ -266,6 +274,52 @@ class ClassMixin(object):
return True return True
return False return False
def py__getitem__(self, index_value_set, contextualized_node):
from jedi.inference.gradual.base import GenericClass
if not index_value_set:
debug.warning('Class indexes inferred to nothing. Returning class instead')
return ValueSet([self])
return ValueSet(
GenericClass(
self,
LazyGenericManager(
context_of_index=contextualized_node.context,
index_value=index_value,
)
)
for index_value in index_value_set
)
def with_generics(self, generics_tuple):
from jedi.inference.gradual.base import GenericClass
return GenericClass(
self,
TupleGenericManager(generics_tuple)
)
def define_generics(self, type_var_dict):
from jedi.inference.gradual.base import GenericClass
def remap_type_vars():
"""
The TypeVars in the resulting classes have sometimes different names
and we need to check for that, e.g. a signature can be:
def iter(iterable: Iterable[_T]) -> Iterator[_T]: ...
However, the iterator is defined as Iterator[_T_co], which means it has
a different type var name.
"""
for type_var in self.list_type_vars():
yield type_var_dict.get(type_var.py__name__(), NO_VALUES)
if type_var_dict:
return ValueSet([GenericClass(
self,
TupleGenericManager(tuple(remap_type_vars()))
)])
return ValueSet({self})
class ClassValue(use_metaclass(CachedMetaClass, ClassMixin, FunctionAndClassBase)): class ClassValue(use_metaclass(CachedMetaClass, ClassMixin, FunctionAndClassBase)):
api_type = u'class' api_type = u'class'
@ -310,54 +364,9 @@ class ClassValue(use_metaclass(CachedMetaClass, ClassMixin, FunctionAndClassBase
self.inference_state.builtins_module.py__getattribute__('object') self.inference_state.builtins_module.py__getattribute__('object')
)] )]
def py__getitem__(self, index_value_set, contextualized_node):
from jedi.inference.gradual.base import GenericClass
if not index_value_set:
return ValueSet([self])
return ValueSet(
GenericClass(
self,
LazyGenericManager(
context_of_index=contextualized_node.context,
index_value=index_value,
)
)
for index_value in index_value_set
)
def with_generics(self, generics_tuple):
from jedi.inference.gradual.base import GenericClass
return GenericClass(
self,
TupleGenericManager(generics_tuple)
)
def define_generics(self, type_var_dict):
from jedi.inference.gradual.base import GenericClass
def remap_type_vars():
"""
The TypeVars in the resulting classes have sometimes different names
and we need to check for that, e.g. a signature can be:
def iter(iterable: Iterable[_T]) -> Iterator[_T]: ...
However, the iterator is defined as Iterator[_T_co], which means it has
a different type var name.
"""
for type_var in self.list_type_vars():
yield type_var_dict.get(type_var.py__name__(), NO_VALUES)
if type_var_dict:
return ValueSet([GenericClass(
self,
TupleGenericManager(tuple(remap_type_vars()))
)])
return ValueSet({self})
@plugin_manager.decorate() @plugin_manager.decorate()
def get_metaclass_filters(self, metaclass): def get_metaclass_filters(self, metaclasses, is_instance):
debug.dbg('Unprocessed metaclass %s', metaclass) debug.warning('Unprocessed metaclass %s', metaclasses)
return [] return []
@inference_state_method_cache(default=NO_VALUES) @inference_state_method_cache(default=NO_VALUES)
@ -377,3 +386,7 @@ class ClassValue(use_metaclass(CachedMetaClass, ClassMixin, FunctionAndClassBase
if values: if values:
return values return values
return NO_VALUES return NO_VALUES
@plugin_manager.decorate()
def get_metaclass_signatures(self, metaclasses):
return []

View File

@ -288,6 +288,8 @@ def cut_value_at_position(leaf, position):
column = position[1] column = position[1]
if leaf.line == position[0]: if leaf.line == position[0]:
column -= leaf.column column -= leaf.column
if not lines:
return ''
lines[-1] = lines[-1][:column] lines[-1] = lines[-1][:column]
return ''.join(lines) return ''.join(lines)

View File

@ -5,7 +5,8 @@ This is not a plugin, this is just the place were plugins are registered.
from jedi.plugins import stdlib from jedi.plugins import stdlib
from jedi.plugins import flask from jedi.plugins import flask
from jedi.plugins import pytest from jedi.plugins import pytest
from jedi.plugins import django
from jedi.plugins import plugin_manager from jedi.plugins import plugin_manager
plugin_manager.register(stdlib, flask, pytest) plugin_manager.register(stdlib, flask, pytest, django)

View File

@ -16,7 +16,7 @@ from jedi._compatibility import force_unicode, Parameter
from jedi import debug from jedi import debug
from jedi.inference.utils import safe_property from jedi.inference.utils import safe_property
from jedi.inference.helpers import get_str_or_none from jedi.inference.helpers import get_str_or_none
from jedi.inference.arguments import \ from jedi.inference.arguments import iterate_argument_clinic, ParamIssue, \
repack_with_argument_clinic, AbstractArguments, TreeArgumentsWrapper repack_with_argument_clinic, AbstractArguments, TreeArgumentsWrapper
from jedi.inference import analysis from jedi.inference import analysis
from jedi.inference import compiled from jedi.inference import compiled
@ -143,7 +143,7 @@ def _follow_param(inference_state, arguments, index):
return lazy_value.infer() return lazy_value.infer()
def argument_clinic(string, want_value=False, want_context=False, def argument_clinic(clinic_string, want_value=False, want_context=False,
want_arguments=False, want_inference_state=False, want_arguments=False, want_inference_state=False,
want_callback=False): want_callback=False):
""" """
@ -151,13 +151,15 @@ def argument_clinic(string, want_value=False, want_context=False,
""" """
def f(func): def f(func):
@repack_with_argument_clinic(string, keep_arguments_param=True, def wrapper(value, arguments, callback):
keep_callback_param=True) try:
def wrapper(value, *args, **kwargs): args = tuple(iterate_argument_clinic(
arguments = kwargs.pop('arguments') value.inference_state, arguments, clinic_string))
callback = kwargs.pop('callback') except ParamIssue:
assert not kwargs # Python 2... return NO_VALUES
debug.dbg('builtin start %s' % value, color='MAGENTA') debug.dbg('builtin start %s' % value, color='MAGENTA')
kwargs = {}
if want_context: if want_context:
kwargs['context'] = arguments.context kwargs['context'] = arguments.context
if want_value: if want_value:
@ -258,13 +260,12 @@ class ReversedObject(AttributeOverwrite):
super(ReversedObject, self).__init__(reversed_obj) super(ReversedObject, self).__init__(reversed_obj)
self._iter_list = iter_list self._iter_list = iter_list
@publish_method('__iter__') def py__iter__(self, contextualized_node):
def py__iter__(self, contextualized_node=None):
return self._iter_list return self._iter_list
@publish_method('next', python_version_match=2) @publish_method('next', python_version_match=2)
@publish_method('__next__', python_version_match=3) @publish_method('__next__', python_version_match=3)
def py__next__(self): def py__next__(self, arguments):
return ValueSet.from_sets( return ValueSet.from_sets(
lazy_value.infer() for lazy_value in self._iter_list lazy_value.infer() for lazy_value in self._iter_list
) )
@ -393,13 +394,13 @@ class PropertyObject(AttributeOverwrite, ValueWrapper):
def py__get__(self, instance, class_value): def py__get__(self, instance, class_value):
if instance is None: if instance is None:
return NO_VALUES return ValueSet([self])
return self._function.execute_with_values(instance) return self._function.execute_with_values(instance)
@publish_method('deleter') @publish_method('deleter')
@publish_method('getter') @publish_method('getter')
@publish_method('setter') @publish_method('setter')
def _return_self(self): def _return_self(self, arguments):
return ValueSet({self}) return ValueSet({self})
@ -516,6 +517,8 @@ class PartialObject(ValueWrapper):
class PartialMethodObject(PartialObject): class PartialMethodObject(PartialObject):
def py__get__(self, instance, class_value): def py__get__(self, instance, class_value):
if instance is None:
return ValueSet([self])
return ValueSet([PartialObject(self._actual_value, self._arguments, instance)]) return ValueSet([PartialObject(self._actual_value, self._arguments, instance)])
@ -782,6 +785,9 @@ _implemented = {
# Therefore, just make it return nothing, which leads to the stubs # Therefore, just make it return nothing, which leads to the stubs
# being used instead. This only matters for 3.7+. # being used instead. This only matters for 3.7+.
'_alias': lambda value, arguments, callback: NO_VALUES, '_alias': lambda value, arguments, callback: NO_VALUES,
# runtime_checkable doesn't really change anything and is just
# adding logs for infering stuff, so we can safely ignore it.
'runtime_checkable': lambda value, arguments, callback: NO_VALUES,
}, },
'dataclasses': { 'dataclasses': {
# For now this works at least better than Jedi trying to understand it. # For now this works at least better than Jedi trying to understand it.
@ -797,7 +803,7 @@ _implemented = {
def get_metaclass_filters(func): def get_metaclass_filters(func):
def wrapper(cls, metaclasses): def wrapper(cls, metaclasses, is_instance):
for metaclass in metaclasses: for metaclass in metaclasses:
if metaclass.py__name__() == 'EnumMeta' \ if metaclass.py__name__() == 'EnumMeta' \
and metaclass.get_root_context().py__name__() == 'enum': and metaclass.get_root_context().py__name__() == 'enum':
@ -805,7 +811,7 @@ def get_metaclass_filters(func):
return [DictFilter({ return [DictFilter({
name.string_name: EnumInstance(cls, name).name for name in filter_.values() name.string_name: EnumInstance(cls, name).name for name in filter_.values()
})] })]
return func(cls, metaclasses) return func(cls, metaclasses, is_instance)
return wrapper return wrapper

View File

@ -69,8 +69,8 @@ Adds an opening bracket after a function for completions.
# ---------------- # ----------------
if platform.system().lower() == 'windows': if platform.system().lower() == 'windows':
_cache_directory = os.path.join(os.getenv('APPDATA') or '~', 'Jedi', _cache_directory = os.path.join(os.getenv('LOCALAPPDATA') or
'Jedi') os.path.expanduser('~'), 'Jedi', 'Jedi')
elif platform.system().lower() == 'darwin': elif platform.system().lower() == 'darwin':
_cache_directory = os.path.join('~', 'Library', 'Caches', 'Jedi') _cache_directory = os.path.join('~', 'Library', 'Caches', 'Jedi')
else: else:
@ -81,7 +81,7 @@ cache_directory = os.path.expanduser(_cache_directory)
The path where the cache is stored. The path where the cache is stored.
On Linux, this defaults to ``~/.cache/jedi/``, on OS X to On Linux, this defaults to ``~/.cache/jedi/``, on OS X to
``~/Library/Caches/Jedi/`` and on Windows to ``%APPDATA%\\Jedi\\Jedi\\``. ``~/Library/Caches/Jedi/`` and on Windows to ``%LOCALAPPDATA%\\Jedi\\Jedi\\``.
On Linux, if the environment variable ``$XDG_CACHE_HOME`` is set, On Linux, if the environment variable ``$XDG_CACHE_HOME`` is set,
``$XDG_CACHE_HOME/jedi`` is used instead of the default one. ``$XDG_CACHE_HOME/jedi`` is used instead of the default one.
""" """

View File

@ -1 +0,0 @@
import sys, types, os;has_mfs = sys.version_info > (3, 5);p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('mpl_toolkits',));importlib = has_mfs and __import__('importlib.util');has_mfs and __import__('importlib.machinery');m = has_mfs and sys.modules.setdefault('mpl_toolkits', importlib.util.module_from_spec(importlib.machinery.PathFinder.find_spec('mpl_toolkits', [os.path.dirname(p)])));m = m or sys.modules.setdefault('mpl_toolkits', types.ModuleType('mpl_toolkits'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p)

View File

@ -1,127 +0,0 @@
Metadata-Version: 2.1
Name: matplotlib
Version: 3.2.1
Summary: Python plotting package
Home-page: https://matplotlib.org
Author: John D. Hunter, Michael Droettboom
Author-email: matplotlib-users@python.org
License: PSF
Download-URL: https://matplotlib.org/users/installing.html
Project-URL: Documentation, https://matplotlib.org
Project-URL: Source Code, https://github.com/matplotlib/matplotlib
Project-URL: Bug Tracker, https://github.com/matplotlib/matplotlib/issues
Project-URL: Forum, https://discourse.matplotlib.org/
Project-URL: Donate, https://numfocus.org/donate-to-matplotlib
Platform: any
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: Matplotlib
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Education
Classifier: License :: OSI Approved :: Python Software Foundation License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.6
Description-Content-Type: text/x-rst
Requires-Dist: cycler (>=0.10)
Requires-Dist: kiwisolver (>=1.0.1)
Requires-Dist: numpy (>=1.11)
Requires-Dist: pyparsing (!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1)
Requires-Dist: python-dateutil (>=2.1)
|Travis|_ |AzurePipelines|_ |AppVeyor|_ |Codecov|_ |LGTM|_ |PyPi|_ |Gitter|_ |NUMFocus|_ |GitTutorial|_
.. |Travis| image:: https://travis-ci.org/matplotlib/matplotlib.svg?branch=master
.. _Travis: https://travis-ci.org/matplotlib/matplotlib
.. |AzurePipelines| image:: https://dev.azure.com/matplotlib/matplotlib/_apis/build/status/matplotlib.matplotlib?branchName=master
.. _AzurePipelines: https://dev.azure.com/matplotlib/matplotlib/_build/latest?definitionId=1&branchName=master
.. |AppVeyor| image:: https://ci.appveyor.com/api/projects/status/github/matplotlib/matplotlib?branch=master&svg=true
.. _AppVeyor: https://ci.appveyor.com/project/matplotlib/matplotlib
.. |Codecov| image:: https://codecov.io/github/matplotlib/matplotlib/badge.svg?branch=master&service=github
.. _Codecov: https://codecov.io/github/matplotlib/matplotlib?branch=master
.. |LGTM| image:: https://img.shields.io/lgtm/grade/python/g/matplotlib/matplotlib.svg?logo=lgtm&logoWidth=18
.. _LGTM: https://lgtm.com/projects/g/matplotlib/matplotlib
.. |PyPi| image:: https://badge.fury.io/py/matplotlib.svg
.. _PyPi: https://badge.fury.io/py/matplotlib
.. |Gitter| image:: https://badges.gitter.im/matplotlib/matplotlib.png
.. _Gitter: https://gitter.im/matplotlib/matplotlib
.. |NUMFocus| image:: https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat&colorA=E1523D&colorB=007D8A
.. _NUMFocus: https://www.numfocus.org
.. |GitTutorial| image:: https://img.shields.io/badge/PR-Welcome-%23FF8300.svg?
.. _GitTutorial: https://git-scm.com/book/en/v2/GitHub-Contributing-to-a-Project
.. image:: https://matplotlib.org/_static/logo2.svg
Matplotlib is a comprehensive library for creating static, animated, and interactive visualizations in Python.
Check out our `home page <https://matplotlib.org/>`_ for more information.
.. image:: https://matplotlib.org/_static/readme_preview.png
Matplotlib produces publication-quality figures in a variety of hardcopy formats
and interactive environments across platforms. Matplotlib can be used in Python scripts,
the Python and IPython shell, web application servers, and various
graphical user interface toolkits.
Install
=======
For installation instructions and requirements, see `INSTALL.rst <INSTALL.rst>`_ or the
`install <https://matplotlib.org/users/installing.html>`_ documentation.
Test
====
After installation, launch the test suite::
python -m pytest
Read the `testing guide <https://matplotlib.org/devel/testing.html>`_ for more information and alternatives.
Contribute
==========
You've discovered a bug or something else you want to change - excellent!
You've worked out a way to fix it even better!
You want to tell us about it best of all!
Start at the `contributing guide <https://matplotlib.org/devdocs/devel/contributing.html>`_!
Contact
=======
`Discourse <https://discourse.matplotlib.org/>`_ is the discussion forum for general questions and discussions and our recommended starting point.
Our active mailing lists (which are mirrored on Discourse) are:
* `Users <https://mail.python.org/mailman/listinfo/matplotlib-users>`_ mailing list: matplotlib-users@python.org
* `Announcement <https://mail.python.org/mailman/listinfo/matplotlib-announce>`_ mailing list: matplotlib-announce@python.org
* `Development <https://mail.python.org/mailman/listinfo/matplotlib-devel>`_ mailing list: matplotlib-devel@python.org
Gitter_ is for coordinating development and asking questions directly related
to contributing to matplotlib.
Citing Matplotlib
=================
If Matplotlib contributes to a project that leads to publication, please
acknowledge this by citing Matplotlib.
`A ready-made citation entry <https://matplotlib.org/citing.html>`_ is available.

View File

@ -1,892 +0,0 @@
__pycache__/pylab.cpython-37.pyc,,
matplotlib-3.2.1-py3.7-nspkg.pth,sha256=FgO_3ug071EXEKT8mgOPBUhyrswPtPCYjOpUCyau7UU,569
matplotlib-3.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
matplotlib-3.2.1.dist-info/METADATA,sha256=F1oGQTHWb-ltDWNhlYUpDR9UvF5wAQ7l9pyVaRKk_1M,5170
matplotlib-3.2.1.dist-info/RECORD,,
matplotlib-3.2.1.dist-info/WHEEL,sha256=AhV6RMqZ2IDfreRJKo44QWYxYeP-0Jr0bezzBLQ1eog,109
matplotlib-3.2.1.dist-info/namespace_packages.txt,sha256=A2PHFg9NKYOU4pEQ1h97U0Qd-rB-65W34XqC-56ZN9g,13
matplotlib-3.2.1.dist-info/top_level.txt,sha256=9tEw2ni8DdgX8CceoYHqSH1s50vrJ9SDfgtLIG8e3Y4,30
matplotlib/.libs/libpng16-cfdb1654.so.16.21.0,sha256=Fo8LBDWTuCclLkpSng_KP5pI7wcQtuXA9opT1FFkXl0,275648
matplotlib/.libs/libz-a147dcb0.so.1.2.3,sha256=VwXH3AM7bnoa793tKDw_H0pW-VZos08-FEtM_g_VWVM,87848
matplotlib/__init__.py,sha256=FLEIOOmlbJDBzqg4aq8W6w0wSpQF9tVwGu0VW8EwqsA,54615
matplotlib/__pycache__/__init__.cpython-37.pyc,,
matplotlib/__pycache__/_animation_data.cpython-37.pyc,,
matplotlib/__pycache__/_cm.cpython-37.pyc,,
matplotlib/__pycache__/_cm_listed.cpython-37.pyc,,
matplotlib/__pycache__/_color_data.cpython-37.pyc,,
matplotlib/__pycache__/_constrained_layout.cpython-37.pyc,,
matplotlib/__pycache__/_layoutbox.cpython-37.pyc,,
matplotlib/__pycache__/_mathtext_data.cpython-37.pyc,,
matplotlib/__pycache__/_pylab_helpers.cpython-37.pyc,,
matplotlib/__pycache__/_text_layout.cpython-37.pyc,,
matplotlib/__pycache__/_version.cpython-37.pyc,,
matplotlib/__pycache__/afm.cpython-37.pyc,,
matplotlib/__pycache__/animation.cpython-37.pyc,,
matplotlib/__pycache__/artist.cpython-37.pyc,,
matplotlib/__pycache__/axis.cpython-37.pyc,,
matplotlib/__pycache__/backend_bases.cpython-37.pyc,,
matplotlib/__pycache__/backend_managers.cpython-37.pyc,,
matplotlib/__pycache__/backend_tools.cpython-37.pyc,,
matplotlib/__pycache__/bezier.cpython-37.pyc,,
matplotlib/__pycache__/blocking_input.cpython-37.pyc,,
matplotlib/__pycache__/category.cpython-37.pyc,,
matplotlib/__pycache__/cm.cpython-37.pyc,,
matplotlib/__pycache__/collections.cpython-37.pyc,,
matplotlib/__pycache__/colorbar.cpython-37.pyc,,
matplotlib/__pycache__/colors.cpython-37.pyc,,
matplotlib/__pycache__/container.cpython-37.pyc,,
matplotlib/__pycache__/contour.cpython-37.pyc,,
matplotlib/__pycache__/dates.cpython-37.pyc,,
matplotlib/__pycache__/docstring.cpython-37.pyc,,
matplotlib/__pycache__/dviread.cpython-37.pyc,,
matplotlib/__pycache__/figure.cpython-37.pyc,,
matplotlib/__pycache__/font_manager.cpython-37.pyc,,
matplotlib/__pycache__/fontconfig_pattern.cpython-37.pyc,,
matplotlib/__pycache__/gridspec.cpython-37.pyc,,
matplotlib/__pycache__/hatch.cpython-37.pyc,,
matplotlib/__pycache__/image.cpython-37.pyc,,
matplotlib/__pycache__/legend.cpython-37.pyc,,
matplotlib/__pycache__/legend_handler.cpython-37.pyc,,
matplotlib/__pycache__/lines.cpython-37.pyc,,
matplotlib/__pycache__/markers.cpython-37.pyc,,
matplotlib/__pycache__/mathtext.cpython-37.pyc,,
matplotlib/__pycache__/mlab.cpython-37.pyc,,
matplotlib/__pycache__/offsetbox.cpython-37.pyc,,
matplotlib/__pycache__/patches.cpython-37.pyc,,
matplotlib/__pycache__/path.cpython-37.pyc,,
matplotlib/__pycache__/patheffects.cpython-37.pyc,,
matplotlib/__pycache__/pylab.cpython-37.pyc,,
matplotlib/__pycache__/pyplot.cpython-37.pyc,,
matplotlib/__pycache__/quiver.cpython-37.pyc,,
matplotlib/__pycache__/rcsetup.cpython-37.pyc,,
matplotlib/__pycache__/sankey.cpython-37.pyc,,
matplotlib/__pycache__/scale.cpython-37.pyc,,
matplotlib/__pycache__/spines.cpython-37.pyc,,
matplotlib/__pycache__/stackplot.cpython-37.pyc,,
matplotlib/__pycache__/streamplot.cpython-37.pyc,,
matplotlib/__pycache__/table.cpython-37.pyc,,
matplotlib/__pycache__/texmanager.cpython-37.pyc,,
matplotlib/__pycache__/text.cpython-37.pyc,,
matplotlib/__pycache__/textpath.cpython-37.pyc,,
matplotlib/__pycache__/ticker.cpython-37.pyc,,
matplotlib/__pycache__/tight_bbox.cpython-37.pyc,,
matplotlib/__pycache__/tight_layout.cpython-37.pyc,,
matplotlib/__pycache__/transforms.cpython-37.pyc,,
matplotlib/__pycache__/type1font.cpython-37.pyc,,
matplotlib/__pycache__/units.cpython-37.pyc,,
matplotlib/__pycache__/widgets.cpython-37.pyc,,
matplotlib/_animation_data.py,sha256=yClmMx6K-y6pjG3FdHancRyRhyneFuBEbQZ_lhezVys,7499
matplotlib/_cm.py,sha256=nZCQdTWsPc5aJ-n08l2g293Wwg0kSWIgcfStzv9Dtxg,66643
matplotlib/_cm_listed.py,sha256=9aMZ1uoTkxeDKlXfUNmY99HEtAXsW_JcSpwYaBs0kHs,98165
matplotlib/_color_data.py,sha256=K2HSKblmuh-X_1ZZ9TcXcP7iKHaGC4mC_ScWqX_tdXE,34947
matplotlib/_constrained_layout.py,sha256=eafuhM2rw5SL_ilqf0ImxQwtmFX_pR_boeKUrjTHvB0,29678
matplotlib/_contour.cpython-37m-x86_64-linux-gnu.so,sha256=DRPfZh8e5HSbyEOFKEIzpA_3hYpnxckV0Icfe-g-wyM,95144
matplotlib/_image.cpython-37m-x86_64-linux-gnu.so,sha256=Cqh9lTOtqGFawWjs6bJtIPDu8vVhWxKGh_eOWwNuC4M,242496
matplotlib/_layoutbox.py,sha256=LG5KEmNm5apZa1putqzafEpX9w4lLwkoOPxg4owiO2Y,23872
matplotlib/_mathtext_data.py,sha256=CmKFRW6mXCJqgZSQaiNOSG_VUn9WiSx5Hrg-4qKIn14,89371
matplotlib/_path.cpython-37m-x86_64-linux-gnu.so,sha256=KJKK6xVyb6Mf-68Ff7BkdnDzRqjY6YTt8WMeCktMA_Q,190280
matplotlib/_png.cpython-37m-x86_64-linux-gnu.so,sha256=cDH1KkEt0zaDGkU8YS3JZcIOX3mmMYiXHQeoqnHMKqM,35608
matplotlib/_pylab_helpers.py,sha256=RscVbvWEk6QyznzVvX-lSHkWCUOo9Lik7D7j4xelQJ4,3445
matplotlib/_qhull.cpython-37m-x86_64-linux-gnu.so,sha256=BpI08RX7LTHpLVupETP7x1ZXRLaovGizekhFuXR4MFE,382672
matplotlib/_text_layout.py,sha256=88DxzfAOPzpRjpu0OwLaRl6eOVJ5Var8ZxrDyhAQ7C8,1036
matplotlib/_tri.cpython-37m-x86_64-linux-gnu.so,sha256=4GFgZW6QzC-_k3oVs0UCjYnnL0hDSVGIqPIKuTCq2UU,128616
matplotlib/_version.py,sha256=etxeX_ByADCJBN53WhU2IEezakT1gixcO41qmDlMwfY,471
matplotlib/afm.py,sha256=Y2FmLqutIXI__QiAbMNpFclleQrpGf1xsqBgjyCZir0,16642
matplotlib/animation.py,sha256=N0HzAqLF1fscM2OIkER3gv4zsqUXWpxA8BmE_3Jqi5k,68066
matplotlib/artist.py,sha256=2Qd4EUb9n4FAizD1fdb48diR7yRivgwvY8JESg4r4mE,53229
matplotlib/axes/__init__.py,sha256=npQuBvs_xEBEGUP2-BBZzCrelsAQYgB1U96kSZTSWIs,46
matplotlib/axes/__pycache__/__init__.cpython-37.pyc,,
matplotlib/axes/__pycache__/_axes.cpython-37.pyc,,
matplotlib/axes/__pycache__/_base.cpython-37.pyc,,
matplotlib/axes/__pycache__/_secondary_axes.cpython-37.pyc,,
matplotlib/axes/__pycache__/_subplots.cpython-37.pyc,,
matplotlib/axes/_axes.py,sha256=dSaGhVBB00lKf1AF9mCsaFcleTU8qKlSkVNP2ET_CPU,312519
matplotlib/axes/_base.py,sha256=x89D4ElapqkI9lQ0oTAwTGcKPm-m-J26Fg-A0R3Ys1M,159726
matplotlib/axes/_secondary_axes.py,sha256=plMlrvrznuuBSRakuznyCyr_ZNnSiuc_3J-YD3Hg8e8,14352
matplotlib/axes/_subplots.py,sha256=rkT6vCCbCTItY_oAmlT-1rSPOoIerjScJC91I2YLTp0,10203
matplotlib/axis.py,sha256=50zN9IvoaYGqq8t8zUiaaTtcUJeNjxdAnmXioRlfNWc,90049
matplotlib/backend_bases.py,sha256=vNzjru0RDGIlzyeT9vjmWv8ktEFaax0C7W1tXz1qR_w,117888
matplotlib/backend_managers.py,sha256=HuHOXPFjVF1R6ttBLxlucsLcEsWlRXtbm_wr1OJer2Q,12819
matplotlib/backend_tools.py,sha256=zVBxfyPoQx0_lQe1Su0o-zTycOQt-zKWTp3HEY-jTxI,36252
matplotlib/backends/__init__.py,sha256=cKAeiC5g0Up9svoxT24paOcnKc4tb5cbfbF-AWxXLUE,1722
matplotlib/backends/__pycache__/__init__.cpython-37.pyc,,
matplotlib/backends/__pycache__/_backend_pdf_ps.cpython-37.pyc,,
matplotlib/backends/__pycache__/_backend_tk.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_agg.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_cairo.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_gtk3.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_gtk3agg.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_gtk3cairo.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_macosx.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_mixed.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_nbagg.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_pdf.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_pgf.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_ps.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_qt4.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_qt4agg.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_qt4cairo.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_qt5.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_qt5agg.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_qt5cairo.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_svg.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_template.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_tkagg.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_tkcairo.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_webagg.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_webagg_core.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_wx.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_wxagg.cpython-37.pyc,,
matplotlib/backends/__pycache__/backend_wxcairo.cpython-37.pyc,,
matplotlib/backends/__pycache__/qt_compat.cpython-37.pyc,,
matplotlib/backends/_backend_agg.cpython-37m-x86_64-linux-gnu.so,sha256=6sGDDe5csQINH5pB6bcFhLK0a8SyPrVFBT7pUAE4J0s,362384
matplotlib/backends/_backend_pdf_ps.py,sha256=T8x_NWAo9_Wvnpw6HnsneRI9AyAxcp80TDe-z2eosbM,2709
matplotlib/backends/_backend_tk.py,sha256=k1eZjNeVC0rDMEKlOqevga-PFTERv9mcwUn_d_LZUyo,32021
matplotlib/backends/_tkagg.cpython-37m-x86_64-linux-gnu.so,sha256=dk5Ggr6xNaIkdXEind0il3BBX2zEnZTQwzdAVD-wE0U,27256
matplotlib/backends/backend_agg.py,sha256=bjt43QEsQ-AeEeWXSBwRcbJsuDU7Dex-JsdbApekXzA,22347
matplotlib/backends/backend_cairo.py,sha256=zJAQ5_OkKchNrItE8jN9CriAw4aQ0PP3qKqfINu3CSc,16562
matplotlib/backends/backend_gtk3.py,sha256=ED_iXiCIXQlMJmh8YlJJcPkCxnm9Wly7kSod0UogtRc,33832
matplotlib/backends/backend_gtk3agg.py,sha256=iKLBQ48c9Vh4krSxYeSDbHZ4G9wXoezk2VTIgNR4BWw,3072
matplotlib/backends/backend_gtk3cairo.py,sha256=TDQUuYq5KCPvAU-MY2wBxpx2zAn9vOO_ieeE_7fdtS4,1591
matplotlib/backends/backend_macosx.py,sha256=fALNUVEkZrqRrMHe5G_wy5i7FODvXXIum7RU2PXOiG4,5829
matplotlib/backends/backend_mixed.py,sha256=R3-Z5AW7anq31csMjylsY4pSehsAsBLrxFD5YhZkZ6w,5280
matplotlib/backends/backend_nbagg.py,sha256=xAv_OZfz6NtMrbAXWqwX9GCgTEsb5e5FpyAMHSIE-j4,8902
matplotlib/backends/backend_pdf.py,sha256=sq_dTpmyOkYrtWdHQGKanZxRezXFmfeZNCMcObJR95A,96197
matplotlib/backends/backend_pgf.py,sha256=R34xfvJyVm0k4IgjCHPU0bKeP02zJ0_Pr0hV6yaCVv8,43431
matplotlib/backends/backend_ps.py,sha256=MWZmgx9nrlp9_u50gp_JZE2bEt2E3ixZxPqT9Wk5BqY,50575
matplotlib/backends/backend_qt4.py,sha256=H9AsG4NAF27LdGUJDi1n5RwJhK1lI43sa9VXtUgW3K8,397
matplotlib/backends/backend_qt4agg.py,sha256=BXMTBYmqyT_uvEpgSMWts5m2q1YK0vhPeybt0ZMVd0I,292
matplotlib/backends/backend_qt4cairo.py,sha256=cvXKhk8CZvceDiEl9OXmumjJ6dZ3k0u93xy8w8i24gQ,229
matplotlib/backends/backend_qt5.py,sha256=BjGTvVXytXhqRPpYNzoWaO03ULCfKdF3xG78e9nr0Sc,39256
matplotlib/backends/backend_qt5agg.py,sha256=sF1oFyKNmOAdCGUChUbrKfmFmNo8QuD2SzuQQl4U0Mg,3560
matplotlib/backends/backend_qt5cairo.py,sha256=YzXN1Ckr6JLS2r50LPxeypajdWccXaHoXC5QZ4VWrEY,1892
matplotlib/backends/backend_svg.py,sha256=KGdJMf-cXIW82s0MC9-wOsmtEeo8P3np_uK06z2FGkI,43552
matplotlib/backends/backend_template.py,sha256=SVPx4bl2n0eKgEolfJH7ljJnqlak0XhFE6Zr3yr6GU4,8407
matplotlib/backends/backend_tkagg.py,sha256=WMslLWYmtxlmAaBH4tx4HjmRDWMKiSV91KHF9yeMRng,676
matplotlib/backends/backend_tkcairo.py,sha256=dVCh7ZD_2OR0DBQ0N3icD8cDV1SeEzCsRja446wWhPw,1069
matplotlib/backends/backend_webagg.py,sha256=NtP1VSSXQNvB_EBQi14No7flt1C64VwekiTG58tt7LU,10794
matplotlib/backends/backend_webagg_core.py,sha256=u026hAuD_dwL0a2D7g--jzBr_KFS5UqJdFZDvIdlmII,17558
matplotlib/backends/backend_wx.py,sha256=O606ybHYiOFCxpnhpZ_TYaHdULG53YuAZQDq70xjoms,66672
matplotlib/backends/backend_wxagg.py,sha256=Jhb24f2W6e5yCqSi4F971hor_I8Epf_WMfutq3VoTYI,3027
matplotlib/backends/backend_wxcairo.py,sha256=VC5TyJaX8TPLSgHv5ckAreoGrY_KiNRMQjVInMLlcFk,1843
matplotlib/backends/qt_compat.py,sha256=Me6QS6xk4ASjOdBhr7RxvIp4Frzbdmu7mIXRO5uJlwU,6551
matplotlib/backends/qt_editor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
matplotlib/backends/qt_editor/__pycache__/__init__.cpython-37.pyc,,
matplotlib/backends/qt_editor/__pycache__/_formlayout.cpython-37.pyc,,
matplotlib/backends/qt_editor/__pycache__/figureoptions.cpython-37.pyc,,
matplotlib/backends/qt_editor/__pycache__/formlayout.cpython-37.pyc,,
matplotlib/backends/qt_editor/__pycache__/formsubplottool.cpython-37.pyc,,
matplotlib/backends/qt_editor/_formlayout.py,sha256=aHC33AfwtVjly7sPjLTFrVABZqAD2RAloR6KCEAUv5A,20592
matplotlib/backends/qt_editor/figureoptions.py,sha256=YySx6A_wZSACMEHbXYkoQ6wR0_6PPwON2c6YwejUeVs,9481
matplotlib/backends/qt_editor/formlayout.py,sha256=ERfmFwpvhl168PWNTJ0SFhQmPuSrmjzFNOe_puUCoSE,177
matplotlib/backends/qt_editor/formsubplottool.py,sha256=HiiXkwCotra_hI9JU208KOs8Q9JuGH1uAW3mV5l3Evg,1934
matplotlib/backends/web_backend/all_figures.html,sha256=m20aQIhuI4GBdrgZg_j02zSVjAcTRUufPOMSe4i7ayc,1525
matplotlib/backends/web_backend/css/boilerplate.css,sha256=qui16QXRnQFNJDbcMasfH6KtN9hLjv8883U9cJmsVCE,2310
matplotlib/backends/web_backend/css/fbm.css,sha256=Us0osu_rK8EUAdp_GXrh89tN_hUNCN-r7N1T1NvmmwI,1473
matplotlib/backends/web_backend/css/page.css,sha256=Djf6ZNMFaM6_hVaizSkDFoqk-jn81qgduwles4AroGk,1599
matplotlib/backends/web_backend/ipython_inline_figure.html,sha256=mzi-yWg4fcO6PdtTBCfiNuvcv04T53lcRQi-8hphwuE,1305
matplotlib/backends/web_backend/jquery-ui-1.12.1/AUTHORS.txt,sha256=W2Lh1mbGo3Owc0oXX9U1-TFVSZYaC72KvSRrrRp3UII,12660
matplotlib/backends/web_backend/jquery-ui-1.12.1/LICENSE.txt,sha256=3jP7aViA0LB2FdS4b3jNQ3lpBpWa3l_f73CWiCeg23g,1817
matplotlib/backends/web_backend/jquery-ui-1.12.1/external/jquery/jquery.js,sha256=Qw82-bXyGq6MydymqBxNPYTaUXXq7c8v3CwiYwLLNXU,293430
matplotlib/backends/web_backend/jquery-ui-1.12.1/images/ui-icons_444444_256x240.png,sha256=6vfH7idHJ13abFPnMaENsaexX0-7RuG2nWuyBWvJ_YE,7006
matplotlib/backends/web_backend/jquery-ui-1.12.1/images/ui-icons_555555_256x240.png,sha256=XQQFHf2dLXQDVUBPmKaD0ewP6y_KfXblM8Gm5c6S3S4,7074
matplotlib/backends/web_backend/jquery-ui-1.12.1/images/ui-icons_777620_256x240.png,sha256=nb5KDQP-7W9l6yVgoKi0ukJkVF7o_THBdjo7IZ0DKNY,4676
matplotlib/backends/web_backend/jquery-ui-1.12.1/images/ui-icons_777777_256x240.png,sha256=51snIR4W_PlHFRaAAbtwVco3bUb5KBELo9CCUjJFLlo,7013
matplotlib/backends/web_backend/jquery-ui-1.12.1/images/ui-icons_cc0000_256x240.png,sha256=AokVddQ1jp7d4-QtlAV_jp-CqdZDdvce6GzvFJ0wU34,4632
matplotlib/backends/web_backend/jquery-ui-1.12.1/images/ui-icons_ffffff_256x240.png,sha256=trBt7vK5JMw4NdY_SIPUeIJzSjPnGyEtkXpozt47jp0,6313
matplotlib/backends/web_backend/jquery-ui-1.12.1/index.html,sha256=5g7_MLZlkh92FXWOR0q02My8knssXq20DXz-BkiYiP4,32588
matplotlib/backends/web_backend/jquery-ui-1.12.1/jquery-ui.css,sha256=p6xU9YulB7E2Ic62_PX-h59ayb3PBJ0WFTEQxq0EjHw,37326
matplotlib/backends/web_backend/jquery-ui-1.12.1/jquery-ui.js,sha256=T0Vest3yCU7pafRw9r-settMBX6JkKN06dqBnpQ8d30,520714
matplotlib/backends/web_backend/jquery-ui-1.12.1/jquery-ui.min.css,sha256=rByPlHULObEjJ6XQxW_flG2r-22R5dKiAoef-aXWfik,32076
matplotlib/backends/web_backend/jquery-ui-1.12.1/jquery-ui.min.js,sha256=KM512VNnjElC30ehFwehXjx1YCHPiQkOPmqnrWtpccM,253669
matplotlib/backends/web_backend/jquery-ui-1.12.1/jquery-ui.structure.css,sha256=E1uqV-d412nbSI-oqDMIQsTSttP-FS7Bxwc7mQdQYOo,18705
matplotlib/backends/web_backend/jquery-ui-1.12.1/jquery-ui.structure.min.css,sha256=rxais37anKUnpL5QzSYte-JnIsmkGmLG-ZhKSkZkwVM,15548
matplotlib/backends/web_backend/jquery-ui-1.12.1/jquery-ui.theme.css,sha256=mEMD30TTg-vIEGUmHHgcgSOgm0FBfLipyQ97Jr0TTH8,18671
matplotlib/backends/web_backend/jquery-ui-1.12.1/jquery-ui.theme.min.css,sha256=AjyoyaRtnGVTywKH_Isxxu5PXI0s4CcE0BzPAX83Ppc,13849
matplotlib/backends/web_backend/jquery-ui-1.12.1/package.json,sha256=kjEW8xMYuqRSwEE58KqTDNLgkx_6YL7tb1M9vlMK98w,1847
matplotlib/backends/web_backend/js/mpl.js,sha256=xrBOaet7K2P2iq7wgIexceDdc9T_WFb4TPJXDX55JuU,16991
matplotlib/backends/web_backend/js/mpl_tornado.js,sha256=lSxC7-yqF1GYY-6SheaHanx6SujMdcG7Vx2_3qbi-9Q,272
matplotlib/backends/web_backend/js/nbagg_mpl.js,sha256=nqIF0zFBQGpOo5Tmq2uRkyFJDeali66PWQDSYySgpnQ,7428
matplotlib/backends/web_backend/nbagg_uat.ipynb,sha256=y1N8hQzBJ05rJ2hZla2_Mw6tOUfNP1UHKo636W1e098,15933
matplotlib/backends/web_backend/single_figure.html,sha256=-iFrlIsaY1rOK9bNiDxcX8fdc0WP7DXXq-MEuLYfOvM,1216
matplotlib/bezier.py,sha256=Fqb2gqRnmS2wYjEZVFcdSngRxh5g_hFnxX82RFpimec,17271
matplotlib/blocking_input.py,sha256=soMcLeXT2mKxkH5fyQqYEOP_Dd-TUjoA1_L7imb2B2Q,11105
matplotlib/category.py,sha256=_iJbNlZzi3kqPtz_bhEBCj8q6RsBp5Urd3yNS81dOQg,7131
matplotlib/cbook/__init__.py,sha256=k7_Gdpbg26mrQlfQJr3eTnRGvXInhfuEjWeBrY5-IlY,70426
matplotlib/cbook/__pycache__/__init__.cpython-37.pyc,,
matplotlib/cbook/__pycache__/deprecation.cpython-37.pyc,,
matplotlib/cbook/deprecation.py,sha256=E8xSJYv-br0VswU-LNQFTU0VlurdH6v2rNOMCvOfs2I,15080
matplotlib/cm.py,sha256=qo1ZhJvKa7dCfALcj1X6rsy7R60pbJht7zK6pi_9EcA,12623
matplotlib/collections.py,sha256=n_Mru2nfEhqvAGHAD3g_JhWAoxvtK5MjYFLfztvSK3s,74328
matplotlib/colorbar.py,sha256=gaI17iRKX4NntEaLROYsg4q1fXUboda2L0w7PUaWSKg,63074
matplotlib/colors.py,sha256=auWiOGPMdI5twHSoVVI0AyEe7O9LJfn3fKetp_8yMzA,75537
matplotlib/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
matplotlib/compat/__pycache__/__init__.cpython-37.pyc,,
matplotlib/container.py,sha256=yAq9s8ylaQxkt2N-qTSnBdF7zQZ5_-g96XgKzlySaLI,4302
matplotlib/contour.py,sha256=p8PJvj7N7wd-yA94NP7cz230VHmYG3rkSsdYSoTP4hE,68387
matplotlib/dates.py,sha256=hGrXqJ-O1ahP2yCYK0HjFWJu0jt-EDke1S33VZ2uOe0,66867
matplotlib/docstring.py,sha256=TuDl6xhQwCISvIV5_rPKvT85V1k1IA5HVSyK-JMY9k4,3970
matplotlib/dviread.py,sha256=sO5Mq6CkNYqgu5S3oMcDc6Gqh1YhD36VoRWH9PbbIJw,39009
matplotlib/figure.py,sha256=yQsOCdFl3HHez8H3Y6xylSKAAEZzy-Hl-b1-BSJ3r8k,100886
matplotlib/font_manager.py,sha256=OZ2BAmPgFrO4VjeBA-DKGM0H0I5T4ev5gtAdirbXwR0,45282
matplotlib/fontconfig_pattern.py,sha256=El7xTXT3EnEESVONX9bKz_Yvaq4lLQp3KIYBgNbAguI,6719
matplotlib/ft2font.cpython-37m-x86_64-linux-gnu.so,sha256=titw2vLp_Ik6oZW2WqHUe-BXW8d7U1vIQgiAQEyWqgg,919008
matplotlib/gridspec.py,sha256=k_YO0Enho4Ztxi9-rv-ZgSXs-rrqKq1TdeOGwOzJwQI,25046
matplotlib/hatch.py,sha256=6AcnVeBs4d_Uv_FWQoU48v28iW5F7oKI_RKkv68L_WM,6971
matplotlib/image.py,sha256=0FR_I8bEV0XfM6kYyAS8j965LCbtapgnpxDWLrEV390,62787
matplotlib/legend.py,sha256=QBSq0VyGWFsTB7QFGx8bpmUR-MLw9xJPrhMcJSlpVtU,48268
matplotlib/legend_handler.py,sha256=hDMDvDJepK6UUyTJCkGQcAMVgLYW7eD16hQoQNVGQFY,26428
matplotlib/lines.py,sha256=8u3vEQXb_ceOivl4zyL5MIDuVDlxgZwOsH9xf37OIYo,51362
matplotlib/markers.py,sha256=Xpuq9O1t7OB3DBK2nZa4IbPjqV0ROGY9mxXW_NUKDKk,32533
matplotlib/mathtext.py,sha256=udfWXa-87xV1Mhve65rO0jf5On3DAQwJ-FgD6BSojhM,120491
matplotlib/mlab.py,sha256=1V0nvAkZF5RJbsIAp3AfTgzim2wRQCql0FCq7HvLknI,49040
matplotlib/mpl-data/fonts/afm/cmex10.afm,sha256=blR3ERmrVBV5XKkAnDCj4NMeYVgzH7cXtJ3u59u9GuE,12070
matplotlib/mpl-data/fonts/afm/cmmi10.afm,sha256=5qwEOpedEo76bDUahyuuF1q0cD84tRrX-VQ4p3MlfBo,10416
matplotlib/mpl-data/fonts/afm/cmr10.afm,sha256=WDvgC_D3UkGJg9u-J0U6RaT02lF4oz3lQxHtg1r3lYw,10101
matplotlib/mpl-data/fonts/afm/cmsy10.afm,sha256=AbmzvCVWBceHRfmRfeJ9E6xzOQTFLk0U1zDfpf3_MaM,8295
matplotlib/mpl-data/fonts/afm/cmtt10.afm,sha256=4ji7_mTpeWMa93o_UHBWPKCnqsBfhJJNllat1lJArP4,6501
matplotlib/mpl-data/fonts/afm/pagd8a.afm,sha256=jjFrigwkTpYLqa26cpzZvKQNBo-PuF4bmDVqaM4pMWw,17183
matplotlib/mpl-data/fonts/afm/pagdo8a.afm,sha256=sgNQdeYyx8J-itGw9h31y95aMBiTCRvmNSPTXwwS7xg,17255
matplotlib/mpl-data/fonts/afm/pagk8a.afm,sha256=ZUtfHPloNqcvGMHMxaKDSlshhOcjwheUx143RwpGdIU,17241
matplotlib/mpl-data/fonts/afm/pagko8a.afm,sha256=Yj1wBg6Jsqqz1KBfhRoJ3ACR-CMQol8Fj_ZM5NZ1gDk,17346
matplotlib/mpl-data/fonts/afm/pbkd8a.afm,sha256=Zl5o6J_di9Y5j2EpHtjew-_sfg7-WoeVmO9PzOYSTUc,15157
matplotlib/mpl-data/fonts/afm/pbkdi8a.afm,sha256=JAOno930iTyfZILMf11vWtiaTgrJcPpP6FRTRhEMMD4,15278
matplotlib/mpl-data/fonts/afm/pbkl8a.afm,sha256=UJqJjOJ6xQDgDBLX157mKpohIJFVmHM-N6x2-DiGv14,15000
matplotlib/mpl-data/fonts/afm/pbkli8a.afm,sha256=AWislZ2hDbs0ox_qOWREugsbS8_8lpL48LPMR40qpi0,15181
matplotlib/mpl-data/fonts/afm/pcrb8a.afm,sha256=6j1TS2Uc7DWSc-8l42TGDc1u0Fg8JspeWfxFayjUwi8,15352
matplotlib/mpl-data/fonts/afm/pcrbo8a.afm,sha256=smg3mjl9QaBDtQIt06ko5GvaxLsO9QtTvYANuE5hfG0,15422
matplotlib/mpl-data/fonts/afm/pcrr8a.afm,sha256=7nxFr0Ehz4E5KG_zSE5SZOhxRH8MyfnCbw-7x5wu7tw,15339
matplotlib/mpl-data/fonts/afm/pcrro8a.afm,sha256=NKEz7XtdFkh9cA8MvY-S3UOZlV2Y_J3tMEWFFxj7QSg,15443
matplotlib/mpl-data/fonts/afm/phvb8a.afm,sha256=NAx4M4HjL7vANCJbc-tk04Vkol-T0oaXeQ3T2h-XUvM,17155
matplotlib/mpl-data/fonts/afm/phvb8an.afm,sha256=8e_myD-AQkNF7q9XNLb2m76_lX2TUr3a5wog_LIE1sk,17086
matplotlib/mpl-data/fonts/afm/phvbo8a.afm,sha256=8fkBRmJ-SWY2YrBg8fFyjJyrJp8daQ6JPO6LvhM8xPI,17230
matplotlib/mpl-data/fonts/afm/phvbo8an.afm,sha256=aeVRvV4r15BBvxuRJ0MG8ZHuH2HViuIiCYkvuapmkmM,17195
matplotlib/mpl-data/fonts/afm/phvl8a.afm,sha256=IyMYM-bgl-gI6rG0EuZZ2OLzlxJfGeSh8xqsh0t-eJQ,15627
matplotlib/mpl-data/fonts/afm/phvlo8a.afm,sha256=s12C-eNnIDHJ_UVbuiprjxBjCiHIbS3Y8ORTC-qTpuI,15729
matplotlib/mpl-data/fonts/afm/phvr8a.afm,sha256=Kt8KaRidts89EBIK29X2JomDUEDxvroeaJz_RNTi6r4,17839
matplotlib/mpl-data/fonts/afm/phvr8an.afm,sha256=lL5fAHTRwODl-sB5mH7IfsD1tnnea4yRUK-_Ca2bQHM,17781
matplotlib/mpl-data/fonts/afm/phvro8a.afm,sha256=3KqK3eejiR4hIFBUynuSX_4lMdE2V2T58xOF8lX-fwc,17919
matplotlib/mpl-data/fonts/afm/phvro8an.afm,sha256=Vx9rRf3YfasMY7tz-njSxz67xHKk-fNkN7yBi0X2IP0,17877
matplotlib/mpl-data/fonts/afm/pncb8a.afm,sha256=aoXepTcDQtQa_mspflMJkEFKefzXHoyjz6ioJVI0YNc,16028
matplotlib/mpl-data/fonts/afm/pncbi8a.afm,sha256=pCWW1MYgy0EmvwaYsaYJaAI_LfrsKmDANHu7Pk0RaiU,17496
matplotlib/mpl-data/fonts/afm/pncr8a.afm,sha256=0CIB2BLe9r-6_Wl5ObRTTf98UOrezmGQ8ZOuBX5kLks,16665
matplotlib/mpl-data/fonts/afm/pncri8a.afm,sha256=5R-pLZOnaHNG8pjV6MP3Ai-d2OTQYR_cYCb5zQhzfSU,16920
matplotlib/mpl-data/fonts/afm/pplb8a.afm,sha256=3EzUbNnXr5Ft5eFLY00W9oWu59rHORgDXUuJaOoKN58,15662
matplotlib/mpl-data/fonts/afm/pplbi8a.afm,sha256=X_9tVspvrcMer3OS8qvdwjFFqpAXYZneyCL2NHA902g,15810
matplotlib/mpl-data/fonts/afm/pplr8a.afm,sha256=ijMb497FDJ9nVdVMb21F7W3-cu9sb_9nF0oriFpSn8k,15752
matplotlib/mpl-data/fonts/afm/pplri8a.afm,sha256=8KITbarcUUMi_hdoRLLmNHtlqs0TtOSKqtPFft7X5nY,15733
matplotlib/mpl-data/fonts/afm/psyr.afm,sha256=Iyt8ajE4B2Tm34oBj2pKtctIf9kPfq05suQefq8p3Ro,9644
matplotlib/mpl-data/fonts/afm/ptmb8a.afm,sha256=bL1fA1NC4_nW14Zrnxz4nHlXJb4dzELJPvodqKnYeMg,17983
matplotlib/mpl-data/fonts/afm/ptmbi8a.afm,sha256=-_Ui6XlKaFTHEnkoS_-1GtIr5VtGa3gFQ2ezLOYHs08,18070
matplotlib/mpl-data/fonts/afm/ptmr8a.afm,sha256=IEcsWcmzJyjCwkgsw4o6hIMmzlyXUglJat9s1PZNnEU,17942
matplotlib/mpl-data/fonts/afm/ptmri8a.afm,sha256=49fQMg5fIGguZ7rgc_2styMK55Pv5bPTs7wCzqpcGpk,18068
matplotlib/mpl-data/fonts/afm/putb8a.afm,sha256=qMaHTdpkrNL-m4DWhjpxJCSmgYkCv1qIzLlFfM0rl40,21532
matplotlib/mpl-data/fonts/afm/putbi8a.afm,sha256=g7AVJyiTxeMpNk_1cSfmYgM09uNUfPlZyWGv3D1vcAk,21931
matplotlib/mpl-data/fonts/afm/putr8a.afm,sha256=XYmNC5GQgSVAZKTIYdYeNksE6znNm9GF_0SmQlriqx0,22148
matplotlib/mpl-data/fonts/afm/putri8a.afm,sha256=i7fVe-iLyLtQxCfAa4IxdxH-ufcHmMk7hbCGG5TxAY4,21891
matplotlib/mpl-data/fonts/afm/pzcmi8a.afm,sha256=wyuoIWEZOcoXrSl1tPzLkEahik7kGi91JJj-tkFRG4A,16250
matplotlib/mpl-data/fonts/afm/pzdr.afm,sha256=MyjLAnzKYRdQBfof1W3k_hf30MvqOkqL__G22mQ5xww,9467
matplotlib/mpl-data/fonts/pdfcorefonts/Courier-Bold.afm,sha256=sIDDI-B82VZ3C0mI_mHFITCZ7PVn37AIYMv1CrHX4sE,15333
matplotlib/mpl-data/fonts/pdfcorefonts/Courier-BoldOblique.afm,sha256=zg61QobD3YU9UBfCXmvmhBNaFKno-xj8sY0b2RpgfLw,15399
matplotlib/mpl-data/fonts/pdfcorefonts/Courier-Oblique.afm,sha256=vRQm5j1sTUN4hicT1PcVZ9P9DTTUHhEzfPXqUUzVZhE,15441
matplotlib/mpl-data/fonts/pdfcorefonts/Courier.afm,sha256=Mdcq2teZEBJrIqVXnsnhee7oZnTs6-P8_292kWGTrw4,15335
matplotlib/mpl-data/fonts/pdfcorefonts/Helvetica-Bold.afm,sha256=i2l4gcjuYXoXf28uK7yIVwuf0rnw6J7PwPVQeHj5iPw,69269
matplotlib/mpl-data/fonts/pdfcorefonts/Helvetica-BoldOblique.afm,sha256=Um5O6qK11DXLt8uj_0IoWkc84TKqHK3bObSKUswQqvY,69365
matplotlib/mpl-data/fonts/pdfcorefonts/Helvetica-Oblique.afm,sha256=hVYDg2b52kqtbVeCzmiv25bW1yYdpkZS-LXlGREN2Rs,74392
matplotlib/mpl-data/fonts/pdfcorefonts/Helvetica.afm,sha256=23cvKDD7bQAJB3kdjSahJSTZaUOppznlIO6FXGslyW8,74292
matplotlib/mpl-data/fonts/pdfcorefonts/Symbol.afm,sha256=P5UaoXr4y0qh4SiMa5uqijDT6ZDr2-jPmj1ayry593E,9740
matplotlib/mpl-data/fonts/pdfcorefonts/Times-Bold.afm,sha256=cQTmr2LFPwKQE_sGQageMcmFicjye16mKJslsJLHQyE,64251
matplotlib/mpl-data/fonts/pdfcorefonts/Times-BoldItalic.afm,sha256=pzWOdycm6RqocBWgAVY5Jq0z3Fp7LuqWgLNMx4q6OFw,59642
matplotlib/mpl-data/fonts/pdfcorefonts/Times-Italic.afm,sha256=bK5puSMpGT_YUILwyJrXoxjfj7XJOdfv5TQ_iKsJRzw,66328
matplotlib/mpl-data/fonts/pdfcorefonts/Times-Roman.afm,sha256=hhNrUnpazuDDKD1WpraPxqPWCYLrO7D7bMVOg-zI13o,60460
matplotlib/mpl-data/fonts/pdfcorefonts/ZapfDingbats.afm,sha256=ZuOmt9GcKofjdOq8kqhPhtAIhOwkL2rTJTmZxAjFakA,9527
matplotlib/mpl-data/fonts/pdfcorefonts/readme.txt,sha256=MRv8ppSITYYAb7lt5EOw9DWWNZIblfxsFhu5TQE7cpI,828
matplotlib/mpl-data/fonts/ttf/DejaVuSans-Bold.ttf,sha256=sYS4njwQdfIva3FXW2_CDUlys8_TsjMiym_Vltyu8Wc,704128
matplotlib/mpl-data/fonts/ttf/DejaVuSans-BoldOblique.ttf,sha256=bt8CgxYBhq9FHL7nHnuEXy5Mq_Jku5ks5mjIPCVGXm8,641720
matplotlib/mpl-data/fonts/ttf/DejaVuSans-Oblique.ttf,sha256=zN90s1DxH9PdV3TeUOXmNGoaXaH1t9X7g1kGZel6UhM,633840
matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf,sha256=P99pyr8GBJ6nCgC1kZNA4s4ebQKwzDxLRPtoAb0eDSI,756072
matplotlib/mpl-data/fonts/ttf/DejaVuSansDisplay.ttf,sha256=ggmdz7paqGjN_CdFGYlSX-MpL3N_s8ngMozpzvWWUvY,25712
matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-Bold.ttf,sha256=uq2ppRcv4giGJRr_BDP8OEYZEtXa8HKH577lZiCo2pY,331536
matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-BoldOblique.ttf,sha256=ppCBwVx2yCfgonpaf1x0thNchDSZlVSV_6jCDTqYKIs,253116
matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-Oblique.ttf,sha256=KAUoE_enCfyJ9S0ZLcmV708P3Fw9e3OknWhJsZFtDNA,251472
matplotlib/mpl-data/fonts/ttf/DejaVuSansMono.ttf,sha256=YC7Ia4lIz82VZIL-ZPlMNshndwFJ7y95HUYT9EO87LM,340240
matplotlib/mpl-data/fonts/ttf/DejaVuSerif-Bold.ttf,sha256=w3U_Lta8Zz8VhG3EWt2-s7nIcvMvsY_VOiHxvvHtdnY,355692
matplotlib/mpl-data/fonts/ttf/DejaVuSerif-BoldItalic.ttf,sha256=2T7-x6nS6CZ2jRou6VuVhw4V4pWZqE80hK8d4c7C4YE,347064
matplotlib/mpl-data/fonts/ttf/DejaVuSerif-Italic.ttf,sha256=PnmU-8VPoQzjNSpC1Uj63X2crbacsRCbydlg9trFfwQ,345612
matplotlib/mpl-data/fonts/ttf/DejaVuSerif.ttf,sha256=EHJElW6ZYrnpb6zNxVGCXgrgiYrhNzcTPhuSGi_TX_o,379740
matplotlib/mpl-data/fonts/ttf/DejaVuSerifDisplay.ttf,sha256=KRTzLkfHd8J75Wd6-ufbTeefnkXeb8kJfZlJwjwU99U,14300
matplotlib/mpl-data/fonts/ttf/LICENSE_DEJAVU,sha256=11k43sCY8G8Kw8AIUwZdlPAgvhw8Yu8dwpdboVtNmw4,4816
matplotlib/mpl-data/fonts/ttf/LICENSE_STIX,sha256=cxFOZdp1AxNhXR6XxCzf5iJpNcu-APm-geOHhD-s0h8,5475
matplotlib/mpl-data/fonts/ttf/STIXGeneral.ttf,sha256=FnN4Ax4t3cYhbWeBnJJg6aBv_ExHjk4jy5im_USxg8I,448228
matplotlib/mpl-data/fonts/ttf/STIXGeneralBol.ttf,sha256=6FM9xwg_o0a9oZM9YOpKg7Z9CUW86vGzVB-CtKDixqA,237360
matplotlib/mpl-data/fonts/ttf/STIXGeneralBolIta.ttf,sha256=mHiP1LpI37sr0CbA4gokeosGxzcoeWKLemuw1bsJc2w,181152
matplotlib/mpl-data/fonts/ttf/STIXGeneralItalic.ttf,sha256=bPyzM9IrfDxiO9_UAXTxTIXD1nMcphZsHtyAFA6uhSc,175040
matplotlib/mpl-data/fonts/ttf/STIXNonUni.ttf,sha256=Ulb34CEzWsSFTRgPDovxmJZOwvyCAXYnbhaqvGU3u1c,59108
matplotlib/mpl-data/fonts/ttf/STIXNonUniBol.ttf,sha256=XRBqW3jR_8MBdFU0ObhiV7-kXwiBIMs7QVClHcT5tgs,30512
matplotlib/mpl-data/fonts/ttf/STIXNonUniBolIta.ttf,sha256=pb22DnbDf2yQqizotc3wBDqFGC_g27YcCGJivH9-Le8,41272
matplotlib/mpl-data/fonts/ttf/STIXNonUniIta.ttf,sha256=BMr9pWiBv2YIZdq04X4c3CgL6NPLUPrl64aV1N4w9Ug,46752
matplotlib/mpl-data/fonts/ttf/STIXSizFiveSymReg.ttf,sha256=wYuH1gYUpCuusqItRH5kf9p_s6mUD-9X3L5RvRtKSxs,13656
matplotlib/mpl-data/fonts/ttf/STIXSizFourSymBol.ttf,sha256=yNdvjUoSmsZCULmD7SVq9HabndG9P4dPhboL1JpAf0s,12228
matplotlib/mpl-data/fonts/ttf/STIXSizFourSymReg.ttf,sha256=-9xVMYL4_1rcO8FiCKrCfR4PaSmKtA42ddLGqwtei1w,15972
matplotlib/mpl-data/fonts/ttf/STIXSizOneSymBol.ttf,sha256=cYexyo8rZcdqMlpa9fNF5a2IoXLUTZuIvh0JD1Qp0i4,12556
matplotlib/mpl-data/fonts/ttf/STIXSizOneSymReg.ttf,sha256=0lbHzpndzJmO8S42mlkhsz5NbvJLQCaH5Mcc7QZRDzc,19760
matplotlib/mpl-data/fonts/ttf/STIXSizThreeSymBol.ttf,sha256=3eBc-VtYbhQU3BnxiypfO6eAzEu8BdDvtIJSFbkS2oY,12192
matplotlib/mpl-data/fonts/ttf/STIXSizThreeSymReg.ttf,sha256=XFSKCptbESM8uxHtUFSAV2cybwxhSjd8dWVByq6f3w0,15836
matplotlib/mpl-data/fonts/ttf/STIXSizTwoSymBol.ttf,sha256=MUCYHrA0ZqFiSE_PjIGlJZgMuv79aUgQqE7Dtu3kuo0,12116
matplotlib/mpl-data/fonts/ttf/STIXSizTwoSymReg.ttf,sha256=_sdxDuEwBDtADpu9CyIXQxV7sIqA2TZVBCUiUjq5UCk,15704
matplotlib/mpl-data/fonts/ttf/cmb10.ttf,sha256=B0SXtQxD6ldZcYFZH5iT04_BKofpUQT1ZX_CSB9hojo,25680
matplotlib/mpl-data/fonts/ttf/cmex10.ttf,sha256=ryjwwXByOsd2pxv6WVrKCemNFa5cPVTOGa_VYZyWqQU,21092
matplotlib/mpl-data/fonts/ttf/cmmi10.ttf,sha256=MJKWW4gR_WpnZXmWZIRRgfwd0TMLk3-RWAjEhdMWI00,32560
matplotlib/mpl-data/fonts/ttf/cmr10.ttf,sha256=Tdl2GwWMAJ25shRfVe5mF9CTwnPdPWxbPkP_YRD6m_Y,26348
matplotlib/mpl-data/fonts/ttf/cmss10.ttf,sha256=ffkag9BbLkcexjjLC0NaNgo8eSsJ_EKn2mfpHy55EVo,20376
matplotlib/mpl-data/fonts/ttf/cmsy10.ttf,sha256=uyJu2TLz8QDNDlL15JEu5VO0G2nnv9uNOFTbDrZgUjI,29396
matplotlib/mpl-data/fonts/ttf/cmtt10.ttf,sha256=YhHwmuk1mZka_alwwkZp2tGnfiU9kVYk-_IS9wLwcdc,28136
matplotlib/mpl-data/images/back.gif,sha256=sdkxFRAh-Mgs44DTvruO5OxcI3Av9CS1g5MqMA_DDkQ,608
matplotlib/mpl-data/images/back.pdf,sha256=ZR7CJo_dAeCM-KlaGvskgtHQyRtrPIolc8REOmcoqJk,1623
matplotlib/mpl-data/images/back.png,sha256=E4dGf4Gnz1xJ1v2tMygHV0YNQgShreDeVApaMb-74mU,380
matplotlib/mpl-data/images/back.svg,sha256=yRdMiKsa-awUm2x_JE_rEV20rNTa7FInbFBEoMo-6ik,1512
matplotlib/mpl-data/images/back_large.gif,sha256=tqCtecrxNrPuDCUj7FGs8UXWftljKcwgp5cSBBhXwiQ,799
matplotlib/mpl-data/images/back_large.png,sha256=9A6hUSQeszhYONE4ZuH3kvOItM0JfDVu6tkfromCbsQ,620
matplotlib/mpl-data/images/filesave.gif,sha256=wAyNwOPd9c-EIPwcUAlqHSfLmxq167nhDVppOWPy9UA,723
matplotlib/mpl-data/images/filesave.pdf,sha256=P1EPPV2g50WTt8UaX-6kFoTZM1xVqo6S2H6FJ6Zd1ec,1734
matplotlib/mpl-data/images/filesave.png,sha256=b7ctucrM_F2mG-DycTedG_a_y4pHkx3F-zM7l18GLhk,458
matplotlib/mpl-data/images/filesave.svg,sha256=oxPVbLS9Pzelz71C1GCJWB34DZ0sx_pUVPRHBrCZrGs,2029
matplotlib/mpl-data/images/filesave_large.gif,sha256=IXrenlwu3wwO8WTRvxHt_q62NF6ZWyqk3jZhm6GE-G8,1498
matplotlib/mpl-data/images/filesave_large.png,sha256=LNbRD5KZ3Kf7nbp-stx_a1_6XfGBSWUfDdpgmnzoRvk,720
matplotlib/mpl-data/images/forward.gif,sha256=VNL9R-dECOX7wUAYPtU_DWn5hwi3SwLR17DhmBvUIxE,590
matplotlib/mpl-data/images/forward.pdf,sha256=KIqIL4YId43LkcOxV_TT5uvz1SP8k5iUNUeJmAElMV8,1630
matplotlib/mpl-data/images/forward.png,sha256=pKbLepgGiGeyY2TCBl8svjvm7Z4CS3iysFxcq4GR-wk,357
matplotlib/mpl-data/images/forward.svg,sha256=NnQDOenfjsn-o0aJMUfErrP320Zcx9XHZkLh0cjMHsk,1531
matplotlib/mpl-data/images/forward_large.gif,sha256=H6Jbcc7qJwHJAE294YqI5Bm-5irofX40cKRvYdrG_Ig,786
matplotlib/mpl-data/images/forward_large.png,sha256=36h7m7DZDHql6kkdpNPckyi2LKCe_xhhyavWARz_2kQ,593
matplotlib/mpl-data/images/hand.gif,sha256=3lRfmAqQU7A2t1YXXsB9IbwzK7FaRh-IZO84D5-xCrw,1267
matplotlib/mpl-data/images/hand.pdf,sha256=hspwkNY915KPD7AMWnVQs7LFPOtlcj0VUiLu76dMabQ,4172
matplotlib/mpl-data/images/hand.png,sha256=2cchRETGKa0hYNKUxnJABwkyYXEBPqJy_VqSPlT0W2Q,979
matplotlib/mpl-data/images/hand.svg,sha256=tsVIES_nINrAbH4FqdsCGOx0SVE37vcofSYBhnnaOP0,4888
matplotlib/mpl-data/images/hand_large.gif,sha256=H5IHmVTvOqHQb9FZ_7g7AlPt9gv-zRq0L5_Q9B7OuvU,973
matplotlib/mpl-data/images/help.pdf,sha256=CeE978IMi0YWznWKjIT1R8IrP4KhZ0S7usPUvreSgcA,1813
matplotlib/mpl-data/images/help.png,sha256=s4pQrqaQ0py8I7vc9hv3BI3DO_tky-7YBMpaHuBDCBY,472
matplotlib/mpl-data/images/help.ppm,sha256=mVPvgwcddzCM-nGZd8Lnl_CorzDkRIXQE17b7qo8vlU,1741
matplotlib/mpl-data/images/help.svg,sha256=KXabvQhqIWen_t2SvZuddFYa3S0iI3W8cAKm3s1fI8Q,1870
matplotlib/mpl-data/images/help_large.png,sha256=1IwEyWfGRgnoCWM-r9CJHEogTJVD5n1c8LXTK4AJ4RE,747
matplotlib/mpl-data/images/help_large.ppm,sha256=MiCSKp1Su88FXOi9MTtkQDA2srwbX3w5navi6cneAi4,6925
matplotlib/mpl-data/images/home.gif,sha256=NKuFM7tTtFngdfsOpJ4AxYTL8PYS5GWKAoiJjBMwLlU,666
matplotlib/mpl-data/images/home.pdf,sha256=e0e0pI-XRtPmvUCW2VTKL1DeYu1pvPmUUeRSgEbWmik,1737
matplotlib/mpl-data/images/home.png,sha256=IcFdAAUa6_A0qt8IO3I8p4rpXpQgAlJ8ndBECCh7C1w,468
matplotlib/mpl-data/images/home.svg,sha256=n_AosjJVXET3McymFuHgXbUr5vMLdXK2PDgghX8Cch4,1891
matplotlib/mpl-data/images/home_large.gif,sha256=k86PJCgED46sCFkOlUYHA0s5U7OjRsc517bpAtU2JSw,1422
matplotlib/mpl-data/images/home_large.png,sha256=uxS2O3tWOHh1iau7CaVV4ermIJaZ007ibm5Z3i8kXYg,790
matplotlib/mpl-data/images/matplotlib.pdf,sha256=BkSUf-2xoij-eXfpV2t7y1JFKG1zD1gtV6aAg3Xi_wE,22852
matplotlib/mpl-data/images/matplotlib.png,sha256=w8KLRYVa-voUZXa41hgJauQuoois23f3NFfdc72pUYY,1283
matplotlib/mpl-data/images/matplotlib.svg,sha256=QiTIcqlQwGaVPtHsEk-vtmJk1wxwZSvijhqBe_b9VCI,62087
matplotlib/mpl-data/images/matplotlib_128.ppm,sha256=IHPRWXpLFRq3Vb7UjiCkFrN_N86lSPcfrEGunST08d8,49167
matplotlib/mpl-data/images/matplotlib_large.png,sha256=ElRoue9grUqkZXJngk-nvh4GKfpvJ4gE69WryjCbX5U,3088
matplotlib/mpl-data/images/move.gif,sha256=FN52MptH4FZiwmV2rQgYCO2FvO3m5LtqYv8jk6Xbeyk,679
matplotlib/mpl-data/images/move.pdf,sha256=CXk3PGK9WL5t-5J-G2X5Tl-nb6lcErTBS5oUj2St6aU,1867
matplotlib/mpl-data/images/move.png,sha256=TmjR41IzSzxGbhiUcV64X0zx2BjrxbWH3cSKvnG2vzc,481
matplotlib/mpl-data/images/move.svg,sha256=_ZKpcwGD6DMTkZlbyj0nQbT8Ygt5vslEZ0OqXaXGd4E,2509
matplotlib/mpl-data/images/move_large.gif,sha256=RMIAr-G9OOY7vWC04oN6qv5TAHJxhQGhLsw_bNsvWbg,951
matplotlib/mpl-data/images/move_large.png,sha256=Skjz2nW_RTA5s_0g88gdq2hrVbm6DOcfYW4Fu42Fn9U,767
matplotlib/mpl-data/images/qt4_editor_options.pdf,sha256=2qu6GVyBrJvVHxychQoJUiXPYxBylbH2j90QnytXs_w,1568
matplotlib/mpl-data/images/qt4_editor_options.png,sha256=EryQjQ5hh2dwmIxtzCFiMN1U6Tnd11p1CDfgH5ZHjNM,380
matplotlib/mpl-data/images/qt4_editor_options.svg,sha256=E00YoX7u4NrxMHm_L1TM8PDJ88bX5qRdCrO-Uj59CEA,1244
matplotlib/mpl-data/images/qt4_editor_options_large.png,sha256=-Pd-9Vh5aIr3PZa8O6Ge_BLo41kiEnpmkdDj8a11JkY,619
matplotlib/mpl-data/images/subplots.gif,sha256=QfhmUdcrko08-WtrzCJUjrVFDTvUZCJEXpARNtzEwkg,691
matplotlib/mpl-data/images/subplots.pdf,sha256=Q0syPMI5EvtgM-CE-YXKOkL9eFUAZnj_X2Ihoj6R4p4,1714
matplotlib/mpl-data/images/subplots.png,sha256=MUfCItq3_yzb9yRieGOglpn0Y74h8IA7m5i70B63iRc,445
matplotlib/mpl-data/images/subplots.svg,sha256=8acBogXIr9OWGn1iD6mUkgahdFZgDybww385zLCLoIs,2130
matplotlib/mpl-data/images/subplots_large.gif,sha256=Ff3ERmtVAaGP9i1QGUNnIIKac6LGuSW2Qf4DrockZSI,1350
matplotlib/mpl-data/images/subplots_large.png,sha256=Edu9SwVMQEXJZ5ogU5cyW7VLcwXJdhdf-EtxxmxdkIs,662
matplotlib/mpl-data/images/zoom_to_rect.gif,sha256=mTX6h9fh2W9zmvUYqeibK0TZ7qIMKOB1nAXMpD_jDys,696
matplotlib/mpl-data/images/zoom_to_rect.pdf,sha256=SEvPc24gfZRpl-dHv7nx8KkxPyU66Kq4zgQTvGFm9KA,1609
matplotlib/mpl-data/images/zoom_to_rect.png,sha256=aNz3QZBrIgxu9E-fFfaQweCVNitGuDUFoC27e5NU2L4,530
matplotlib/mpl-data/images/zoom_to_rect.svg,sha256=1vRxr3cl8QTwTuRlQzD1jxu0fXZofTJ2PMgG97E7Bco,1479
matplotlib/mpl-data/images/zoom_to_rect_large.gif,sha256=nx5LUpTAH6ZynM3ZfZDS-wR87jbMUsUnyQ27NGkV0_c,1456
matplotlib/mpl-data/images/zoom_to_rect_large.png,sha256=V6pkxmm6VwFExdg_PEJWdK37HB7k3cE_corLa7RbUMk,1016
matplotlib/mpl-data/matplotlibrc,sha256=ZDuS3NjqmSy4_oIXNk9mMNcD74ExJ9clpz6fbgSVMCk,40282
matplotlib/mpl-data/sample_data/Minduka_Present_Blue_Pack.png,sha256=XnKGiCanpDKalQ5anvo5NZSAeDP7fyflzQAaivuc0IE,13634
matplotlib/mpl-data/sample_data/None_vs_nearest-pdf.png,sha256=5CPvcG3SDNfOXx39CMKHCNS9JKZ-fmOUwIfpppNXsQ0,106228
matplotlib/mpl-data/sample_data/README.txt,sha256=ABz19VBKfGewdY39QInG9Qccgn1MTYV3bT5Ph7TCy2Y,128
matplotlib/mpl-data/sample_data/aapl.npz,sha256=GssVYka_EccteiXbNRJJ5GsuqU7G8F597qX7srYXZsw,107503
matplotlib/mpl-data/sample_data/ada.png,sha256=X1hjJK1_1Nc8DN-EEhey3G7Sq8jBwQDKNSl4cCAE0uY,308313
matplotlib/mpl-data/sample_data/axes_grid/bivariate_normal.npy,sha256=DpWZ9udAh6ospYqneEa27D6EkRgORFwHosacZXVu98U,1880
matplotlib/mpl-data/sample_data/ct.raw.gz,sha256=LDvvgH-mycRQF2D29-w5MW94ZI0opvwKUoFI8euNpMk,256159
matplotlib/mpl-data/sample_data/data_x_x2_x3.csv,sha256=A0SU3buOUGhT-NI_6LQ6p70fFSIU3iLFdgzvzrKR6SE,132
matplotlib/mpl-data/sample_data/demodata.csv,sha256=MRybziqnyrqMCH9qG7Mr6BwcohIhftVG5dejXV2AX2M,659
matplotlib/mpl-data/sample_data/eeg.dat,sha256=KGVjFt8ABKz7p6XZirNfcxSTOpGGNuyA8JYErRKLRBc,25600
matplotlib/mpl-data/sample_data/embedding_in_wx3.xrc,sha256=cUqVw5vDHNSZoaO4J0ebZUf5SrJP36775abs7R9Bclg,2186
matplotlib/mpl-data/sample_data/goog.npz,sha256=QAkXzzDmtmT3sNqT18dFhg06qQCNqLfxYNLdEuajGLE,22845
matplotlib/mpl-data/sample_data/grace_hopper.jpg,sha256=qMptc0dlcDsJcoq0f-WfRz2Trjln_CTHwCiMPHrbcTA,61306
matplotlib/mpl-data/sample_data/grace_hopper.png,sha256=MCf0ju2kpC40srQ0xw4HEyOoKhLL4khP3jHfU9_dR7s,628280
matplotlib/mpl-data/sample_data/jacksboro_fault_dem.npz,sha256=1JP1CjPoKkQgSUxU0fyhU50Xe9wnqxkLxf5ukvYvtjc,174061
matplotlib/mpl-data/sample_data/logo2.png,sha256=ITxkJUsan2oqXgJDy6DJvwJ4aHviKeWGnxPkTjXUt7A,33541
matplotlib/mpl-data/sample_data/membrane.dat,sha256=q3lbQpIBpbtXXGNw1eFwkN_PwxdDGqk4L46IE2b0M1c,48000
matplotlib/mpl-data/sample_data/msft.csv,sha256=GArKb0O3DgKZRsKdJf6lX3rMSf-PCekIiBoLNdgF7Mk,3211
matplotlib/mpl-data/sample_data/percent_bachelors_degrees_women_usa.csv,sha256=TzoqamsV_N3d3lW7SKmj14zZVX4FOOg9jJcsC5U9pbA,5681
matplotlib/mpl-data/sample_data/s1045.ima.gz,sha256=MrQk1k9it-ccsk0p_VOTitVmTWCAVaZ6srKvQ2n4uJ4,33229
matplotlib/mpl-data/sample_data/topobathy.npz,sha256=AkTgMpFwLfRQJNy1ysvE89TLMNct-n_TccSsYcQrT78,45224
matplotlib/mpl-data/stylelib/Solarize_Light2.mplstyle,sha256=PECeO60wwJe2sSDvxapBJRuKGek0qLcoaN8qOX6tgNQ,1255
matplotlib/mpl-data/stylelib/_classic_test_patch.mplstyle,sha256=iopHpMaM3im_AK2aiHGuM2DKM5i9Kc84v6NQEoSb10Q,167
matplotlib/mpl-data/stylelib/bmh.mplstyle,sha256=-KbhaI859BITHIoyUZIfpQDjfckgLAlDAS_ydKsm6mc,712
matplotlib/mpl-data/stylelib/classic.mplstyle,sha256=0RjtrDi0vZOzWGnt9cme_At_9GqMwHzwEBCAH9OQZ7I,24511
matplotlib/mpl-data/stylelib/dark_background.mplstyle,sha256=-EGmoFm_35Zk7oRp29UalT56HsOSuJbYMeQGdAATnz4,477
matplotlib/mpl-data/stylelib/fast.mplstyle,sha256=yTa2YEIIP9xi5V_G0p2vSlxghuhNwjRi9gPECMxyRiM,288
matplotlib/mpl-data/stylelib/fivethirtyeight.mplstyle,sha256=WNUmAFuBPcqQPVgt6AS1ldy8Be2XO01N-1YQL__Q6ZY,832
matplotlib/mpl-data/stylelib/ggplot.mplstyle,sha256=xhjLwr8hiikEXKy8APMy0Bmvtz1g0WnG84gX7e9lArs,957
matplotlib/mpl-data/stylelib/grayscale.mplstyle,sha256=KCLg-pXpns9cnKDXKN2WH6mV41OH-6cbT-5zKQotSdw,526
matplotlib/mpl-data/stylelib/seaborn-bright.mplstyle,sha256=pDqn3-NUyVLvlfkYs8n8HzNZvmslVMChkeH-HtZuJIc,144
matplotlib/mpl-data/stylelib/seaborn-colorblind.mplstyle,sha256=eCSzFj5_2vR6n5qu1rHE46wvSVGZcdVqz85ov40ZsH8,148
matplotlib/mpl-data/stylelib/seaborn-dark-palette.mplstyle,sha256=p5ABKNQHRG7bk4HXqMQrRBjDlxGAo3RCXHdQmP7g-Ng,142
matplotlib/mpl-data/stylelib/seaborn-dark.mplstyle,sha256=I4xQ75vE5_9X4k0cNDiqhhnF3OcrZ2xlPX8Ll7OCkoE,667
matplotlib/mpl-data/stylelib/seaborn-darkgrid.mplstyle,sha256=2bXOSzS5gmPzRBrRmzVWyhg_7ZaBRQ6t_-O-cRuyZoA,670
matplotlib/mpl-data/stylelib/seaborn-deep.mplstyle,sha256=44dLcXjjRgR-6yaopgGRInaVgz3jk8VJVQTbBIcxRB0,142
matplotlib/mpl-data/stylelib/seaborn-muted.mplstyle,sha256=T4o3jvqKD_ImXDkp66XFOV_xrBVFUolJU34JDFk1Xkk,143
matplotlib/mpl-data/stylelib/seaborn-notebook.mplstyle,sha256=PcvZQbYrDdducrNlavBPmQ1g2minio_9GkUUFRdgtoM,382
matplotlib/mpl-data/stylelib/seaborn-paper.mplstyle,sha256=n0mboUp2C4Usq2j6tNWcu4TZ_YT4-kKgrYO0t-rz1yw,393
matplotlib/mpl-data/stylelib/seaborn-pastel.mplstyle,sha256=8nV8qRpbUrnFZeyE6VcQ1oRuZPLil2W74M2U37DNMOE,144
matplotlib/mpl-data/stylelib/seaborn-poster.mplstyle,sha256=dUaKqTE4MRfUq2rWVXbbou7kzD7Z9PE9Ko8aXLza8JA,403
matplotlib/mpl-data/stylelib/seaborn-talk.mplstyle,sha256=7FnBaBEdWBbncTm6_ER-EQVa_bZgU7dncgez-ez8R74,403
matplotlib/mpl-data/stylelib/seaborn-ticks.mplstyle,sha256=CITZmZFUFp40MK2Oz8tI8a7WRoCizQU9Z4J172YWfWw,665
matplotlib/mpl-data/stylelib/seaborn-white.mplstyle,sha256=WjJ6LEU6rlCwUugToawciAbKP9oERFHr9rfFlUrdTx0,665
matplotlib/mpl-data/stylelib/seaborn-whitegrid.mplstyle,sha256=ec4BjsNzmOvHptcJ3mdPxULF3S1_U1EUocuqfIpw-Nk,664
matplotlib/mpl-data/stylelib/seaborn.mplstyle,sha256=_Xu6qXKzi4b3GymCOB1b1-ykKTQ8xhDliZ8ezHGTiAs,1130
matplotlib/mpl-data/stylelib/tableau-colorblind10.mplstyle,sha256=BsirZVd1LmPWT4tBIz6loZPjZcInoQrIGfC7rvzqmJw,190
matplotlib/offsetbox.py,sha256=1oReQSHV50aRsHqHIa3Km234FXx8sUZRLdiGbdGu2zU,58812
matplotlib/patches.py,sha256=4JTt8OKfTg_BzSQVXYjsQLAFbZvvzR9T-1zsajaPpx8,151886
matplotlib/path.py,sha256=ov2ghbmWhCV-PhxUPGEfsG409Nrkf9HP4u7oQSpGFtc,37640
matplotlib/patheffects.py,sha256=ERzaWP5RZTnaEVWx77c8oB-JQeMpVJtY-hBdRqkQ4ZM,13235
matplotlib/projections/__init__.py,sha256=4b447LtxkDz1nC1B9tb_J7cCpq1fjxwaEvzkHy-Y3KA,1816
matplotlib/projections/__pycache__/__init__.cpython-37.pyc,,
matplotlib/projections/__pycache__/geo.cpython-37.pyc,,
matplotlib/projections/__pycache__/polar.cpython-37.pyc,,
matplotlib/projections/geo.py,sha256=OrTW_dk4QqrTv9lYBean9uz24MBIWyWcnkADyTOdNuc,17690
matplotlib/projections/polar.py,sha256=1aHOdhpaJKpu5BNS2eRoeIgej-QUunRpIGcxXkv1s28,52508
matplotlib/pylab.py,sha256=VOs5onux2-yPGn0exAPsR75U9ty2hOzvg8Nz1K7TWBg,9595
matplotlib/pyplot.py,sha256=vM3sVw0yIb0EbehwlLAOWHfGnMSN4W9OfTDmcsBELvs,111042
matplotlib/quiver.py,sha256=B3CGGxSNVLwOPx2IgyG2DCSPQHs1MAS0o9sL_4Mm7rY,48018
matplotlib/rcsetup.py,sha256=BhPaDqHrifbncC47epnKBtvlkk-MzhNp1HlVYgcgvF8,58589
matplotlib/sankey.py,sha256=3PygeZ3h19RFICw1hL6qt5TwRoBrP1AKSznWvKHc6Z4,36986
matplotlib/scale.py,sha256=_G5Aq3ta2vc2WOLuL3_UlnZ8XsXbGRrwBuqAG_OxCxU,25209
matplotlib/sphinxext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
matplotlib/sphinxext/__pycache__/__init__.cpython-37.pyc,,
matplotlib/sphinxext/__pycache__/mathmpl.cpython-37.pyc,,
matplotlib/sphinxext/__pycache__/plot_directive.cpython-37.pyc,,
matplotlib/sphinxext/mathmpl.py,sha256=jTqwBfxLLGjx-4TwEzwYvi2WdCoJpqHfDcbLKrgcKss,4276
matplotlib/sphinxext/plot_directive.py,sha256=dAECzhJ1qVCq3nN3poGjKK2AAaAIwGikEHQIz_V0U0Y,26574
matplotlib/spines.py,sha256=Xl9hIsBHzYaGq79UQb3Amfwfrq1-ZNsiS4wpPwstbp8,21227
matplotlib/stackplot.py,sha256=fj4oqFbYA1G3RaTnV_Jic5mn5K3rza-JYp6jGR7e0yk,3917
matplotlib/streamplot.py,sha256=9zniqozPg42NfXk4bx_Ro2RlkYYuR2CEJwJfJkt7jtI,22641
matplotlib/style/__init__.py,sha256=EExOAUAq3u_rscUwkfKtZoEgLA5npmltCrYZOP9ftjw,67
matplotlib/style/__pycache__/__init__.cpython-37.pyc,,
matplotlib/style/__pycache__/core.cpython-37.pyc,,
matplotlib/style/core.py,sha256=EAubJQ90H__1bljwNfjpT8kxHp30r6KtXoveLvnfs4Q,8222
matplotlib/table.py,sha256=FXhhFOy_-ZkHwyphkjFBQku1WgDjR3iYlmV4Wvls0cY,26674
matplotlib/testing/__init__.py,sha256=MVV0ao_RHOKgDhpSN7QJBnyunje7tDeco-No_HtvvcQ,1428
matplotlib/testing/__pycache__/__init__.cpython-37.pyc,,
matplotlib/testing/__pycache__/compare.cpython-37.pyc,,
matplotlib/testing/__pycache__/conftest.cpython-37.pyc,,
matplotlib/testing/__pycache__/decorators.cpython-37.pyc,,
matplotlib/testing/__pycache__/disable_internet.cpython-37.pyc,,
matplotlib/testing/__pycache__/exceptions.cpython-37.pyc,,
matplotlib/testing/compare.py,sha256=67rAW447H4AUnGoT-AUP7s6CB2Q1N4oqhetFdvBdKZk,16969
matplotlib/testing/conftest.py,sha256=juolFb13qZ_jwO6DsOxkfCKuPmPsQwbY6Oznx76tLYo,4317
matplotlib/testing/decorators.py,sha256=t9XYPto5sIm4OObU5dyF6z5FjdhuNE2saBr-dnZ45wU,17704
matplotlib/testing/disable_internet.py,sha256=ovCho7Nu6w-uoJeUPjJS7XGKJN0ktSNyF6NODaEyjb4,4925
matplotlib/testing/exceptions.py,sha256=72QmjiHG7DwxSvlJf8mei-hRit5AH3NKh0-osBo4YbY,138
matplotlib/testing/jpl_units/Duration.py,sha256=Leomw6a4XHddFgqMoYj63HfxV_-u6_MuQ3iaQ26TJcg,4946
matplotlib/testing/jpl_units/Epoch.py,sha256=XpQMTIOs6VIVzuFYxRcv6JUuz4kqVCb1nGfBpYYbeJA,6305
matplotlib/testing/jpl_units/EpochConverter.py,sha256=TAhtAyDHvvxDJL036DWEXrkZl_CwpVl2y5FNXloAoxo,4067
matplotlib/testing/jpl_units/StrConverter.py,sha256=36hFTYbCM3Dh9_QR82dBbHh_7DSpsEthpnJYRICLlIc,4107
matplotlib/testing/jpl_units/UnitDbl.py,sha256=sL0U984sJmka_0gzp6uhxSJuxnuh77aDAjtfCYdYJZ0,7793
matplotlib/testing/jpl_units/UnitDblConverter.py,sha256=M5h3lOB4IEysqnR7VbkjUnMPS7wBtrZYWKvU3JUaJtI,4145
matplotlib/testing/jpl_units/UnitDblFormatter.py,sha256=CRcbPtE3K0FlFJ4hkhi-SgQl1MUV-VlmIeOPIEPNwuI,681
matplotlib/testing/jpl_units/__init__.py,sha256=Bp4Lz_eqRuxNWO_l3VvhuurFZaUmZIlvcF3N0UBmzHc,2692
matplotlib/testing/jpl_units/__pycache__/Duration.cpython-37.pyc,,
matplotlib/testing/jpl_units/__pycache__/Epoch.cpython-37.pyc,,
matplotlib/testing/jpl_units/__pycache__/EpochConverter.cpython-37.pyc,,
matplotlib/testing/jpl_units/__pycache__/StrConverter.cpython-37.pyc,,
matplotlib/testing/jpl_units/__pycache__/UnitDbl.cpython-37.pyc,,
matplotlib/testing/jpl_units/__pycache__/UnitDblConverter.cpython-37.pyc,,
matplotlib/testing/jpl_units/__pycache__/UnitDblFormatter.cpython-37.pyc,,
matplotlib/testing/jpl_units/__pycache__/__init__.cpython-37.pyc,,
matplotlib/tests/__init__.py,sha256=ns6SIKdszYNXD5h5PqKRCR06Z45H-sXrUX2VwujSRIM,366
matplotlib/tests/__pycache__/__init__.cpython-37.pyc,,
matplotlib/tests/__pycache__/conftest.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_afm.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_agg.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_agg_filter.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_animation.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_arrow_patches.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_artist.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_axes.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_backend_bases.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_backend_cairo.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_backend_nbagg.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_backend_pdf.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_backend_pgf.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_backend_ps.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_backend_qt.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_backend_svg.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_backend_tk.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_backend_tools.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_backend_webagg.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_backends_interactive.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_basic.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_bbox_tight.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_category.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_cbook.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_collections.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_colorbar.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_colors.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_compare_images.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_constrainedlayout.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_container.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_contour.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_cycles.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_dates.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_determinism.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_dviread.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_figure.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_font_manager.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_fontconfig_pattern.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_gridspec.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_image.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_legend.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_lines.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_marker.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_mathtext.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_matplotlib.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_mlab.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_offsetbox.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_patches.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_path.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_patheffects.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_pickle.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_png.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_preprocess_data.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_pyplot.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_quiver.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_rcparams.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_sankey.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_scale.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_simplification.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_skew.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_sphinxext.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_spines.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_streamplot.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_style.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_subplots.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_table.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_testing.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_texmanager.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_text.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_ticker.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_tightlayout.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_transforms.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_triangulation.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_ttconv.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_type1font.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_units.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_usetex.cpython-37.pyc,,
matplotlib/tests/__pycache__/test_widgets.cpython-37.pyc,,
matplotlib/tests/cmr10.pfb,sha256=_c7eh5QBjfXytY8JBfsgorQY7Y9ntz7hJEWFXfvlsb4,35752
matplotlib/tests/conftest.py,sha256=QtpdWPUoXL_9F8WIytDc3--h0nPjbo8PToig7svIT1Y,258
matplotlib/tests/mpltest.ttf,sha256=Jwb2O5KRVk_2CMqnhL0igeI3iGQCY3eChyS16N589zE,2264
matplotlib/tests/test_afm.py,sha256=DGVfvABg6FRmbAq2ldRhM2wlqNfVrmRtSz12MCyqDXk,3710
matplotlib/tests/test_agg.py,sha256=SC6WsFbq9Hs4dokpEqGqGPaFGS7zJpNxKRIRLUzD3Qk,7558
matplotlib/tests/test_agg_filter.py,sha256=sfntvGVUuCaGqU3DdOnTRXqq0P1afVqWuaV_ZEYh8kQ,969
matplotlib/tests/test_animation.py,sha256=WZ2kU7tjlDXL5Ryf89irQok884cWGtkVOJpNSjVyj3o,8916
matplotlib/tests/test_arrow_patches.py,sha256=3EB9HIfdLCg_Nvq8zxEH9LJAV5OUbo6yndbZ-lIVcnQ,5593
matplotlib/tests/test_artist.py,sha256=hMSfbg8Le0Li-vLEk2N9tZQtC1cUUE5Xn0O4CgYLugs,9418
matplotlib/tests/test_axes.py,sha256=nRp8gbewUffIIfUBFlBxkq5E6FnH75wrCFY4Xp4GpG8,216153
matplotlib/tests/test_backend_bases.py,sha256=I3Oiqk6Fm-fctj-aOxq5Av8Kqe3QLjlY-oTwTbdO6dw,3811
matplotlib/tests/test_backend_cairo.py,sha256=gIjbQesBuvIBdpzoXXSdRmq3E2axCVX4h1Qfv6PNeKM,1936
matplotlib/tests/test_backend_nbagg.py,sha256=dp9pYxWXN8ZBBjJcVE-1tJ61K7oeWtzcqIsAd7ABnfk,948
matplotlib/tests/test_backend_pdf.py,sha256=GUqvImL8-HgpZGG0Zb41AE3KqVwtt8i00xcPutzGM1w,6696
matplotlib/tests/test_backend_pgf.py,sha256=GAArsyhcLvWIHDtKgdv2kscRlgpNQ_oqyOXVGdVTw3Q,8636
matplotlib/tests/test_backend_ps.py,sha256=E3eheQhOHcUhub4IzcWcDVvvnnVC6bHn6tv1NAF_KA4,3633
matplotlib/tests/test_backend_qt.py,sha256=Oqtl2ZuS8Ly_ouDGkwndSheCs8U9OSiwBwJnnMmVGXI,9798
matplotlib/tests/test_backend_svg.py,sha256=rPppxppM-G4mm4ISP4hq7pIVGTfS6Zyydt1jUoY2QqY,5863
matplotlib/tests/test_backend_tk.py,sha256=sLqemf0mAFMIpv2414wKSVInLekL8bvzzaeREhE2UBU,934
matplotlib/tests/test_backend_tools.py,sha256=C-B7NCkyWsQ5KzQEnI5Be16DsAHHZJU9P5v9--wsF-o,501
matplotlib/tests/test_backend_webagg.py,sha256=u-UvO04iqxZbFlUrNIfyD0KIAxEhSOyqlrOqxO4DnDw,702
matplotlib/tests/test_backends_interactive.py,sha256=QsdZhWATJPh3ZYM2F90MRQCyoW3ROUOGXYgrM0XUxsc,5018
matplotlib/tests/test_basic.py,sha256=KRMwLx3J53urIx689lWHzkWkaWGTf0ZwhTyGrFDUfao,1268
matplotlib/tests/test_bbox_tight.py,sha256=3nrCNbVtd-0K3LvndlPQBG9raTLdbXuDmoMWt5oVMSY,3902
matplotlib/tests/test_category.py,sha256=SKBDW4R4q_7A0K1H-q801mTivxBgcLXigw4E6-tb1P4,10011
matplotlib/tests/test_cbook.py,sha256=Z2Hp8UkeebK-BglQXm9WhiTpZC8CbSsSKUNy6hJoJbU,18684
matplotlib/tests/test_collections.py,sha256=9Lyyydi1Ykk0BKXXWDPSYUQ1M9F-uJdVwqaZE1ZMKxI,23520
matplotlib/tests/test_colorbar.py,sha256=OW2F_D6Vs7jEV8HOBh2kv_iV21u7sdyIqJcRakwEkTg,22065
matplotlib/tests/test_colors.py,sha256=KYXZa1yFlkEGriaLMm-v2WnhROS2lvOUgseSHV2xC7w,33376
matplotlib/tests/test_compare_images.py,sha256=n3Uoukid0GcjyQpd6ZrqIY9u3RLNE2XAPWwtcHIsqto,3155
matplotlib/tests/test_constrainedlayout.py,sha256=9689kXb21xPGT3rqgZMxVT8HT4HXlzjO_aS6wq7b8kM,12981
matplotlib/tests/test_container.py,sha256=75Di6cic-JY7JbOnsaz7N6Hcm3KUAJKaKbCoVSDPAuU,576
matplotlib/tests/test_contour.py,sha256=G4dN6t8yrbpKp0aEI1VTrb-woyBKidGUqdDJ3b5D55U,12018
matplotlib/tests/test_cycles.py,sha256=mgYXt63ov7th7IwGpLEoCh-ImubEp6wltzTbDchfQYI,7112
matplotlib/tests/test_dates.py,sha256=1oDBr8xj2v_5tLHP_1rMkKA2nikoXSxK5u44ekL_NLA,32805
matplotlib/tests/test_determinism.py,sha256=bu8E_NMdeN0X2KRMStjAgK3tklL5SG_IqYu4hov6Z-4,4586
matplotlib/tests/test_dviread.py,sha256=kTk9Qv6q9Kk3fJcDAEWm35HF-sKsP6Ybec6N8jEHasE,2342
matplotlib/tests/test_figure.py,sha256=EKv9PCtr5KU30dZ_tBjxfgrQryxYjf1u0YIS83mFfe8,15244
matplotlib/tests/test_font_manager.py,sha256=OrOm9CD4FnUnSzoQEpRNcsDktw7gNBz3h7YMPGkudjI,7217
matplotlib/tests/test_fontconfig_pattern.py,sha256=1MhBrF914MKxjbpdxKDqkfVyCZGnFBA06D2I6rqHRHo,2012
matplotlib/tests/test_gridspec.py,sha256=zahj5Rd4pB0xtAc_3KX7fQWyBys0P-IQk-Cq0cs8VgY,626
matplotlib/tests/test_image.py,sha256=RMReqvIC2celG9NhUkJzv7Cl2us5Pc3f8I4uhxAzGQs,36254
matplotlib/tests/test_legend.py,sha256=oXMRtvzQgYMqNC0vPR8mhqQQl5n-IZRBSIZbr_N4hVk,20051
matplotlib/tests/test_lines.py,sha256=zbpM3DO0F-aclKrTE2JliUZpBR1UV5coR6I5OXOvJbg,5970
matplotlib/tests/test_marker.py,sha256=yGEoHoMji04-BPN-mmddO60pcpGwvL6FMO101xz70dg,4768
matplotlib/tests/test_mathtext.py,sha256=xqmDclBoB-7253xFBgf_yI9JxdkYZfuYgJ66HFcyqQA,13331
matplotlib/tests/test_matplotlib.py,sha256=DIBqISzUIYanSxNWJL9n2oob1dRLOOAr6TIz2BTWK1I,706
matplotlib/tests/test_mlab.py,sha256=ZpoL_7s2ARzt3uhq1InSVEWahB-svI0siIutKqyyUpM,89334
matplotlib/tests/test_offsetbox.py,sha256=f_I8sNuPmN4TXQAKGp5w3XQvnpWVSrHgEZr_0ZR7siE,6633
matplotlib/tests/test_patches.py,sha256=NaNojcVYpt6Lw3xr4bcI1c6Tc0fjBlz5OkQMhZlLApg,16948
matplotlib/tests/test_path.py,sha256=X6kEMiXLHVdRaZ9w2JF2ID2_DtIVonQDByvXpLbKXSo,12736
matplotlib/tests/test_patheffects.py,sha256=I1C81Cms_QBK6cPg_xxKZBXKykZuGI5H2wwFtwnALZk,5207
matplotlib/tests/test_pickle.py,sha256=BahI72bPhtSEylUvRwKgksK4N5i2vjsQ1APvEw3Om-0,5653
matplotlib/tests/test_png.py,sha256=-ik0JJOAuZCED13VshP5RZsBOQpXu_Kv9I1oaZ_grxs,1705
matplotlib/tests/test_preprocess_data.py,sha256=vVnEzVU-jd1hAQwh-b9IbWo-S_pIg4I9NCpSQ1lLChI,10034
matplotlib/tests/test_pyplot.py,sha256=9KEPaGTyHduk7vi40kbva03HFk7bm8KrGlWjkBGMoQ0,1662
matplotlib/tests/test_quiver.py,sha256=_dGa3bJmvNqcnBvFhGntvhBKRipROZUNOrSm-lMtc7Y,8087
matplotlib/tests/test_rcparams.py,sha256=HnXA81intnBhogrXbCuaAfOV2nyvbGvOCESYElue6C4,20896
matplotlib/tests/test_sankey.py,sha256=KdWhgZpEiCJ8o7yuFjnCgqFeodwKSCuuhV_mhIc04dM,310
matplotlib/tests/test_scale.py,sha256=kolkvXNDsSm7P44yrVDNuz25lve4iGGreaG-JC8-VIA,5895
matplotlib/tests/test_simplification.py,sha256=_dIImjiA0VHBEbOrGQluQKCS6SQFwEVvfL9pqIn_SHI,11048
matplotlib/tests/test_skew.py,sha256=hngaWfqV6zqZSnRmVadBvtMIrg1snTZvu3fsqv5YddU,6310
matplotlib/tests/test_sphinxext.py,sha256=VfFfCq5T3jaVN0Ut67SHpilUOzl-_zaJDnGxfGEtrgA,2022
matplotlib/tests/test_spines.py,sha256=5jGy42khH7ndaHRCgJONXBOvM5ZnrzOhPSR42IAUAA0,3132
matplotlib/tests/test_streamplot.py,sha256=_9iDNwQ0M1djl0eEX94QJtPYqCKFN5ncU_cIKJlm39w,3909
matplotlib/tests/test_style.py,sha256=FKsTSWx43sls_PqZzOEJ-ZRaiBmSmVQCgCxfGTlyiNc,5677
matplotlib/tests/test_subplots.py,sha256=RIk5cOGJmZwQz4UzZ_IEe1rzx4riAjO3bdltY5p1F6k,5992
matplotlib/tests/test_table.py,sha256=UEvwlff7Jdx7ezPMc8nAdaCO0u11PzNpCZqYGLDS3O4,5685
matplotlib/tests/test_testing.py,sha256=6pJ-SCQP1Bj4Qw5m5CEz2aWV4Bl7ovXE2uUpttiIu3Y,449
matplotlib/tests/test_texmanager.py,sha256=zCtJ3JnZNfP2AQNy7q2LQAgaflSe7S5htJkJNylQSGE,459
matplotlib/tests/test_text.py,sha256=49TKkDPy_tFRyxPLSp8-GgeS8TdU87JW24IUvA13NVM,20461
matplotlib/tests/test_ticker.py,sha256=niDdQLrvTIUa4x0jWchca_LJJFQc7EQVfBopnF-DjEM,49453
matplotlib/tests/test_tightlayout.py,sha256=Rg-Vw7VJSFxonhO5qnb2StPkMK7R4jpohMdFQbtPVSc,9685
matplotlib/tests/test_transforms.py,sha256=1CO_STcfUU4yo4bJZLdTpJ7dF3E285LVbG-OBpFUchA,24892
matplotlib/tests/test_triangulation.py,sha256=KWSRvg-_xE5Wz-_LAqB-EvI_5uy9isc9GTmhmi189Kw,45372
matplotlib/tests/test_ttconv.py,sha256=w6U4-5OiEuXsOskvMz4E-f9iqPoxCt8dIC2TNB7PwXo,655
matplotlib/tests/test_type1font.py,sha256=C0pCPBGOv49SR2xxDOq6LSXAEH_ZNvIWvr_jG-23Gmc,2097
matplotlib/tests/test_units.py,sha256=DhE6O7PZhMUf4FMoc1ByTcMgpS9-gMmjqsiQnqBBTKc,5710
matplotlib/tests/test_usetex.py,sha256=OrkN0Alth9lTFBWJbiQDsszhW70oO6TagLaD9XsCFmo,1245
matplotlib/tests/test_widgets.py,sha256=ijPT0E0-nS1J3kBpxoWSok1GbqlZf22J5Csbto3nl4U,17654
matplotlib/tests/tinypages/.gitignore,sha256=re9gqsLda7alFAVabOwnvrzS8ChI0uTxX1FxzsvqyEE,8
matplotlib/tests/tinypages/README.md,sha256=l-sVwF8k46XxCZdwprn5wSibt6S03ICVLlMqJJN7EDo,124
matplotlib/tests/tinypages/__pycache__/conf.cpython-37.pyc,,
matplotlib/tests/tinypages/__pycache__/range4.cpython-37.pyc,,
matplotlib/tests/tinypages/__pycache__/range6.cpython-37.pyc,,
matplotlib/tests/tinypages/_static/.gitignore,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
matplotlib/tests/tinypages/_static/README.txt,sha256=1nnoizmUuHn5GKx8RL6MwJPlkyGmu_KHhYIMTDSWUNM,303
matplotlib/tests/tinypages/conf.py,sha256=0_a4wyqPA9oaOFpLLpSEzkZI-hwtyRbqLWBx9nf0sLA,8432
matplotlib/tests/tinypages/index.rst,sha256=kLSy7c3SoIAVsKOFkbzB4zFVzk3HW3d_rJHlHcNGBAg,446
matplotlib/tests/tinypages/range4.py,sha256=fs2krzi9sY9ysmJRQCdGs_Jh1L9vDXDrNse7c0aX_Rw,81
matplotlib/tests/tinypages/range6.py,sha256=a2EaHrNwXz4GJqhRuc7luqRpt7sqLKhTKeid9Drt2QQ,281
matplotlib/tests/tinypages/some_plots.rst,sha256=C9rwV9UVlhFvxm8VqV6PoAP1AQ8Kk0LGZI9va4joif0,2156
matplotlib/texmanager.py,sha256=kiFNpjY5S8OJ2Q6WPZ2h6YueL_zrXZQyIdrFgP_XRnI,17097
matplotlib/text.py,sha256=bt04zgIbjJUOqdZ8gomc_zWF3UOYL5mHWaHb9OxxYHM,81090
matplotlib/textpath.py,sha256=dEZ1Vg4ZUI5M4iTHn-7I45KeR1FTit78jQ-3EyK6orc,17010
matplotlib/ticker.py,sha256=Dp_BzFOaTG0Qy7W1H4-yo5JlNNLMJS2L8BiXYjCC4Xk,101242
matplotlib/tight_bbox.py,sha256=bQAOXPKfVWoBkGZbC0ckRcldgLJ8eBUe2IsT8UQpgaY,2590
matplotlib/tight_layout.py,sha256=BrNob3eytUkmtXtwgfD3jdRgNh_tIjDE89AZjAnhFdY,14586
matplotlib/transforms.py,sha256=cynqPdAO9gtYxmDBr_zr1VTSlIlbtOAwfNzGqsVV208,97572
matplotlib/tri/__init__.py,sha256=XMaejh88uov7Neu7MuYMyaNQqaxg49nXaiJfvjifrRM,256
matplotlib/tri/__pycache__/__init__.cpython-37.pyc,,
matplotlib/tri/__pycache__/triangulation.cpython-37.pyc,,
matplotlib/tri/__pycache__/tricontour.cpython-37.pyc,,
matplotlib/tri/__pycache__/trifinder.cpython-37.pyc,,
matplotlib/tri/__pycache__/triinterpolate.cpython-37.pyc,,
matplotlib/tri/__pycache__/tripcolor.cpython-37.pyc,,
matplotlib/tri/__pycache__/triplot.cpython-37.pyc,,
matplotlib/tri/__pycache__/trirefine.cpython-37.pyc,,
matplotlib/tri/__pycache__/tritools.cpython-37.pyc,,
matplotlib/tri/triangulation.py,sha256=NCY1Fx66H3MHrMA1-NW6G_shopBtFu1Ehm1f6XyRDBE,8315
matplotlib/tri/tricontour.py,sha256=4gKIAi1CFKWK8BCqAXMD6PlUKxnrC9GvzeQz0Yknvik,9794
matplotlib/tri/trifinder.py,sha256=umsDJX2kach9MVDvEirLdN9q31QQ9tdP67U71eFyGj8,3497
matplotlib/tri/triinterpolate.py,sha256=EP-ZwNC3HlOGB4jNaHGUCncXeO7LocvT2QhTr-jKCrk,64886
matplotlib/tri/tripcolor.py,sha256=H6DEToUjfU12hDkfekshYyuQoZc7Fa4r4W6MOR5d6Jw,5169
matplotlib/tri/triplot.py,sha256=aZ9O_VVLH0AOne31u11ltLlyVyhqKtyzec7WH3b3pkk,2857
matplotlib/tri/trirefine.py,sha256=uwAminHKuxgE0ZuwwllIpqK2Ww_q--VKzMicWUslA0s,13765
matplotlib/tri/tritools.py,sha256=BggcSXDVoc2mSyJp7wQ51qaw8WhdL7ianZ-D7ezkuC8,12398
matplotlib/ttconv.cpython-37m-x86_64-linux-gnu.so,sha256=DhFx2UOow2EkHvRhRhsIYL-lCKzlfCA9nAKyB8_lZpA,83888
matplotlib/type1font.py,sha256=-D1P81hhDUVNAHZ55-Df4cPc-3R8ycY_judVBZphgsk,12168
matplotlib/units.py,sha256=dgSbQsrJPRiKf5IJv-PM0xYMcvT3kle3gdPJsdjbRZk,7332
matplotlib/widgets.py,sha256=lMHpWCFdFTwSCEO5uL4fjcsoDQMzkzlWyVXnx80FVn4,94615
mpl_toolkits/axes_grid/__init__.py,sha256=VLlc0DaOkr9JumPa8W4zt9lGHp180ie8_WLPZVNSJMw,537
mpl_toolkits/axes_grid/__pycache__/__init__.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/anchored_artists.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/angle_helper.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/axes_divider.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/axes_grid.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/axes_rgb.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/axes_size.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/axis_artist.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/axisline_style.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/axislines.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/clip_path.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/colorbar.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/floating_axes.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/grid_finder.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/grid_helper_curvelinear.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/inset_locator.cpython-37.pyc,,
mpl_toolkits/axes_grid/__pycache__/parasite_axes.cpython-37.pyc,,
mpl_toolkits/axes_grid/anchored_artists.py,sha256=_F6-9iacZidb5JpJ8jCOZ9PdiZaR5qpfBjf-3VjTzNc,291
mpl_toolkits/axes_grid/angle_helper.py,sha256=Tb4Mb_NGkUdkisebe2dqfBdFmUZiSmGyUnftiSeSIls,51
mpl_toolkits/axes_grid/axes_divider.py,sha256=tJlPia3Z8xLq6uXehBwAlD_4ywMvRTTkM73qNnCpo7Q,178
mpl_toolkits/axes_grid/axes_grid.py,sha256=UPlVDwsze_w2aZeLaMg4WZVK3q2EvWePXTFZFvjCQz4,89
mpl_toolkits/axes_grid/axes_rgb.py,sha256=d3h2tImoPxvVtl8i4IBA_i1vBQykZDYizcNDGdjRltE,201
mpl_toolkits/axes_grid/axes_size.py,sha256=v4Nhxe7DVp1FkKX03DqJJ1aevDanDvgKT9r0ouDzTxw,48
mpl_toolkits/axes_grid/axis_artist.py,sha256=zUlJFUHueDsMtzLi_mK2_Wf-nSBQgiTsMOFpo_SngZ0,50
mpl_toolkits/axes_grid/axisline_style.py,sha256=lNVHXkFWhSWPXOOfF-wlVkDPzmzuStJyJzF-NS5Wf_g,53
mpl_toolkits/axes_grid/axislines.py,sha256=kVyhb6laiImmuNE53QTQh3kgxz0sO1mcSMpnqIdjylA,48
mpl_toolkits/axes_grid/clip_path.py,sha256=s-d36hUiy9I9BSr9wpxjgoAACCQrczHjw072JvArNvE,48
mpl_toolkits/axes_grid/colorbar.py,sha256=DckRf6tadLeTNjx-Zk1u3agnSGZgizDjd0Dxw1-GRdw,171
mpl_toolkits/axes_grid/floating_axes.py,sha256=i35OfV1ZMF-DkLo4bKmzFZP6LgCwXfdDKxYlGqjyKOM,52
mpl_toolkits/axes_grid/grid_finder.py,sha256=Y221c-Jh_AFd3Oolzvr0B1Zrz9MoXPatUABQdLsFdpw,50
mpl_toolkits/axes_grid/grid_helper_curvelinear.py,sha256=nRl_B-755X7UpVqqdwkqc_IwiTmM48z3eOMHuvJT5HI,62
mpl_toolkits/axes_grid/inset_locator.py,sha256=qqXlT8JWokP0kV-8NHknZDINtK-jbXfkutH_1tcRe_o,216
mpl_toolkits/axes_grid/parasite_axes.py,sha256=kCFtaRTd0O8ePL78GOYvhEKqn8rE9bk61v0kVgMb6UE,469
mpl_toolkits/axes_grid1/__init__.py,sha256=-lw0ZfG4XUpuAolCpXKFwtS3w1LJ1ZToSEC9OSmB-4Q,204
mpl_toolkits/axes_grid1/__pycache__/__init__.cpython-37.pyc,,
mpl_toolkits/axes_grid1/__pycache__/anchored_artists.cpython-37.pyc,,
mpl_toolkits/axes_grid1/__pycache__/axes_divider.cpython-37.pyc,,
mpl_toolkits/axes_grid1/__pycache__/axes_grid.cpython-37.pyc,,
mpl_toolkits/axes_grid1/__pycache__/axes_rgb.cpython-37.pyc,,
mpl_toolkits/axes_grid1/__pycache__/axes_size.cpython-37.pyc,,
mpl_toolkits/axes_grid1/__pycache__/colorbar.cpython-37.pyc,,
mpl_toolkits/axes_grid1/__pycache__/inset_locator.cpython-37.pyc,,
mpl_toolkits/axes_grid1/__pycache__/mpl_axes.cpython-37.pyc,,
mpl_toolkits/axes_grid1/__pycache__/parasite_axes.cpython-37.pyc,,
mpl_toolkits/axes_grid1/anchored_artists.py,sha256=F9396ifiWLedXEsivC3-rJjhYOxZ84dHYFhlRMVt4wE,21031
mpl_toolkits/axes_grid1/axes_divider.py,sha256=rZOhnowUzJ3mXb6LKkLPjDyxkz-EPJmA3MCafFa8VN8,29175
mpl_toolkits/axes_grid1/axes_grid.py,sha256=2ThJGeKXb9avu0KN3ujBliY2HV26IHC1daxy74t8ITk,27888
mpl_toolkits/axes_grid1/axes_rgb.py,sha256=NsMKkaMEeXd6N1AYVP1Pz-ulwNeof1pU4qkReoQ8xFc,6652
mpl_toolkits/axes_grid1/axes_size.py,sha256=YBC1PUmUK1-0c7cuqgJQBpDwVrbZQaWXyWadvuOO5bs,8602
mpl_toolkits/axes_grid1/colorbar.py,sha256=Y0-Uf9osbz31YBOTxxs_UFXbp6Xyc9Rais47tBMjTXI,27123
mpl_toolkits/axes_grid1/inset_locator.py,sha256=0BA8z3BiT78sS2-ksVe8iKS6KLxVv_NTV38NTLmRuu4,23675
mpl_toolkits/axes_grid1/mpl_axes.py,sha256=MJVYUN4YRtTWrq1wmyv_y61O002tiyFESmBSaJ8xkG4,4380
mpl_toolkits/axes_grid1/parasite_axes.py,sha256=ug0YRJiTtA3YVikdKMGj-qjoeOFnqNw2QnRab0Qp7wI,13570
mpl_toolkits/axisartist/__init__.py,sha256=2zsgjqTtP_NXv78MEaKabmfmkjA7yhy77pIcaR57YWs,748
mpl_toolkits/axisartist/__pycache__/__init__.cpython-37.pyc,,
mpl_toolkits/axisartist/__pycache__/angle_helper.cpython-37.pyc,,
mpl_toolkits/axisartist/__pycache__/axes_divider.cpython-37.pyc,,
mpl_toolkits/axisartist/__pycache__/axes_grid.cpython-37.pyc,,
mpl_toolkits/axisartist/__pycache__/axes_rgb.cpython-37.pyc,,
mpl_toolkits/axisartist/__pycache__/axis_artist.cpython-37.pyc,,
mpl_toolkits/axisartist/__pycache__/axisline_style.cpython-37.pyc,,
mpl_toolkits/axisartist/__pycache__/axislines.cpython-37.pyc,,
mpl_toolkits/axisartist/__pycache__/clip_path.cpython-37.pyc,,
mpl_toolkits/axisartist/__pycache__/floating_axes.cpython-37.pyc,,
mpl_toolkits/axisartist/__pycache__/grid_finder.cpython-37.pyc,,
mpl_toolkits/axisartist/__pycache__/grid_helper_curvelinear.cpython-37.pyc,,
mpl_toolkits/axisartist/__pycache__/parasite_axes.cpython-37.pyc,,
mpl_toolkits/axisartist/angle_helper.py,sha256=KZiXfi0IPcGp6JFXewj0VLrUycSfI93ezoimkti3wpY,12632
mpl_toolkits/axisartist/axes_divider.py,sha256=baPCBjM20SvAUeMjhvlS_cccRSM1y7ZKybtoW8upo2k,127
mpl_toolkits/axisartist/axes_grid.py,sha256=vfd_EXHuYQ7iIVK2FOm6inLhb7huZxtOSvFyOVW2GmU,610
mpl_toolkits/axisartist/axes_rgb.py,sha256=TpJCB8eA0wHZVXOxxfFoy1Tk_KFj68sZvo74doDeHYE,179
mpl_toolkits/axisartist/axis_artist.py,sha256=gScMYbfAyxT5IgyEZRVto2NyZVLGpDQeJ1t9tk1d3OM,43453
mpl_toolkits/axisartist/axisline_style.py,sha256=bQ3M5gAxS7HbCC3oOQgrSyNWdk_FbvXfX24Eatge0UE,5098
mpl_toolkits/axisartist/axislines.py,sha256=mrQIihqbfBi2F-QgLRjZvHGM6rEojStBzojYpVNkjg0,20852
mpl_toolkits/axisartist/clip_path.py,sha256=LE_IIP0byNr5ELJlD8_8fsAh215MUDoK19-BISuFB80,3777
mpl_toolkits/axisartist/floating_axes.py,sha256=xSAJ5Myaa5Xm9DkOhJcdaPwzdPyvJnw5K9YPmDwB5ME,13122
mpl_toolkits/axisartist/grid_finder.py,sha256=K1Gae38Jt2OFfScZaKbxkLLcWrHDm-2bAVsl56SC1F0,10388
mpl_toolkits/axisartist/grid_helper_curvelinear.py,sha256=6QT9nTQ2dJ_NPsazS0Q0hC8W5IV7yzqYd_Fa8_gJXmI,14384
mpl_toolkits/axisartist/parasite_axes.py,sha256=1sQwBEYuXHpaEeObb7cXh0I1xWroYtcvFiEmwrzqK3w,447
mpl_toolkits/mplot3d/__init__.py,sha256=V2iPIP9VyRhoJsFWnQf5AkfyI1GSSP9H6hICEe9edJo,27
mpl_toolkits/mplot3d/__pycache__/__init__.cpython-37.pyc,,
mpl_toolkits/mplot3d/__pycache__/art3d.cpython-37.pyc,,
mpl_toolkits/mplot3d/__pycache__/axes3d.cpython-37.pyc,,
mpl_toolkits/mplot3d/__pycache__/axis3d.cpython-37.pyc,,
mpl_toolkits/mplot3d/__pycache__/proj3d.cpython-37.pyc,,
mpl_toolkits/mplot3d/art3d.py,sha256=MAR_fFyBwe3VkwlOeWMccwDWo8RR1VqhUjuipLPuIFU,27647
mpl_toolkits/mplot3d/axes3d.py,sha256=iJ7LN-UKY7xMaGjYbeu-J1IuC54QX3irx7Kkh5gInzY,98609
mpl_toolkits/mplot3d/axis3d.py,sha256=UdxPxUW7GDoOpBy4uByLmLZJfle2wu0oYGenDHjjcLA,16737
mpl_toolkits/mplot3d/proj3d.py,sha256=5xwjogevdUCBaV9sx1RlNqO6fMCSIBi_1_uVZniy2pU,5499
mpl_toolkits/tests/__init__.py,sha256=iPdasxJf0vpIi11tQ98OVSQgS0UaPUyOEGGfAryAhIA,381
mpl_toolkits/tests/__pycache__/__init__.cpython-37.pyc,,
mpl_toolkits/tests/__pycache__/conftest.cpython-37.pyc,,
mpl_toolkits/tests/__pycache__/test_axes_grid.cpython-37.pyc,,
mpl_toolkits/tests/__pycache__/test_axes_grid1.cpython-37.pyc,,
mpl_toolkits/tests/__pycache__/test_axisartist_angle_helper.cpython-37.pyc,,
mpl_toolkits/tests/__pycache__/test_axisartist_axis_artist.cpython-37.pyc,,
mpl_toolkits/tests/__pycache__/test_axisartist_axislines.cpython-37.pyc,,
mpl_toolkits/tests/__pycache__/test_axisartist_clip_path.cpython-37.pyc,,
mpl_toolkits/tests/__pycache__/test_axisartist_floating_axes.cpython-37.pyc,,
mpl_toolkits/tests/__pycache__/test_axisartist_grid_finder.cpython-37.pyc,,
mpl_toolkits/tests/__pycache__/test_axisartist_grid_helper_curvelinear.cpython-37.pyc,,
mpl_toolkits/tests/__pycache__/test_mplot3d.cpython-37.pyc,,
mpl_toolkits/tests/baseline_images/test_axes_grid/imagegrid_cbar_mode.png,sha256=yvo6erXXc3Z9aO0rrEezBooCc6KhAw7wKv4WngOQmFA,87393
mpl_toolkits/tests/baseline_images/test_axes_grid1/anchored_direction_arrows.png,sha256=XMZGgG7_9k96bKhI2G--XBVKpct5O5psbGH2Wvj5YA0,10784
mpl_toolkits/tests/baseline_images/test_axes_grid1/anchored_direction_arrows_many_args.png,sha256=fkPsdmhd4S1g-QxMb55M63iAgWmC2G4ytcLOT9tMAD0,11039
mpl_toolkits/tests/baseline_images/test_axes_grid1/divider_append_axes.pdf,sha256=eW2CuM_T4d95dC-DU0PmmQD7gqRQIO0rcQpvp-zu1i4,25446
mpl_toolkits/tests/baseline_images/test_axes_grid1/divider_append_axes.png,sha256=VfRfs6p4akgjGxxNm6Bu83Pg0v1KmU7WPu97_-kzNFc,48825
mpl_toolkits/tests/baseline_images/test_axes_grid1/divider_append_axes.svg,sha256=usfsa3y-s-N2KMOzsOZHTq-PZXgAPXsSM-lkxJ3ZUi0,172812
mpl_toolkits/tests/baseline_images/test_axes_grid1/fill_facecolor.png,sha256=Tkrylxebxm8SuWZjQK0qXSX8m9QsQU6kYm7L2dgt4yg,14845
mpl_toolkits/tests/baseline_images/test_axes_grid1/image_grid.png,sha256=HIg43mbdOUyEWY-jQ1DEpG7DMqCcWbX1Xf2itmW1YL4,3786
mpl_toolkits/tests/baseline_images/test_axes_grid1/inset_axes.png,sha256=RQmR39E6Vskvl7G4LInHibW9E1VK0QgCvI-hBlb-E2E,9928
mpl_toolkits/tests/baseline_images/test_axes_grid1/inset_locator.png,sha256=bQKKKUuoU_EZwZT_9FzzeVKsKwUUBOZV55g4vVUbnCU,9490
mpl_toolkits/tests/baseline_images/test_axes_grid1/inverted_zoomed_axes.png,sha256=rvglsLg8Kl9jE_JukTJ5B3EHozsIYJsaYA0JIOicZL8,25997
mpl_toolkits/tests/baseline_images/test_axes_grid1/twin_axes_empty_and_removed.png,sha256=0YzkFhxs4SBG_FEmnWB10bXIxl9aq7WJveQAqHm0JrQ,37701
mpl_toolkits/tests/baseline_images/test_axes_grid1/zoomed_axes.png,sha256=mUu8zJtz8FMb7h5l4Cfp3oBi9jaNR5OoyaDgwqpAZp4,25893
mpl_toolkits/tests/baseline_images/test_axisartist_axis_artist/axis_artist.png,sha256=qdlk9UPScCAN9RBOhoNqLmJvmkXt8pCuwuQtrz5E8Bs,10151
mpl_toolkits/tests/baseline_images/test_axisartist_axis_artist/axis_artist_labelbase.png,sha256=An5lovtvAiNA1NZI-E8kOj6eYTruQMqwf3J7pXwdk4A,10598
mpl_toolkits/tests/baseline_images/test_axisartist_axis_artist/axis_artist_ticklabels.png,sha256=7vuAKkIqcpgJrc2AF7oslf-E_sDfSlCoymyc87u4AWs,5696
mpl_toolkits/tests/baseline_images/test_axisartist_axis_artist/axis_artist_ticks.png,sha256=CkVtCWG13ViW0w2DsbzfXSvoFWHYaaqQYeEYpbKbOg8,5695
mpl_toolkits/tests/baseline_images/test_axisartist_axislines/ParasiteAxesAuxTrans_meshplot.png,sha256=FOgl-Glmzhdp6V8mz4StofTsFXGysFkEcUeaWtmJDZs,34354
mpl_toolkits/tests/baseline_images/test_axisartist_axislines/Subplot.png,sha256=tRpYCjR5zUkafA85DVmY3duTEouwCZq6jDwSF4UsBS8,26919
mpl_toolkits/tests/baseline_images/test_axisartist_axislines/SubplotZero.png,sha256=3kCrz7HQMYrK3iDgYgf8kyigxRtIGFBbcUzJPtiXh_E,28682
mpl_toolkits/tests/baseline_images/test_axisartist_clip_path/clip_path.png,sha256=BtMyb7ZawcgId9jl1_qW72lU_ZyxLN780uQ9bCLjbHA,25701
mpl_toolkits/tests/baseline_images/test_axisartist_floating_axes/curvelinear3.png,sha256=4th7Y74_9YV6X25RqJW0Op9WDzGRCcxF1kfNogkgozE,52835
mpl_toolkits/tests/baseline_images/test_axisartist_floating_axes/curvelinear4.png,sha256=cYjrSiH6Mvor-VhmwNUgX7Le3_k1rurpd8L5vhTf16s,29374
mpl_toolkits/tests/baseline_images/test_axisartist_grid_helper_curvelinear/axis_direction.png,sha256=3fue92dg-ntYI0XX0nB31IFpgRT2V3izqjrmLvEdYN4,40536
mpl_toolkits/tests/baseline_images/test_axisartist_grid_helper_curvelinear/custom_transform.png,sha256=4cQhIFK1z8oPUVyvkHNZ_m-GCbikmUbTvkvYVGy6U4o,15118
mpl_toolkits/tests/baseline_images/test_axisartist_grid_helper_curvelinear/polar_box.png,sha256=wWaPM3I7_435SkVQqIggb8BHrWBMWrsSVyMZQQJ6fE4,62526
mpl_toolkits/tests/baseline_images/test_mplot3d/axes3d_cla.png,sha256=htnP1CA8dd85KqdnOsHVlsehT90MUoQD8kFTyra0AuE,51409
mpl_toolkits/tests/baseline_images/test_mplot3d/axes3d_labelpad.png,sha256=zrLsk8t7s970yaY3cqj6SOMbI6UY8Loe0Zbp0WqFtwQ,66817
mpl_toolkits/tests/baseline_images/test_mplot3d/axes3d_ortho.png,sha256=SoyN30SsuvEECZyB_ReGP3ZKGZJazOp05dXa3YUn7Jc,47796
mpl_toolkits/tests/baseline_images/test_mplot3d/bar3d.png,sha256=Qw909B4nDmV9DlMuo1DKk7y5ndjtvni5d_DcysmG9VA,100466
mpl_toolkits/tests/baseline_images/test_mplot3d/bar3d_notshaded.png,sha256=soaHKytaVZHmPvHIEcPFQDJDqhEEuNO_JIVCZyjacxM,66294
mpl_toolkits/tests/baseline_images/test_mplot3d/bar3d_shaded.png,sha256=laBssZyuviouRe3seffJWOz45OLunXC0dFHi-lYge1w,115939
mpl_toolkits/tests/baseline_images/test_mplot3d/contour3d.png,sha256=tii1IakS8MC_Vuwd95HhcyM0iq4zGN5DxgRFfB9mKu8,83161
mpl_toolkits/tests/baseline_images/test_mplot3d/contourf3d.png,sha256=Jb-fhAcgogE8jn9DSsaqInUfWC7D_5Pf3QRf7XWAX2Q,42575
mpl_toolkits/tests/baseline_images/test_mplot3d/contourf3d_fill.png,sha256=dE8eHoj43eePB44F1nLM2RLj8iqw8rCYI3D0VD3gUg0,39694
mpl_toolkits/tests/baseline_images/test_mplot3d/lines3d.png,sha256=DQT-NruHCeG5LKpjG-dlLln3aCoPKhua5PQnHTafBGU,60217
mpl_toolkits/tests/baseline_images/test_mplot3d/mixedsubplot.png,sha256=iHxYbxRflxIpjoAtWo9KAvgK4CS-k4N03p0SX_xF4DA,39674
mpl_toolkits/tests/baseline_images/test_mplot3d/plot_3d_from_2d.png,sha256=AWos5EJWMerD0tgVZyvBofz-5hnCq6fhGHKmQi-izAg,56593
mpl_toolkits/tests/baseline_images/test_mplot3d/poly3dcollection_alpha.png,sha256=AnZJbnnBnF_fny5FBTlSWblkNMlPI1dcQRlCfGPIjWI,52046
mpl_toolkits/tests/baseline_images/test_mplot3d/poly3dcollection_closed.png,sha256=ePzSA-iFaQbmH603vw1jhs9vyIt45xXnbpIuUF3a1l8,52065
mpl_toolkits/tests/baseline_images/test_mplot3d/proj3d_axes_cube.png,sha256=AJ0EoayvdBoywpOUWcxbMQ0oB7cTzcoWGgGyx2qgQMU,23182
mpl_toolkits/tests/baseline_images/test_mplot3d/proj3d_axes_cube_ortho.png,sha256=5Phz7BclSciZpg4SDu-eUQ-v_ikHbEqReQWCdeHywQk,16210
mpl_toolkits/tests/baseline_images/test_mplot3d/proj3d_lines_dists.png,sha256=XCd4hX2ckc5GCxcgenkRJ8MT7pX-3iMLylD2rCjNl-4,18898
mpl_toolkits/tests/baseline_images/test_mplot3d/quiver3d.png,sha256=PBllNI1kHf1rz-oPK507OwsPNE9DPwivXAVJM9DemBI,104755
mpl_toolkits/tests/baseline_images/test_mplot3d/quiver3d_empty.png,sha256=98D3k5QIL7KugUwzqJhdLtp9dgDGgx8hGa9_u8cvX6o,37954
mpl_toolkits/tests/baseline_images/test_mplot3d/quiver3d_masked.png,sha256=67yp7-6f-vDiYTmCqMFfuIEGly5UHCCUOV84YJtLsX8,80392
mpl_toolkits/tests/baseline_images/test_mplot3d/quiver3d_pivot_middle.png,sha256=N4o26wMzfnyxndPbZ2VnsjIAiNYrFN9Aa40ficwO9AM,104735
mpl_toolkits/tests/baseline_images/test_mplot3d/quiver3d_pivot_tail.png,sha256=Ff_UrWxD-VIMQLN1uXy5u_Yd5e1P427YfGM05nvU2kE,104951
mpl_toolkits/tests/baseline_images/test_mplot3d/scatter3d.png,sha256=MDaocusHz6Itinjm2j6fnDh-rl1fqVjnqM89nP8bwZs,43155
mpl_toolkits/tests/baseline_images/test_mplot3d/scatter3d_color.png,sha256=Y7De9BIFLp0Ova4fk9IcXloNjiwmifTrFA1IfVJA3aE,41598
mpl_toolkits/tests/baseline_images/test_mplot3d/surface3d.png,sha256=Ok0UmO2DELze2yK8mRx0CifmRAgvjyS1IvERsBRvFlU,54712
mpl_toolkits/tests/baseline_images/test_mplot3d/surface3d_shaded.png,sha256=kWYGPWgG1ZrQVgd389xmIZ1cc59tAkKKiikKaJzHKkw,43474
mpl_toolkits/tests/baseline_images/test_mplot3d/text3d.png,sha256=sO68K3cti2YsPkkjEIAvc7_pd8JaHpc_a78UVx4Htu4,78758
mpl_toolkits/tests/baseline_images/test_mplot3d/tricontour.png,sha256=8IjYmJP6cBhnPGLz-WDyn7UUMYZ10Kz2MpjOFwDUVow,71328
mpl_toolkits/tests/baseline_images/test_mplot3d/trisurf3d.png,sha256=nO0gJBIluLEX3mlxXY3C6bx-9Jf_xJyXAnTXKnqrIkQ,99103
mpl_toolkits/tests/baseline_images/test_mplot3d/trisurf3d_shaded.png,sha256=LSVF3lI7JnYXmCBAcn410k3JRE-3ssp84Dmgg3zr0FA,94328
mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-alpha.png,sha256=LELjsQnfvfzLF8rNSh5azv9BdwF8TlCMn2wbBJNTtyQ,178141
mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-edge-style.png,sha256=UJXpFMSWIFgUH2rLEv1nxDvHrnshlSz4d5ZB34upa3g,65759
mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-named-colors.png,sha256=J8m66Bc5NoeZxGRwbBThV06_aybNvMeTtwUnmCRzNak,93580
mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-rgb-data.png,sha256=5s02No0RWv8NYV_ccFUnDdBaUHQ8DTO90qddKBnN6mw,131458
mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-simple.png,sha256=7VCcyzKKKz8E7txQV4wi-jEbtftaFW_ekWmA9E1qx3Y,60304
mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-xyz.png,sha256=KwDmkuK7FMtl0Q2ank7wcph9uTncUr7UdTh2hUYdZP8,121446
mpl_toolkits/tests/baseline_images/test_mplot3d/wireframe3d.png,sha256=epmsR4rWGzh7prW3RL_t8ZcUEsphM5bc0t5j__iauOY,108371
mpl_toolkits/tests/baseline_images/test_mplot3d/wireframe3dzerocstride.png,sha256=WaO_3NcaZPFzlui5SQYJ-TbUylHkSbieneCYPffNgAA,81117
mpl_toolkits/tests/baseline_images/test_mplot3d/wireframe3dzerorstride.png,sha256=y1JvfuVOBiNhJoJ2HdOXyBYBBkQm-oaPcoekfT-cMso,84284
mpl_toolkits/tests/conftest.py,sha256=Ph6QZKdfAnkPwU52StddC-uwtCHfANKX1dDXgtX122g,213
mpl_toolkits/tests/test_axes_grid.py,sha256=SUnj9aImCEI-Q3_cM8e5BlizoNle9E1joKkE_q57OAg,2694
mpl_toolkits/tests/test_axes_grid1.py,sha256=pUw19PTds6WRlLON5U9ZWmt6HxV56Q6DKDPVGM34ysk,17113
mpl_toolkits/tests/test_axisartist_angle_helper.py,sha256=PwhJwBm2kk4uMyhdO5arQs8IlqSX2vN0hvUzI7YHqrw,5670
mpl_toolkits/tests/test_axisartist_axis_artist.py,sha256=N4Khx8jSxkoiMz3KvumodmFKHZUtdwtjkzxLWPSdyuw,3008
mpl_toolkits/tests/test_axisartist_axislines.py,sha256=4ujhndnDq-6albE4WwVFTVURfjG1xK1597smUGMxfFg,2331
mpl_toolkits/tests/test_axisartist_clip_path.py,sha256=afS3nvNqCgvDpJdg_MvbwydtSWv5b6ciP-Iq2aNcNFQ,1004
mpl_toolkits/tests/test_axisartist_floating_axes.py,sha256=xENnUpFU8EHPgnON6W1xqMVWIq8qxIzuGf1oMmSMFJo,4127
mpl_toolkits/tests/test_axisartist_grid_finder.py,sha256=e65sLudWFIXeU08Sis3_SI1JEI6eq8YqKj-80F_Nohk,325
mpl_toolkits/tests/test_axisartist_grid_helper_curvelinear.py,sha256=0AT6TdbxHGHlircgjNZyK2u1dw05YLXdOhLqXmsKyw4,7572
mpl_toolkits/tests/test_mplot3d.py,sha256=TojtKh1gbRWl-kCWQcYaFMOS89txDRd02O0NBJuu-vE,31991
pylab.py,sha256=u_By3CHla-rBMg57egFXIxZ3P_J6zEkSu_dNpBcH5pw,90

View File

@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.31.1)
Root-Is-Purelib: false
Tag: cp37-cp37m-manylinux1_x86_64

View File

@ -1,3 +0,0 @@
matplotlib
mpl_toolkits
pylab

View File

@ -11,8 +11,8 @@ version_json = '''
{ {
"dirty": false, "dirty": false,
"error": null, "error": null,
"full-revisionid": "ca3d653536dec38a0c1ac3b80413961ca1bcdda6", "full-revisionid": "a1a5298b0d4a8d8230103d0fa8d369fca7fdeea0",
"version": "3.2.1" "version": "3.2.2"
} }
''' # END VERSION_JSON ''' # END VERSION_JSON

View File

@ -1099,7 +1099,7 @@ class Animation:
extra_args=extra_args, extra_args=extra_args,
metadata=metadata) metadata=metadata)
else: else:
alt_writer = next(writers, None) alt_writer = next(iter(writers), None)
if alt_writer is None: if alt_writer is None:
raise ValueError("Cannot save animation: no writers are " raise ValueError("Cannot save animation: no writers are "
"available. Please install ffmpeg to " "available. Please install ffmpeg to "

View File

@ -654,6 +654,7 @@ class Axes(_AxesBase):
raise ValueError('secondary_xaxis location must be either ' raise ValueError('secondary_xaxis location must be either '
'a float or "top"/"bottom"') 'a float or "top"/"bottom"')
@docstring.dedent_interpd
def secondary_yaxis(self, location, *, functions=None, **kwargs): def secondary_yaxis(self, location, *, functions=None, **kwargs):
""" """
Add a second y-axis to this axes. Add a second y-axis to this axes.
@ -4211,19 +4212,26 @@ class Axes(_AxesBase):
except ValueError: except ValueError:
pass # Failed to convert to float array; must be color specs. pass # Failed to convert to float array; must be color specs.
else: else:
# handle the documented special case of a 2D array with 1
# row which as RGB(A) to broadcast.
if c.shape == (1, 4) or c.shape == (1, 3):
c_is_mapped = False
if c.size != xsize:
valid_shape = False
# If c can be either mapped values or a RGB(A) color, prefer # If c can be either mapped values or a RGB(A) color, prefer
# the former if shapes match, the latter otherwise. # the former if shapes match, the latter otherwise.
if c.size == xsize: elif c.size == xsize:
c = c.ravel() c = c.ravel()
c_is_mapped = True c_is_mapped = True
else: # Wrong size; it must not be intended for mapping. else: # Wrong size; it must not be intended for mapping.
if c.shape in ((3,), (4,)): if c.shape in ((3,), (4,)):
_log.warning( _log.warning(
"'c' argument looks like a single numeric RGB or " "*c* argument looks like a single numeric RGB or "
"RGBA sequence, which should be avoided as value-" "RGBA sequence, which should be avoided as value-"
"mapping will have precedence in case its length " "mapping will have precedence in case its length "
"matches with 'x' & 'y'. Please use a 2-D array " "matches with *x* & *y*. Please use the *color* "
"with a single row if you really want to specify " "keyword-argument or provide a 2-D array "
"with a single row if you intend to specify "
"the same RGB or RGBA value for all points.") "the same RGB or RGBA value for all points.")
valid_shape = False valid_shape = False
if not c_is_mapped: if not c_is_mapped:
@ -4267,14 +4275,14 @@ class Axes(_AxesBase):
The marker size in points**2. The marker size in points**2.
Default is ``rcParams['lines.markersize'] ** 2``. Default is ``rcParams['lines.markersize'] ** 2``.
c : color, sequence, or sequence of colors, optional c : array-like or list of colors or color, optional
The marker color. Possible values: The marker colors. Possible values:
- A single color format string.
- A sequence of colors of length n.
- A scalar or sequence of n numbers to be mapped to colors using - A scalar or sequence of n numbers to be mapped to colors using
*cmap* and *norm*. *cmap* and *norm*.
- A 2-D array in which the rows are RGB or RGBA. - A 2-D array in which the rows are RGB or RGBA.
- A sequence of colors of length n.
- A single color format string.
Note that *c* should not be a single numeric RGB or RGBA sequence Note that *c* should not be a single numeric RGB or RGBA sequence
because that is indistinguishable from an array of values to be because that is indistinguishable from an array of values to be
@ -4283,9 +4291,12 @@ class Axes(_AxesBase):
matching will have precedence in case of a size matching with *x* matching will have precedence in case of a size matching with *x*
and *y*. and *y*.
Defaults to ``None``. In that case the marker color is determined If you wish to specify a single color for all points
by the value of ``color``, ``facecolor`` or ``facecolors``. In case prefer the *color* keyword argument.
those are not specified or ``None``, the marker color is determined
Defaults to `None`. In that case the marker color is determined
by the value of *color*, *facecolor* or *facecolors*. In case
those are not specified or `None`, the marker color is determined
by the next color of the ``Axes``' current "shape and fill" color by the next color of the ``Axes``' current "shape and fill" color
cycle. This cycle defaults to :rc:`axes.prop_cycle`. cycle. This cycle defaults to :rc:`axes.prop_cycle`.

View File

@ -3220,6 +3220,9 @@ class _AxesBase(martist.Artist):
left, right = sorted([left, right], reverse=bool(reverse)) left, right = sorted([left, right], reverse=bool(reverse))
self._viewLim.intervalx = (left, right) self._viewLim.intervalx = (left, right)
# Mark viewlims as no longer stale without triggering an autoscale.
for ax in self._shared_x_axes.get_siblings(self):
ax._stale_viewlim_x = False
if auto is not None: if auto is not None:
self._autoscaleXon = bool(auto) self._autoscaleXon = bool(auto)
@ -3611,6 +3614,9 @@ class _AxesBase(martist.Artist):
bottom, top = sorted([bottom, top], reverse=bool(reverse)) bottom, top = sorted([bottom, top], reverse=bool(reverse))
self._viewLim.intervaly = (bottom, top) self._viewLim.intervaly = (bottom, top)
# Mark viewlims as no longer stale without triggering an autoscale.
for ax in self._shared_y_axes.get_siblings(self):
ax._stale_viewlim_y = False
if auto is not None: if auto is not None:
self._autoscaleYon = bool(auto) self._autoscaleYon = bool(auto)

View File

@ -32,7 +32,7 @@ graphics contexts must implement to serve as a matplotlib backend
The base class for the messaging area. The base class for the messaging area.
""" """
from contextlib import contextmanager from contextlib import contextmanager, suppress
from enum import IntEnum from enum import IntEnum
import functools import functools
import importlib import importlib
@ -52,6 +52,7 @@ from matplotlib import (
from matplotlib._pylab_helpers import Gcf from matplotlib._pylab_helpers import Gcf
from matplotlib.transforms import Affine2D from matplotlib.transforms import Affine2D
from matplotlib.path import Path from matplotlib.path import Path
from matplotlib.cbook import _setattr_cm
try: try:
from PIL import __version__ as PILLOW_VERSION from PIL import __version__ as PILLOW_VERSION
@ -712,6 +713,23 @@ class RendererBase:
Currently only supported by the agg renderer. Currently only supported by the agg renderer.
""" """
def _draw_disabled(self):
"""
Context manager to temporary disable drawing.
This is used for getting the drawn size of Artists. This lets us
run the draw process to update any Python state but does not pay the
cost of the draw_XYZ calls on the canvas.
"""
no_ops = {
meth_name: lambda *args, **kwargs: None
for meth_name in dir(RendererBase)
if (meth_name.startswith("draw_")
or meth_name in ["open_group", "close_group"])
}
return _setattr_cm(self, **no_ops)
class GraphicsContextBase: class GraphicsContextBase:
"""An abstract base class that provides color, line styles, etc.""" """An abstract base class that provides color, line styles, etc."""
@ -1420,7 +1438,6 @@ class MouseEvent(LocationEvent):
(*x*, *y*) in figure coords ((0, 0) = bottom left) (*x*, *y*) in figure coords ((0, 0) = bottom left)
button pressed None, 1, 2, 3, 'up', 'down' button pressed None, 1, 2, 3, 'up', 'down'
""" """
LocationEvent.__init__(self, name, canvas, x, y, guiEvent=guiEvent)
if button in MouseButton.__members__.values(): if button in MouseButton.__members__.values():
button = MouseButton(button) button = MouseButton(button)
self.button = button self.button = button
@ -1428,6 +1445,10 @@ class MouseEvent(LocationEvent):
self.step = step self.step = step
self.dblclick = dblclick self.dblclick = dblclick
# super-init is deferred to the end because it calls back on
# 'axes_enter_event', which requires a fully initialized event.
LocationEvent.__init__(self, name, canvas, x, y, guiEvent=guiEvent)
def __str__(self): def __str__(self):
return (f"{self.name}: " return (f"{self.name}: "
f"xy=({self.x}, {self.y}) xydata=({self.xdata}, {self.ydata}) " f"xy=({self.x}, {self.y}) xydata=({self.xdata}, {self.ydata}) "
@ -1512,19 +1533,19 @@ class KeyEvent(LocationEvent):
cid = fig.canvas.mpl_connect('key_press_event', on_key) cid = fig.canvas.mpl_connect('key_press_event', on_key)
""" """
def __init__(self, name, canvas, key, x=0, y=0, guiEvent=None): def __init__(self, name, canvas, key, x=0, y=0, guiEvent=None):
LocationEvent.__init__(self, name, canvas, x, y, guiEvent=guiEvent)
self.key = key self.key = key
# super-init deferred to the end: callback errors if called before
LocationEvent.__init__(self, name, canvas, x, y, guiEvent=guiEvent)
def _get_renderer(figure, print_method, *, draw_disabled=False): def _get_renderer(figure, print_method):
""" """
Get the renderer that would be used to save a `~.Figure`, and cache it on Get the renderer that would be used to save a `~.Figure`, and cache it on
the figure. the figure.
If *draw_disabled* is True, additionally replace draw_foo methods on If you need a renderer without any active draw methods use
*renderer* by no-ops. This is used by the tight-bbox-saving renderer, renderer._draw_disabled to temporary patch them out at your call site.
which needs to walk through the artist tree to compute the tight-bbox, but
for which the output file may be closed early.
""" """
# This is implemented by triggering a draw, then immediately jumping out of # This is implemented by triggering a draw, then immediately jumping out of
# Figure.draw() by raising an exception. # Figure.draw() by raising an exception.
@ -1540,11 +1561,6 @@ def _get_renderer(figure, print_method, *, draw_disabled=False):
except Done as exc: except Done as exc:
renderer, = figure._cachedRenderer, = exc.args renderer, = figure._cachedRenderer, = exc.args
if draw_disabled:
for meth_name in dir(RendererBase):
if meth_name.startswith("draw_"):
setattr(renderer, meth_name, lambda *args, **kwargs: None)
return renderer return renderer
@ -2052,8 +2068,9 @@ default: :rc:`savefig.bbox`
# Some code (e.g. Figure.show) differentiates between having *no* # Some code (e.g. Figure.show) differentiates between having *no*
# manager and a *None* manager, which should be fixed at some point, # manager and a *None* manager, which should be fixed at some point,
# but this should be fine. # but this should be fine.
with cbook._setattr_cm(self, _is_saving=True, manager=None), \ with cbook._setattr_cm(self, manager=None), \
cbook._setattr_cm(self.figure, dpi=dpi): cbook._setattr_cm(self.figure, dpi=dpi), \
cbook._setattr_cm(canvas, _is_saving=True):
if facecolor is None: if facecolor is None:
facecolor = rcParams['savefig.facecolor'] facecolor = rcParams['savefig.facecolor']
@ -2074,9 +2091,13 @@ default: :rc:`savefig.bbox`
renderer = _get_renderer( renderer = _get_renderer(
self.figure, self.figure,
functools.partial( functools.partial(
print_method, dpi=dpi, orientation=orientation), print_method, dpi=dpi, orientation=orientation)
draw_disabled=True) )
self.figure.draw(renderer) ctx = (renderer._draw_disabled()
if hasattr(renderer, '_draw_disabled')
else suppress())
with ctx:
self.figure.draw(renderer)
bbox_artists = kwargs.pop("bbox_extra_artists", None) bbox_artists = kwargs.pop("bbox_extra_artists", None)
bbox_inches = self.figure.get_tightbbox(renderer, bbox_inches = self.figure.get_tightbbox(renderer,
bbox_extra_artists=bbox_artists) bbox_extra_artists=bbox_artists)
@ -2272,7 +2293,7 @@ default: :rc:`savefig.bbox`
The event loop blocks until a callback function triggers The event loop blocks until a callback function triggers
`stop_event_loop`, or *timeout* is reached. `stop_event_loop`, or *timeout* is reached.
If *timeout* is negative, never timeout. If *timeout* is 0 or negative, never timeout.
Only interactive backends need to reimplement this method and it relies Only interactive backends need to reimplement this method and it relies
on `flush_events` being properly implemented. on `flush_events` being properly implemented.

View File

@ -460,10 +460,18 @@ class FigureManagerTk(FigureManagerBase):
return toolmanager return toolmanager
def resize(self, width, height): def resize(self, width, height):
self.canvas._tkcanvas.master.geometry("%dx%d" % (width, height)) max_size = 1_400_000 # the measured max on xorg 1.20.8 was 1_409_023
if self.toolbar is not None: if (width > max_size or height > max_size) and sys.platform == 'linux':
self.toolbar.configure(width=width) raise ValueError(
'You have requested to resize the '
f'Tk window to ({width}, {height}), one of which '
f'is bigger than {max_size}. At larger sizes xorg will '
'either exit with an error on newer versions (~1.20) or '
'cause corruption on older version (~1.19). We '
'do not expect a window over a million pixel wide or tall '
'to be intended behavior.')
self.canvas._tkcanvas.configure(width=width, height=height)
def show(self): def show(self):
with _restore_foreground_window_at_end(): with _restore_foreground_window_at_end():
@ -541,8 +549,12 @@ class NavigationToolbar2Tk(NavigationToolbar2, tk.Frame):
def set_cursor(self, cursor): def set_cursor(self, cursor):
window = self.canvas.get_tk_widget().master window = self.canvas.get_tk_widget().master
window.configure(cursor=cursord[cursor]) try:
window.update_idletasks() window.configure(cursor=cursord[cursor])
except tkinter.TclError:
pass
else:
window.update_idletasks()
def _Button(self, text, file, command, extension='.gif'): def _Button(self, text, file, command, extension='.gif'):
img_file = str(cbook._get_data_path('images', file + extension)) img_file = str(cbook._get_data_path('images', file + extension))

View File

@ -1394,7 +1394,7 @@ end"""
streamarr['points'] = (flat_points - points_min) * factor streamarr['points'] = (flat_points - points_min) * factor
streamarr['colors'] = flat_colors[:, :colordim] * 255.0 streamarr['colors'] = flat_colors[:, :colordim] * 255.0
self.write(streamarr.tostring()) self.write(streamarr.tobytes())
self.endStream() self.endStream()
self.writeObject(self.gouraudObject, gouraudDict) self.writeObject(self.gouraudObject, gouraudDict)
@ -1487,7 +1487,7 @@ end"""
if png: if png:
self._writePng(data) self._writePng(data)
else: else:
self.currentstream.write(data.tostring()) self.currentstream.write(data.tobytes())
self.endStream() self.endStream()
def writeImages(self): def writeImages(self):

View File

@ -543,8 +543,7 @@ translate
r'\psfrag{%s}[Bl][Bl][1][%f]{\fontsize{%f}{%f}%s}' % ( r'\psfrag{%s}[Bl][Bl][1][%f]{\fontsize{%f}{%f}%s}' % (
thetext, angle, fontsize, fontsize*1.25, tex)) thetext, angle, fontsize, fontsize*1.25, tex))
else: else:
# Stick to the bottom alignment, but this may give incorrect # Stick to the bottom alignment.
# baseline some times.
pos = _nums_to_str(x-corr, y-bl) pos = _nums_to_str(x-corr, y-bl)
self.psfrag.append( self.psfrag.append(
r'\psfrag{%s}[bl][bl][1][%f]{\fontsize{%f}{%f}%s}' % ( r'\psfrag{%s}[bl][bl][1][%f]{\fontsize{%f}{%f}%s}' % (
@ -694,7 +693,7 @@ grestore
streamarr['points'] = (flat_points - points_min) * factor streamarr['points'] = (flat_points - points_min) * factor
streamarr['colors'] = flat_colors[:, :3] * 255.0 streamarr['colors'] = flat_colors[:, :3] * 255.0
stream = quote_ps_string(streamarr.tostring()) stream = quote_ps_string(streamarr.tobytes())
self._pswriter.write(f"""\ self._pswriter.write(f"""\
gsave gsave
@ -1234,19 +1233,21 @@ def convert_psfrags(tmpfile, psfrags, font_preamble, custom_preamble,
""" """
with mpl.rc_context({ with mpl.rc_context({
"text.latex.preamble": "text.latex.preamble":
rcParams["text.latex.preamble"] + mpl.rcParams["text.latex.preamble"] +
r"\usepackage{psfrag,color}" r"\usepackage{psfrag,color}""\n"
r"\usepackage[dvips]{graphicx}" r"\usepackage[dvips]{graphicx}""\n"
r"\PassOptionsToPackage{dvips}{geometry}"}): r"\geometry{papersize={%(width)sin,%(height)sin},"
r"body={%(width)sin,%(height)sin},margin=0in}"
% {"width": paper_width, "height": paper_height}
}):
dvifile = TexManager().make_dvi( dvifile = TexManager().make_dvi(
r"\newgeometry{papersize={%(width)sin,%(height)sin}," "\n"
r"body={%(width)sin,%(height)sin}, margin={0in,0in}}""\n" r"\begin{figure}""\n"
r"\begin{figure}" r" \centering\leavevmode""\n"
r"\centering\leavevmode%(psfrags)s" r" %(psfrags)s""\n"
r"\includegraphics*[angle=%(angle)s]{%(epsfile)s}" r" \includegraphics*[angle=%(angle)s]{%(epsfile)s}""\n"
r"\end{figure}" r"\end{figure}"
% { % {
"width": paper_width, "height": paper_height,
"psfrags": "\n".join(psfrags), "psfrags": "\n".join(psfrags),
"angle": 90 if orientation == 'landscape' else 0, "angle": 90 if orientation == 'landscape' else 0,
"epsfile": pathlib.Path(tmpfile).resolve().as_posix(), "epsfile": pathlib.Path(tmpfile).resolve().as_posix(),

View File

@ -15,10 +15,12 @@ from matplotlib.backend_bases import (
import matplotlib.backends.qt_editor.figureoptions as figureoptions import matplotlib.backends.qt_editor.figureoptions as figureoptions
from matplotlib.backends.qt_editor.formsubplottool import UiSubplotTool from matplotlib.backends.qt_editor.formsubplottool import UiSubplotTool
from matplotlib.backend_managers import ToolManager from matplotlib.backend_managers import ToolManager
from . import qt_compat
from .qt_compat import ( from .qt_compat import (
QtCore, QtGui, QtWidgets, _isdeleted, _getSaveFileName, QtCore, QtGui, QtWidgets, _isdeleted, _getSaveFileName,
is_pyqt5, __version__, QT_API) is_pyqt5, __version__, QT_API, _setDevicePixelRatioF,
_devicePixelRatioF)
backend_version = __version__ backend_version = __version__
@ -267,12 +269,7 @@ class FigureCanvasQT(QtWidgets.QWidget, FigureCanvasBase):
@property @property
def _dpi_ratio(self): def _dpi_ratio(self):
# Not available on Qt4 or some older Qt5. return _devicePixelRatioF(self)
try:
# self.devicePixelRatio() returns 0 in rare cases
return self.devicePixelRatio() or 1
except AttributeError:
return 1
def _update_dpi(self): def _update_dpi(self):
# As described in __init__ above, we need to be careful in cases with # As described in __init__ above, we need to be careful in cases with
@ -454,8 +451,9 @@ class FigureCanvasQT(QtWidgets.QWidget, FigureCanvasBase):
if hasattr(self, "_event_loop") and self._event_loop.isRunning(): if hasattr(self, "_event_loop") and self._event_loop.isRunning():
raise RuntimeError("Event loop already running") raise RuntimeError("Event loop already running")
self._event_loop = event_loop = QtCore.QEventLoop() self._event_loop = event_loop = QtCore.QEventLoop()
if timeout: if timeout > 0:
timer = QtCore.QTimer.singleShot(timeout * 1000, event_loop.quit) timer = QtCore.QTimer.singleShot(int(timeout * 1000),
event_loop.quit)
event_loop.exec_() event_loop.exec_()
def stop_event_loop(self, event=None): def stop_event_loop(self, event=None):
@ -508,7 +506,7 @@ class FigureCanvasQT(QtWidgets.QWidget, FigureCanvasBase):
pen = QtGui.QPen(QtCore.Qt.black, 1 / self._dpi_ratio, pen = QtGui.QPen(QtCore.Qt.black, 1 / self._dpi_ratio,
QtCore.Qt.DotLine) QtCore.Qt.DotLine)
painter.setPen(pen) painter.setPen(pen)
painter.drawRect(*(pt / self._dpi_ratio for pt in rect)) painter.drawRect(*(int(pt / self._dpi_ratio) for pt in rect))
else: else:
def _draw_rect_callback(painter): def _draw_rect_callback(painter):
return return
@ -683,8 +681,7 @@ class NavigationToolbar2QT(NavigationToolbar2, QtWidgets.QToolBar):
if is_pyqt5(): if is_pyqt5():
name = name.replace('.png', '_large.png') name = name.replace('.png', '_large.png')
pm = QtGui.QPixmap(os.path.join(self.basedir, name)) pm = QtGui.QPixmap(os.path.join(self.basedir, name))
if hasattr(pm, 'setDevicePixelRatio'): _setDevicePixelRatioF(pm, _devicePixelRatioF(self))
pm.setDevicePixelRatio(self.canvas._dpi_ratio)
if color is not None: if color is not None:
mask = pm.createMaskFromColor(QtGui.QColor('black'), mask = pm.createMaskFromColor(QtGui.QColor('black'),
QtCore.Qt.MaskOutColor) QtCore.Qt.MaskOutColor)

View File

@ -11,7 +11,7 @@ from .backend_agg import FigureCanvasAgg
from .backend_qt5 import ( from .backend_qt5 import (
QtCore, QtGui, QtWidgets, _BackendQT5, FigureCanvasQT, FigureManagerQT, QtCore, QtGui, QtWidgets, _BackendQT5, FigureCanvasQT, FigureManagerQT,
NavigationToolbar2QT, backend_version) NavigationToolbar2QT, backend_version)
from .qt_compat import QT_API from .qt_compat import QT_API, _setDevicePixelRatioF
class FigureCanvasQTAgg(FigureCanvasAgg, FigureCanvasQT): class FigureCanvasQTAgg(FigureCanvasAgg, FigureCanvasQT):
@ -38,45 +38,44 @@ class FigureCanvasQTAgg(FigureCanvasAgg, FigureCanvasQT):
return return
painter = QtGui.QPainter(self) painter = QtGui.QPainter(self)
try:
# See documentation of QRect: bottom() and right() are off
# by 1, so use left() + width() and top() + height().
rect = event.rect()
# scale rect dimensions using the screen dpi ratio to get
# correct values for the Figure coordinates (rather than
# QT5's coords)
width = rect.width() * self._dpi_ratio
height = rect.height() * self._dpi_ratio
left, top = self.mouseEventCoords(rect.topLeft())
# shift the "top" by the height of the image to get the
# correct corner for our coordinate system
bottom = top - height
# same with the right side of the image
right = left + width
# create a buffer using the image bounding box
bbox = Bbox([[left, bottom], [right, top]])
reg = self.copy_from_bbox(bbox)
buf = cbook._unmultiplied_rgba8888_to_premultiplied_argb32(
memoryview(reg))
# See documentation of QRect: bottom() and right() are off by 1, so use # clear the widget canvas
# left() + width() and top() + height(). painter.eraseRect(rect)
rect = event.rect()
# scale rect dimensions using the screen dpi ratio to get
# correct values for the Figure coordinates (rather than QT5's coords)
width = rect.width() * self._dpi_ratio
height = rect.height() * self._dpi_ratio
left, top = self.mouseEventCoords(rect.topLeft())
# shift the "top" by the height of the image to get the
# correct corner for our coordinate system
bottom = top - height
# same with the right side of the image
right = left + width
# create a buffer using the image bounding box
bbox = Bbox([[left, bottom], [right, top]])
reg = self.copy_from_bbox(bbox)
buf = cbook._unmultiplied_rgba8888_to_premultiplied_argb32(
memoryview(reg))
# clear the widget canvas qimage = QtGui.QImage(buf, buf.shape[1], buf.shape[0],
painter.eraseRect(rect) QtGui.QImage.Format_ARGB32_Premultiplied)
_setDevicePixelRatioF(qimage, self._dpi_ratio)
# set origin using original QT coordinates
origin = QtCore.QPoint(rect.left(), rect.top())
painter.drawImage(origin, qimage)
# Adjust the buf reference count to work around a memory
# leak bug in QImage under PySide on Python 3.
if QT_API in ('PySide', 'PySide2'):
ctypes.c_long.from_address(id(buf)).value = 1
qimage = QtGui.QImage(buf, buf.shape[1], buf.shape[0], self._draw_rect_callback(painter)
QtGui.QImage.Format_ARGB32_Premultiplied) finally:
if hasattr(qimage, 'setDevicePixelRatio'): painter.end()
# Not available on Qt4 or some older Qt5.
qimage.setDevicePixelRatio(self._dpi_ratio)
# set origin using original QT coordinates
origin = QtCore.QPoint(rect.left(), rect.top())
painter.drawImage(origin, qimage)
# Adjust the buf reference count to work around a memory
# leak bug in QImage under PySide on Python 3.
if QT_API in ('PySide', 'PySide2'):
ctypes.c_long.from_address(id(buf)).value = 1
self._draw_rect_callback(painter)
painter.end()
def blit(self, bbox=None): def blit(self, bbox=None):
# docstring inherited # docstring inherited
@ -86,7 +85,7 @@ class FigureCanvasQTAgg(FigureCanvasAgg, FigureCanvasQT):
bbox = self.figure.bbox bbox = self.figure.bbox
# repaint uses logical pixels, not physical pixels like the renderer. # repaint uses logical pixels, not physical pixels like the renderer.
l, b, w, h = [pt / self._dpi_ratio for pt in bbox.bounds] l, b, w, h = [int(pt / self._dpi_ratio) for pt in bbox.bounds]
t = b + h t = b + h
self.repaint(l, self.renderer.height / self._dpi_ratio - t, w, h) self.repaint(l, self.renderer.height / self._dpi_ratio - t, w, h)

View File

@ -2,7 +2,7 @@ import ctypes
from .backend_cairo import cairo, FigureCanvasCairo, RendererCairo from .backend_cairo import cairo, FigureCanvasCairo, RendererCairo
from .backend_qt5 import QtCore, QtGui, _BackendQT5, FigureCanvasQT from .backend_qt5 import QtCore, QtGui, _BackendQT5, FigureCanvasQT
from .qt_compat import QT_API from .qt_compat import QT_API, _setDevicePixelRatioF
class FigureCanvasQTCairo(FigureCanvasQT, FigureCanvasCairo): class FigureCanvasQTCairo(FigureCanvasQT, FigureCanvasCairo):
@ -19,8 +19,8 @@ class FigureCanvasQTCairo(FigureCanvasQT, FigureCanvasCairo):
def paintEvent(self, event): def paintEvent(self, event):
self._update_dpi() self._update_dpi()
dpi_ratio = self._dpi_ratio dpi_ratio = self._dpi_ratio
width = dpi_ratio * self.width() width = int(dpi_ratio * self.width())
height = dpi_ratio * self.height() height = int(dpi_ratio * self.height())
if (width, height) != self._renderer.get_canvas_width_height(): if (width, height) != self._renderer.get_canvas_width_height():
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
self._renderer.set_ctx_from_surface(surface) self._renderer.set_ctx_from_surface(surface)
@ -33,9 +33,7 @@ class FigureCanvasQTCairo(FigureCanvasQT, FigureCanvasCairo):
# QImage under PySide on Python 3. # QImage under PySide on Python 3.
if QT_API == 'PySide': if QT_API == 'PySide':
ctypes.c_long.from_address(id(buf)).value = 1 ctypes.c_long.from_address(id(buf)).value = 1
if hasattr(qimage, 'setDevicePixelRatio'): _setDevicePixelRatioF(qimage, dpi_ratio)
# Not available on Qt4 or some older Qt5.
qimage.setDevicePixelRatio(dpi_ratio)
painter = QtGui.QPainter(self) painter = QtGui.QPainter(self)
painter.eraseRect(event.rect()) painter.eraseRect(event.rect())
painter.drawImage(0, 0, qimage) painter.drawImage(0, 0, qimage)

View File

@ -288,7 +288,7 @@ class RendererWx(RendererBase):
w = self.width w = self.width
h = self.height h = self.height
rows, cols = im.shape[:2] rows, cols = im.shape[:2]
bitmap = wx.Bitmap.FromBufferRGBA(cols, rows, im.tostring()) bitmap = wx.Bitmap.FromBufferRGBA(cols, rows, im.tobytes())
gc = self.get_gc() gc = self.get_gc()
gc.select() gc.select()
gc.gfx_ctx.DrawBitmap(bitmap, int(l), int(self.height - b), gc.gfx_ctx.DrawBitmap(bitmap, int(l), int(self.height - b),
@ -702,7 +702,9 @@ class _FigureCanvasWxBase(FigureCanvasBase, wx.Panel):
The 'WXAgg' backend sets origin accordingly. The 'WXAgg' backend sets origin accordingly.
""" """
DEBUG_MSG("gui_repaint()", 1, self) DEBUG_MSG("gui_repaint()", 1, self)
if self.IsShownOnScreen(): # The "if self" check avoids a "wrapped C/C++ object has been deleted"
# RuntimeError if doing things after window is closed.
if self and self.IsShownOnScreen():
if not drawDC: if not drawDC:
# not called from OnPaint use a ClientDC # not called from OnPaint use a ClientDC
drawDC = wx.ClientDC(self) drawDC = wx.ClientDC(self)
@ -776,14 +778,14 @@ class _FigureCanvasWxBase(FigureCanvasBase, wx.Panel):
# no change in size # no change in size
return return
self._width, self._height = size self._width, self._height = size
# Create a new, correctly sized bitmap
self.bitmap = wx.Bitmap(self._width, self._height)
self._isDrawn = False self._isDrawn = False
if self._width <= 1 or self._height <= 1: if self._width <= 1 or self._height <= 1:
return # Empty figure return # Empty figure
# Create a new, correctly sized bitmap
self.bitmap = wx.Bitmap(self._width, self._height)
dpival = self.figure.dpi dpival = self.figure.dpi
winch = self._width / dpival winch = self._width / dpival
hinch = self._height / dpival hinch = self._height / dpival
@ -978,14 +980,11 @@ class FigureCanvasWx(_FigureCanvasWxBase):
# Now that we have rendered into the bitmap, save it to the appropriate # Now that we have rendered into the bitmap, save it to the appropriate
# file type and clean up. # file type and clean up.
if isinstance(filename, str): if (cbook.is_writable_file_like(filename) and
if not image.SaveFile(filename, filetype): not isinstance(image, wx.Image)):
raise RuntimeError(f'Could not save figure to {filename}') image = image.ConvertToImage()
elif cbook.is_writable_file_like(filename): if not image.SaveFile(filename, filetype):
if not isinstance(image, wx.Image): raise RuntimeError(f'Could not save figure to {filename}')
image = image.ConvertToImage()
if not image.SaveStream(filename, filetype):
raise RuntimeError(f'Could not save figure to {filename}')
# Restore everything to normal # Restore everything to normal
self.bitmap = origBitmap self.bitmap = origBitmap
@ -997,7 +996,10 @@ class FigureCanvasWx(_FigureCanvasWxBase):
# otherwise. # otherwise.
if self._isDrawn: if self._isDrawn:
self.draw() self.draw()
self.Refresh() # The "if self" check avoids a "wrapped C/C++ object has been deleted"
# RuntimeError if doing things after window is closed.
if self:
self.Refresh()
######################################################################## ########################################################################
@ -1501,7 +1503,7 @@ class NavigationToolbar2Wx(NavigationToolbar2, wx.ToolBar):
def set_message(self, s): def set_message(self, s):
status_bar = self.GetTopLevelParent().GetStatusBar() status_bar = self.GetTopLevelParent().GetStatusBar()
if status_bar is not None: if status_bar is not None and hasattr(status_bar, 'set_function'):
status_bar.set_function(s) status_bar.set_function(s)
def set_history_buttons(self): def set_history_buttons(self):

View File

@ -92,7 +92,7 @@ def _setup_pyqt4():
def _setup_pyqt4_internal(api): def _setup_pyqt4_internal(api):
global QtCore, QtGui, QtWidgets, \ global QtCore, QtGui, QtWidgets, \
__version__, is_pyqt5, _getSaveFileName __version__, is_pyqt5, _isdeleted, _getSaveFileName
# List of incompatible APIs: # List of incompatible APIs:
# http://pyqt.sourceforge.net/Docs/PyQt4/incompatible_apis.html # http://pyqt.sourceforge.net/Docs/PyQt4/incompatible_apis.html
_sip_apis = ["QDate", "QDateTime", "QString", "QTextStream", "QTime", _sip_apis = ["QDate", "QDateTime", "QString", "QTextStream", "QTime",
@ -173,4 +173,38 @@ else: # We should not get there.
# These globals are only defined for backcompatibility purposes. # These globals are only defined for backcompatibility purposes.
ETS = dict(pyqt=(QT_API_PYQTv2, 4), pyside=(QT_API_PYSIDE, 4), ETS = dict(pyqt=(QT_API_PYQTv2, 4), pyside=(QT_API_PYSIDE, 4),
pyqt5=(QT_API_PYQT5, 5), pyside2=(QT_API_PYSIDE2, 5)) pyqt5=(QT_API_PYQT5, 5), pyside2=(QT_API_PYSIDE2, 5))
QT_RC_MAJOR_VERSION = 5 if is_pyqt5() else 4
QT_RC_MAJOR_VERSION = int(QtCore.qVersion().split(".")[0])
def _devicePixelRatioF(obj):
"""
Return obj.devicePixelRatioF() with graceful fallback for older Qt.
This can be replaced by the direct call when we require Qt>=5.6.
"""
try:
# Not available on Qt<5.6
return obj.devicePixelRatioF() or 1
except AttributeError:
pass
try:
# Not available on Qt4 or some older Qt5.
# self.devicePixelRatio() returns 0 in rare cases
return obj.devicePixelRatio() or 1
except AttributeError:
return 1
def _setDevicePixelRatioF(obj, val):
"""
Call obj.setDevicePixelRatioF(val) with graceful fallback for older Qt.
This can be replaced by the direct call when we require Qt>=5.6.
"""
if hasattr(obj, 'setDevicePixelRatioF'):
# Not available on Qt<5.6
obj.setDevicePixelRatioF(val)
elif hasattr(obj, 'setDevicePixelRatio'):
# Not available on Qt4 or some older Qt5.
obj.setDevicePixelRatio(val)

View File

@ -184,7 +184,7 @@ def deprecated(since, *, message='', name='', alternative='', pending=False,
obj.__doc__ = new_doc obj.__doc__ = new_doc
except AttributeError: # Can't set on some extension objects. except AttributeError: # Can't set on some extension objects.
pass pass
obj.__init__ = wrapper obj.__init__ = functools.wraps(obj.__init__)(wrapper)
return obj return obj
elif isinstance(obj, property): elif isinstance(obj, property):

View File

@ -213,32 +213,31 @@ class Collection(artist.Artist, cm.ScalarMappable):
# we may have transform.contains_branch(transData) but not # we may have transform.contains_branch(transData) but not
# transforms.get_affine().contains_branch(transData). But later, # transforms.get_affine().contains_branch(transData). But later,
# be careful to only apply the affine part that remains. # be careful to only apply the affine part that remains.
if not transOffset.is_affine:
offsets = transOffset.transform_non_affine(offsets)
if isinstance(offsets, np.ma.MaskedArray): if isinstance(offsets, np.ma.MaskedArray):
offsets = offsets.filled(np.nan) offsets = offsets.filled(np.nan)
# get_path_collection_extents handles nan but not masked arrays # get_path_collection_extents handles nan but not masked arrays
if len(paths) and len(offsets): if len(paths) and len(offsets):
if transform.contains_branch(transData): if any(transform.contains_branch_seperately(transData)):
# collections that are just in data units (like quiver) # collections that are just in data units (like quiver)
# can properly have the axes limits set by their shape + # can properly have the axes limits set by their shape +
# offset. LineCollections that have no offsets can # offset. LineCollections that have no offsets can
# also use this algorithm (like streamplot). # also use this algorithm (like streamplot).
result = mpath.get_path_collection_extents( result = mpath.get_path_collection_extents(
transform.get_affine(), paths, self.get_transforms(), transform.get_affine(), paths, self.get_transforms(),
offsets, transOffset.get_affine().frozen()) transOffset.transform_non_affine(offsets),
return result.inverse_transformed(transData) transOffset.get_affine().frozen())
return result.transformed(transData.inverted())
if not self._offsetsNone: if not self._offsetsNone:
# this is for collections that have their paths (shapes) # this is for collections that have their paths (shapes)
# in physical, axes-relative, or figure-relative units # in physical, axes-relative, or figure-relative units
# (i.e. like scatter). We can't uniquely set limits based on # (i.e. like scatter). We can't uniquely set limits based on
# those shapes, so we just set the limits based on their # those shapes, so we just set the limits based on their
# location. # location.
# Finish the transform:
offsets = (transOffset.get_affine() + offsets = (transOffset - transData).transform(offsets)
transData.inverted()).transform(offsets) # note A-B means A B^{-1}
offsets = np.ma.masked_invalid(offsets) offsets = np.ma.masked_invalid(offsets)
if not offsets.mask.all(): if not offsets.mask.all():
points = np.row_stack((offsets.min(axis=0), points = np.row_stack((offsets.min(axis=0),

View File

@ -405,7 +405,7 @@ class ColorbarBase(_ColorbarMappableDummy):
ticklocation : {'auto', 'left', 'right', 'top', 'bottom'} ticklocation : {'auto', 'left', 'right', 'top', 'bottom'}
extend : {'neiter', 'both', 'min', 'max'} extend : {'neither', 'both', 'min', 'max'}
spacing : {'uniform', 'proportional'} spacing : {'uniform', 'proportional'}

View File

@ -1713,7 +1713,7 @@ class LightSource:
completely in shadow and 1 is completely illuminated. completely in shadow and 1 is completely illuminated.
""" """
# Because most image and raster gis data has the first row in the array # Because most image and raster GIS data has the first row in the array
# as the "top" of the image, dy is implicitly negative. This is # as the "top" of the image, dy is implicitly negative. This is
# consistent to what `imshow` assumes, as well. # consistent to what `imshow` assumes, as well.
dy = -dy dy = -dy

View File

@ -269,6 +269,12 @@ class Dvi:
maxx = max(maxx, x + w) maxx = max(maxx, x + w)
maxy = max(maxy, y + e) maxy = max(maxy, y + e)
maxy_pure = max(maxy_pure, y) maxy_pure = max(maxy_pure, y)
if self._baseline_v is not None:
maxy_pure = self._baseline_v # This should normally be the case.
self._baseline_v = None
if not self.text and not self.boxes: # Avoid infs/nans from inf+/-inf.
return Page(text=[], boxes=[], width=0, height=0, descent=0)
if self.dpi is None: if self.dpi is None:
# special case for ease of debugging: output raw dvi coordinates # special case for ease of debugging: output raw dvi coordinates
@ -296,9 +302,24 @@ class Dvi:
Read one page from the file. Return True if successful, Read one page from the file. Return True if successful,
False if there were no more pages. False if there were no more pages.
""" """
# Pages appear to start with the sequence
# bop (begin of page)
# xxx comment
# down
# push
# down, down
# push
# down (possibly multiple)
# push <= here, v is the baseline position.
# etc.
# (dviasm is useful to explore this structure.)
self._baseline_v = None
while True: while True:
byte = self.file.read(1)[0] byte = self.file.read(1)[0]
self._dtable[byte](self, byte) self._dtable[byte](self, byte)
if (self._baseline_v is None
and len(getattr(self, "stack", [])) == 3):
self._baseline_v = self.v
if byte == 140: # end of page if byte == 140: # end of page
return True return True
if self.state is _dvistate.post_post: # end of file if self.state is _dvistate.post_post: # end of file

View File

@ -2478,7 +2478,7 @@ default: 'top'
from .tight_layout import ( from .tight_layout import (
get_renderer, get_subplotspec_list, get_tight_layout_figure) get_renderer, get_subplotspec_list, get_tight_layout_figure)
from contextlib import suppress
subplotspec_list = get_subplotspec_list(self.axes) subplotspec_list = get_subplotspec_list(self.axes)
if None in subplotspec_list: if None in subplotspec_list:
cbook._warn_external("This figure includes Axes that are not " cbook._warn_external("This figure includes Axes that are not "
@ -2487,10 +2487,13 @@ default: 'top'
if renderer is None: if renderer is None:
renderer = get_renderer(self) renderer = get_renderer(self)
ctx = (renderer._draw_disabled()
kwargs = get_tight_layout_figure( if hasattr(renderer, '_draw_disabled')
self, self.axes, subplotspec_list, renderer, else suppress())
pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect) with ctx:
kwargs = get_tight_layout_figure(
self, self.axes, subplotspec_list, renderer,
pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect)
if kwargs: if kwargs:
self.subplots_adjust(**kwargs) self.subplots_adjust(**kwargs)

View File

@ -48,9 +48,9 @@ class GridSpecBase:
self.set_width_ratios(width_ratios) self.set_width_ratios(width_ratios)
def __repr__(self): def __repr__(self):
height_arg = (', height_ratios=%r' % self._row_height_ratios height_arg = (', height_ratios=%r' % (self._row_height_ratios,)
if self._row_height_ratios is not None else '') if self._row_height_ratios is not None else '')
width_arg = (', width_ratios=%r' % self._col_width_ratios width_arg = (', width_ratios=%r' % (self._col_width_ratios,)
if self._col_width_ratios is not None else '') if self._col_width_ratios is not None else '')
return '{clsname}({nrows}, {ncols}{optionals})'.format( return '{clsname}({nrows}, {ncols}{optionals})'.format(
clsname=self.__class__.__name__, clsname=self.__class__.__name__,

View File

@ -1592,14 +1592,12 @@ class Arc(Ellipse):
calculation much easier than doing rotated ellipse calculation much easier than doing rotated ellipse
intersection directly). intersection directly).
This uses the "line intersecting a circle" algorithm This uses the "line intersecting a circle" algorithm from:
from:
Vince, John. *Geometry for Computer Graphics: Formulae, Vince, John. *Geometry for Computer Graphics: Formulae,
Examples & Proofs.* London: Springer-Verlag, 2005. Examples & Proofs.* London: Springer-Verlag, 2005.
2. The angles of each of the intersection points are 2. The angles of each of the intersection points are calculated.
calculated.
3. Proceeding counterclockwise starting in the positive 3. Proceeding counterclockwise starting in the positive
x-direction, each of the visible arc-segments between the x-direction, each of the visible arc-segments between the
@ -1609,6 +1607,8 @@ class Arc(Ellipse):
""" """
if not hasattr(self, 'axes'): if not hasattr(self, 'axes'):
raise RuntimeError('Arcs can only be used in Axes instances') raise RuntimeError('Arcs can only be used in Axes instances')
if not self.get_visible():
return
self._recompute_transform() self._recompute_transform()
@ -1621,44 +1621,62 @@ class Arc(Ellipse):
theta = np.deg2rad(theta) theta = np.deg2rad(theta)
x = np.cos(theta) x = np.cos(theta)
y = np.sin(theta) y = np.sin(theta)
return np.rad2deg(np.arctan2(scale * y, x)) stheta = np.rad2deg(np.arctan2(scale * y, x))
theta1 = theta_stretch(self.theta1, width / height) # arctan2 has the range [-pi, pi], we expect [0, 2*pi]
theta2 = theta_stretch(self.theta2, width / height) return (stheta + 360) % 360
# Get width and height in pixels theta1 = self.theta1
width, height = self.get_transform().transform((width, height)) theta2 = self.theta2
if (
# if we need to stretch the angles because we are distorted
width != height
# and we are not doing a full circle.
#
# 0 and 360 do not exactly round-trip through the angle
# stretching (due to both float precision limitations and
# the difference between the range of arctan2 [-pi, pi] and
# this method [0, 360]) so avoid doing it if we don't have to.
and not (theta1 != theta2 and theta1 % 360 == theta2 % 360)
):
theta1 = theta_stretch(self.theta1, width / height)
theta2 = theta_stretch(self.theta2, width / height)
# Get width and height in pixels we need to use
# `self.get_data_transform` rather than `self.get_transform`
# because we want the transform from dataspace to the
# screen space to estimate how big the arc will be in physical
# units when rendered (the transform that we get via
# `self.get_transform()` goes from an idealized unit-radius
# space to screen space).
data_to_screen_trans = self.get_data_transform()
pwidth, pheight = (data_to_screen_trans.transform((width, height)) -
data_to_screen_trans.transform((0, 0)))
inv_error = (1.0 / 1.89818e-6) * 0.5 inv_error = (1.0 / 1.89818e-6) * 0.5
if width < inv_error and height < inv_error:
if pwidth < inv_error and pheight < inv_error:
self._path = Path.arc(theta1, theta2) self._path = Path.arc(theta1, theta2)
return Patch.draw(self, renderer) return Patch.draw(self, renderer)
def iter_circle_intersect_on_line(x0, y0, x1, y1): def line_circle_intersect(x0, y0, x1, y1):
dx = x1 - x0 dx = x1 - x0
dy = y1 - y0 dy = y1 - y0
dr2 = dx * dx + dy * dy dr2 = dx * dx + dy * dy
D = x0 * y1 - x1 * y0 D = x0 * y1 - x1 * y0
D2 = D * D D2 = D * D
discrim = dr2 - D2 discrim = dr2 - D2
if discrim >= 0.0:
# Single (tangential) intersection sign_dy = np.copysign(1, dy) # +/-1, never 0.
if discrim == 0.0:
x = (D * dy) / dr2
y = (-D * dx) / dr2
yield x, y
elif discrim > 0.0:
# The definition of "sign" here is different from
# np.sign: we never want to get 0.0
if dy < 0.0:
sign_dy = -1.0
else:
sign_dy = 1.0
sqrt_discrim = np.sqrt(discrim) sqrt_discrim = np.sqrt(discrim)
for sign in (1., -1.): return np.array(
x = (D * dy + sign * sign_dy * dx * sqrt_discrim) / dr2 [[(D * dy + sign_dy * dx * sqrt_discrim) / dr2,
y = (-D * dx + sign * np.abs(dy) * sqrt_discrim) / dr2 (-D * dx + abs(dy) * sqrt_discrim) / dr2],
yield x, y [(D * dy - sign_dy * dx * sqrt_discrim) / dr2,
(-D * dx - abs(dy) * sqrt_discrim) / dr2]])
else:
return np.empty((0, 2))
def iter_circle_intersect_on_line_seg(x0, y0, x1, y1): def segment_circle_intersect(x0, y0, x1, y1):
epsilon = 1e-9 epsilon = 1e-9
if x1 < x0: if x1 < x0:
x0e, x1e = x1, x0 x0e, x1e = x1, x0
@ -1668,40 +1686,34 @@ class Arc(Ellipse):
y0e, y1e = y1, y0 y0e, y1e = y1, y0
else: else:
y0e, y1e = y0, y1 y0e, y1e = y0, y1
x0e -= epsilon xys = line_circle_intersect(x0, y0, x1, y1)
y0e -= epsilon xs, ys = xys.T
x1e += epsilon return xys[
y1e += epsilon (x0e - epsilon < xs) & (xs < x1e + epsilon)
for x, y in iter_circle_intersect_on_line(x0, y0, x1, y1): & (y0e - epsilon < ys) & (ys < y1e + epsilon)
if x0e <= x <= x1e and y0e <= y <= y1e: ]
yield x, y
# Transforms the axes box_path so that it is relative to the unit # Transforms the axes box_path so that it is relative to the unit
# circle in the same way that it is relative to the desired ellipse. # circle in the same way that it is relative to the desired ellipse.
box_path = Path.unit_rectangle()
box_path_transform = (transforms.BboxTransformTo(self.axes.bbox) box_path_transform = (transforms.BboxTransformTo(self.axes.bbox)
- self.get_transform()) + self.get_transform().inverted())
box_path = box_path.transformed(box_path_transform) box_path = Path.unit_rectangle().transformed(box_path_transform)
thetas = set() thetas = set()
# For each of the point pairs, there is a line segment # For each of the point pairs, there is a line segment
for p0, p1 in zip(box_path.vertices[:-1], box_path.vertices[1:]): for p0, p1 in zip(box_path.vertices[:-1], box_path.vertices[1:]):
x0, y0 = p0 xy = segment_circle_intersect(*p0, *p1)
x1, y1 = p1 x, y = xy.T
for x, y in iter_circle_intersect_on_line_seg(x0, y0, x1, y1): # arctan2 return [-pi, pi), the rest of our angles are in
theta = np.arccos(x) # [0, 360], adjust as needed.
if y < 0: theta = (np.rad2deg(np.arctan2(y, x)) + 360) % 360
theta = 2 * np.pi - theta thetas.update(theta[(theta1 < theta) & (theta < theta2)])
# Convert radians to angles
theta = np.rad2deg(theta)
if theta1 < theta < theta2:
thetas.add(theta)
thetas = sorted(thetas) + [theta2] thetas = sorted(thetas) + [theta2]
last_theta = theta1 last_theta = theta1
theta1_rad = np.deg2rad(theta1) theta1_rad = np.deg2rad(theta1)
inside = box_path.contains_point((np.cos(theta1_rad), inside = box_path.contains_point(
np.sin(theta1_rad))) (np.cos(theta1_rad), np.sin(theta1_rad))
)
# save original path # save original path
path_original = self._path path_original = self._path

View File

@ -953,6 +953,7 @@ class PolarAxes(Axes):
return self._yaxis_text_transform + pad_shift, 'center', halign return self._yaxis_text_transform + pad_shift, 'center', halign
def draw(self, *args, **kwargs): def draw(self, *args, **kwargs):
self._unstale_viewLim()
thetamin, thetamax = np.rad2deg(self._realViewLim.intervalx) thetamin, thetamax = np.rad2deg(self._realViewLim.intervalx)
if thetamin > thetamax: if thetamin > thetamax:
thetamin, thetamax = thetamax, thetamin thetamin, thetamax = thetamax, thetamin

View File

@ -1500,7 +1500,7 @@ def yticks(ticks=None, labels=None, **kwargs):
Parameters Parameters
---------- ----------
ticks : array-like, optional ticks : array-like, optional
The list of xtick locations. Passing an empty list removes all xticks. The list of ytick locations. Passing an empty list removes all yticks.
labels : array-like, optional labels : array-like, optional
The labels to place at the given *ticks* locations. This argument can The labels to place at the given *ticks* locations. This argument can
only be passed if *ticks* is passed as well. only be passed if *ticks* is passed as well.

View File

@ -43,14 +43,14 @@ STYLE_BLACKLIST = {
def _remove_blacklisted_style_params(d, warn=True): def _remove_blacklisted_style_params(d, warn=True):
o = {} o = {}
for key, val in d.items(): for key in d: # prevent triggering RcParams.__getitem__('backend')
if key in STYLE_BLACKLIST: if key in STYLE_BLACKLIST:
if warn: if warn:
cbook._warn_external( cbook._warn_external(
"Style includes a parameter, '{0}', that is not related " "Style includes a parameter, '{0}', that is not related "
"to style. Ignoring".format(key)) "to style. Ignoring".format(key))
else: else:
o[key] = val o[key] = d[key]
return o return o

View File

@ -211,9 +211,9 @@ class _SVGConverter(_Converter):
# Inkscape's output is not localized but gtk's is, so the output # Inkscape's output is not localized but gtk's is, so the output
# stream probably has a mixed encoding. Using the filesystem # stream probably has a mixed encoding. Using the filesystem
# encoding should at least get the filenames right... # encoding should at least get the filenames right...
self._stderr.seek(0) self._proc.stderr.seek(0)
raise ImageComparisonFailure( raise ImageComparisonFailure(
self._stderr.read().decode( self._proc.stderr.read().decode(
sys.getfilesystemencoding(), "replace")) sys.getfilesystemencoding(), "replace"))

View File

@ -358,9 +358,9 @@ def check_figures_equal(*, extensions=("png", "pdf", "svg"), tol=0):
""" """
Decorator for test cases that generate and compare two figures. Decorator for test cases that generate and compare two figures.
The decorated function must take two arguments, *fig_test* and *fig_ref*, The decorated function must take two keyword arguments, *fig_test*
and draw the test and reference images on them. After the function and *fig_ref*, and draw the test and reference images on them.
returns, the figures are saved and compared. After the function returns, the figures are saved and compared.
This decorator should be preferred over `image_comparison` when possible in This decorator should be preferred over `image_comparison` when possible in
order to keep the size of the test suite from ballooning. order to keep the size of the test suite from ballooning.
@ -381,6 +381,7 @@ def check_figures_equal(*, extensions=("png", "pdf", "svg"), tol=0):
def test_plot(fig_test, fig_ref): def test_plot(fig_test, fig_ref):
fig_test.subplots().plot([1, 3, 5]) fig_test.subplots().plot([1, 3, 5])
fig_ref.subplots().plot([0, 1, 2], [1, 3, 5]) fig_ref.subplots().plot([0, 1, 2], [1, 3, 5])
""" """
ALLOWED_CHARS = set(string.digits + string.ascii_letters + '_-[]()') ALLOWED_CHARS = set(string.digits + string.ascii_letters + '_-[]()')
KEYWORD_ONLY = inspect.Parameter.KEYWORD_ONLY KEYWORD_ONLY = inspect.Parameter.KEYWORD_ONLY
@ -390,6 +391,11 @@ def check_figures_equal(*, extensions=("png", "pdf", "svg"), tol=0):
_, result_dir = _image_directories(func) _, result_dir = _image_directories(func)
old_sig = inspect.signature(func) old_sig = inspect.signature(func)
if not {"fig_test", "fig_ref"}.issubset(old_sig.parameters):
raise ValueError("The decorated function must have at least the "
"parameters 'fig_ref' and 'fig_test', but your "
f"function has the signature {old_sig}")
@pytest.mark.parametrize("ext", extensions) @pytest.mark.parametrize("ext", extensions)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
ext = kwargs['ext'] ext = kwargs['ext']

View File

@ -750,7 +750,11 @@ def test_polar_invertedylim():
def test_polar_invertedylim_rorigin(): def test_polar_invertedylim_rorigin():
fig = plt.figure() fig = plt.figure()
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True) ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True)
ax.set_ylim(2, 0) ax.yaxis.set_inverted(True)
# Set the rlims to inverted (2, 0) without calling set_rlim, to check that
# viewlims are correctly unstaled before draw()ing.
ax.plot([0, 0], [0, 2], c="none")
ax.margins(0)
ax.set_rorigin(3) ax.set_rorigin(3)
@ -2084,6 +2088,22 @@ class TestScatter:
c=c_case, edgecolors="black", kwargs={}, xsize=xsize, c=c_case, edgecolors="black", kwargs={}, xsize=xsize,
get_next_color_func=get_next_color) get_next_color_func=get_next_color)
@pytest.mark.style('default')
@check_figures_equal(extensions=["png"])
def test_scatter_single_color_c(self, fig_test, fig_ref):
rgb = [[1, 0.5, 0.05]]
rgba = [[1, 0.5, 0.05, .5]]
# set via color kwarg
ax_ref = fig_ref.subplots()
ax_ref.scatter(np.ones(3), range(3), color=rgb)
ax_ref.scatter(np.ones(4)*2, range(4), color=rgba)
# set via broadcasting via c
ax_test = fig_test.subplots()
ax_test.scatter(np.ones(3), range(3), c=rgb)
ax_test.scatter(np.ones(4)*2, range(4), c=rgba)
def _params(c=None, xsize=2, **kwargs): def _params(c=None, xsize=2, **kwargs):
edgecolors = kwargs.pop('edgecolors', None) edgecolors = kwargs.pop('edgecolors', None)
@ -6674,3 +6694,33 @@ def test_invisible_axes():
assert fig.canvas.inaxes((200, 200)) is not None assert fig.canvas.inaxes((200, 200)) is not None
ax.set_visible(False) ax.set_visible(False)
assert fig.canvas.inaxes((200, 200)) is None assert fig.canvas.inaxes((200, 200)) is None
@pytest.mark.parametrize('auto', (True, False, None))
def test_unautoscaley(auto):
fig, ax = plt.subplots()
x = np.arange(100)
y = np.linspace(-.1, .1, 100)
ax.scatter(x, y)
post_auto = ax.get_autoscaley_on() if auto is None else auto
ax.set_ylim((-.5, .5), auto=auto)
assert post_auto == ax.get_autoscaley_on()
fig.canvas.draw()
assert_array_equal(ax.get_ylim(), (-.5, .5))
@pytest.mark.parametrize('auto', (True, False, None))
def test_unautoscalex(auto):
fig, ax = plt.subplots()
x = np.arange(100)
y = np.linspace(-.1, .1, 100)
ax.scatter(y, x)
post_auto = ax.get_autoscalex_on() if auto is None else auto
ax.set_xlim((-.5, .5), auto=auto)
assert post_auto == ax.get_autoscalex_on()
fig.canvas.draw()
assert_array_equal(ax.get_xlim(), (-.5, .5))

View File

@ -253,6 +253,29 @@ def test_dpi_ratio_change():
assert qt_canvas.get_width_height() == (600, 240) assert qt_canvas.get_width_height() == (600, 240)
assert (fig.get_size_inches() == (5, 2)).all() assert (fig.get_size_inches() == (5, 2)).all()
p.return_value = 1.5
assert qt_canvas._dpi_ratio == 1.5
qt_canvas.draw()
qApp.processEvents()
# this second processEvents is required to fully run the draw.
# On `update` we notice the DPI has changed and trigger a
# resize event to refresh, the second processEvents is
# required to process that and fully update the window sizes.
qApp.processEvents()
# The DPI and the renderer width/height change
assert fig.dpi == 180
assert qt_canvas.renderer.width == 900
assert qt_canvas.renderer.height == 360
# The actual widget size and figure physical size don't change
assert size.width() == 600
assert size.height() == 240
assert qt_canvas.get_width_height() == (600, 240)
assert (fig.get_size_inches() == (5, 2)).all()
@pytest.mark.backend('Qt5Agg') @pytest.mark.backend('Qt5Agg')
def test_subplottool(): def test_subplottool():

View File

@ -205,3 +205,9 @@ def test_gid():
for gid, obj in gdic.items(): for gid, obj in gdic.items():
if include(gid, obj): if include(gid, obj):
assert gid in buf assert gid in buf
def test_savefig_tight():
# Check that the draw-disabled renderer correctly disables open/close_group
# as well.
plt.savefig(BytesIO(), format="svgz", bbox_inches="tight")

View File

@ -35,6 +35,11 @@ def _get_testable_interactive_backends():
if reason: if reason:
backend = pytest.param( backend = pytest.param(
backend, marks=pytest.mark.skip(reason=reason)) backend, marks=pytest.mark.skip(reason=reason))
elif backend == 'wxagg' and sys.platform == 'darwin':
# ignore on OSX because that's currently broken (github #16849)
backend = pytest.param(
backend,
marks=pytest.mark.xfail(reason='github #16849'))
backends.append(backend) backends.append(backend)
return backends return backends
@ -47,6 +52,7 @@ def _get_testable_interactive_backends():
_test_script = """\ _test_script = """\
import importlib import importlib
import importlib.util import importlib.util
import io
import sys import sys
from unittest import TestCase from unittest import TestCase
@ -102,7 +108,23 @@ timer.add_callback(FigureCanvasBase.key_press_event, fig.canvas, "q")
# Trigger quitting upon draw. # Trigger quitting upon draw.
fig.canvas.mpl_connect("draw_event", lambda event: timer.start()) fig.canvas.mpl_connect("draw_event", lambda event: timer.start())
result = io.BytesIO()
fig.savefig(result, format='png')
plt.show() plt.show()
# Ensure that the window is really closed.
plt.pause(0.5)
# Test that saving works after interactive window is closed, but the figure is
# not deleted.
result_after = io.BytesIO()
fig.savefig(result_after, format='png')
if not backend.startswith('qt5') and sys.platform == 'darwin':
# FIXME: This should be enabled everywhere once Qt5 is fixed on macOS to
# not resize incorrectly.
assert_equal(result.getvalue(), result_after.getvalue())
""" """
_test_timeout = 10 # Empirically, 1s is not enough on Travis. _test_timeout = 10 # Empirically, 1s is not enough on Travis.
@ -110,9 +132,10 @@ _test_timeout = 10 # Empirically, 1s is not enough on Travis.
@pytest.mark.parametrize("backend", _get_testable_interactive_backends()) @pytest.mark.parametrize("backend", _get_testable_interactive_backends())
@pytest.mark.flaky(reruns=3) @pytest.mark.flaky(reruns=3)
def test_interactive_backend(backend): def test_interactive_backend(backend):
proc = subprocess.run([sys.executable, "-c", _test_script], proc = subprocess.run(
env={**os.environ, "MPLBACKEND": backend}, [sys.executable, "-c", _test_script],
timeout=_test_timeout) env={**os.environ, "MPLBACKEND": backend, "SOURCE_DATE_EPOCH": "0"},
timeout=_test_timeout)
if proc.returncode: if proc.returncode:
pytest.fail("The subprocess returned with non-zero exit status " pytest.fail("The subprocess returned with non-zero exit status "
f"{proc.returncode}.") f"{proc.returncode}.")
@ -124,7 +147,8 @@ def test_interactive_backend(backend):
def test_webagg(): def test_webagg():
pytest.importorskip("tornado") pytest.importorskip("tornado")
proc = subprocess.Popen([sys.executable, "-c", _test_script], proc = subprocess.Popen([sys.executable, "-c", _test_script],
env={**os.environ, "MPLBACKEND": "webagg"}) env={**os.environ, "MPLBACKEND": "webagg",
"SOURCE_DATE_EPOCH": "0"})
url = "http://{}:{}".format( url = "http://{}:{}".format(
mpl.rcParams["webagg.address"], mpl.rcParams["webagg.port"]) mpl.rcParams["webagg.address"], mpl.rcParams["webagg.port"])
timeout = time.perf_counter() + _test_timeout timeout = time.perf_counter() + _test_timeout

View File

@ -108,3 +108,26 @@ def test_tight_pcolorfast():
# Previously, the bbox would include the area of the image clipped out by # Previously, the bbox would include the area of the image clipped out by
# the axes, resulting in a very tall image given the y limits of (0, 0.1). # the axes, resulting in a very tall image given the y limits of (0, 0.1).
assert width > height assert width > height
def test_noop_tight_bbox():
from PIL import Image
x_size, y_size = (10, 7)
dpi = 100
# make the figure just the right size up front
fig = plt.figure(frameon=False, dpi=dpi, figsize=(x_size/dpi, y_size/dpi))
ax = plt.Axes(fig, [0., 0., 1., 1.])
fig.add_axes(ax)
ax.set_axis_off()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
data = np.arange(x_size * y_size).reshape(y_size, x_size)
ax.imshow(data)
out = BytesIO()
fig.savefig(out, bbox_inches='tight', pad_inches=0)
out.seek(0)
im = np.asarray(Image.open(out))
assert (im[:, :, 3] == 255).all()
assert not (im[:, :, :3] == 255).all()
assert im.shape == (7, 10, 4)

View File

@ -718,3 +718,24 @@ def test_EventCollection_nosort():
arr = np.array([3, 2, 1, 10]) arr = np.array([3, 2, 1, 10])
coll = EventCollection(arr) coll = EventCollection(arr)
np.testing.assert_array_equal(arr, np.array([3, 2, 1, 10])) np.testing.assert_array_equal(arr, np.array([3, 2, 1, 10]))
def test_blended_collection_autolim():
a = [1, 2, 4]
height = .2
xy_pairs = np.column_stack([np.repeat(a, 2), np.tile([0, height], len(a))])
line_segs = xy_pairs.reshape([len(a), 2, 2])
f, ax = plt.subplots()
trans = mtransforms.blended_transform_factory(ax.transData, ax.transAxes)
ax.add_collection(LineCollection(line_segs, transform=trans))
ax.autoscale_view(scalex=True, scaley=False)
np.testing.assert_allclose(ax.get_xlim(), [1., 4.])
def test_singleton_autolim():
fig, ax = plt.subplots()
ax.scatter(0, 0)
np.testing.assert_allclose(ax.get_ylim(), [-0.06, 0.06])
np.testing.assert_allclose(ax.get_xlim(), [-0.06, 0.06])

View File

@ -487,3 +487,12 @@ def test_removed_axis():
fig, axs = plt.subplots(2, sharex=True) fig, axs = plt.subplots(2, sharex=True)
axs[0].remove() axs[0].remove()
fig.canvas.draw() fig.canvas.draw()
@check_figures_equal(extensions=["svg", "pdf", "eps", "png"])
def test_animated_with_canvas_change(fig_test, fig_ref):
ax_ref = fig_ref.subplots()
ax_ref.plot(range(5))
ax_test = fig_test.subplots()
ax_test.plot(range(5), animated=True)

View File

@ -24,3 +24,11 @@ def test_height_ratios():
""" """
with pytest.raises(ValueError): with pytest.raises(ValueError):
gridspec.GridSpec(1, 1, height_ratios=[2, 1, 3]) gridspec.GridSpec(1, 1, height_ratios=[2, 1, 3])
def test_repr():
ss = gridspec.GridSpec(2, 2,
height_ratios=(3, 1),
width_ratios=(1, 3))
assert repr(ss) == \
"GridSpec(2, 2, height_ratios=(3, 1), width_ratios=(1, 3))"

View File

@ -490,3 +490,60 @@ def test_fancyarrow_units():
fig, ax = plt.subplots() fig, ax = plt.subplots()
arrow = FancyArrowPatch((0, dtime), (0.01, dtime)) arrow = FancyArrowPatch((0, dtime), (0.01, dtime))
ax.add_patch(arrow) ax.add_patch(arrow)
@image_comparison(["large_arc.svg"], style="mpl20")
def test_large_arc():
fig, (ax1, ax2) = plt.subplots(1, 2)
x = 210
y = -2115
diameter = 4261
for ax in [ax1, ax2]:
a = mpatches.Arc((x, y), diameter, diameter, lw=2, color='k')
ax.add_patch(a)
ax.set_axis_off()
ax.set_aspect('equal')
# force the high accuracy case
ax1.set_xlim(7, 8)
ax1.set_ylim(5, 6)
# force the low accuracy case
ax2.set_xlim(-25000, 18000)
ax2.set_ylim(-20000, 6600)
@image_comparison(["all_quadrants_arcs.svg"], style="mpl20")
def test_rotated_arcs():
fig, ax_arr = plt.subplots(2, 2, squeeze=False, figsize=(10, 10))
scale = 10_000_000
diag_centers = ((-1, -1), (-1, 1), (1, 1), (1, -1))
on_axis_centers = ((0, 1), (1, 0), (0, -1), (-1, 0))
skews = ((2, 2), (2, 1/10), (2, 1/100), (2, 1/1000))
for ax, (sx, sy) in zip(ax_arr.ravel(), skews):
k = 0
for prescale, centers in zip((1 - .0001, (1 - .0001) / np.sqrt(2)),
(on_axis_centers, diag_centers)):
for j, (x_sign, y_sign) in enumerate(centers, start=k):
a = mpatches.Arc(
(x_sign * scale * prescale,
y_sign * scale * prescale),
scale * sx,
scale * sy,
lw=4,
color=f"C{j}",
zorder=1 + j,
angle=np.rad2deg(np.arctan2(y_sign, x_sign)) % 360,
label=f'big {j}',
gid=f'big {j}'
)
ax.add_patch(a)
k = j+1
ax.set_xlim(-scale / 4000, scale / 4000)
ax.set_ylim(-scale / 4000, scale / 4000)
ax.axhline(0, color="k")
ax.axvline(0, color="k")
ax.set_axis_off()
ax.set_aspect("equal")

View File

@ -9,31 +9,32 @@ import matplotlib as mpl
from matplotlib import pyplot as plt from matplotlib import pyplot as plt
def test_pyplot_up_to_date(): def test_pyplot_up_to_date(tmpdir):
gen_script = Path(mpl.__file__).parents[2] / "tools/boilerplate.py" gen_script = Path(mpl.__file__).parents[2] / "tools/boilerplate.py"
if not gen_script.exists(): if not gen_script.exists():
pytest.skip("boilerplate.py not found") pytest.skip("boilerplate.py not found")
orig_contents = Path(plt.__file__).read_text() orig_contents = Path(plt.__file__).read_text()
try: plt_file = tmpdir.join('pyplot.py')
subprocess.run([sys.executable, str(gen_script)], check=True) plt_file.write_text(orig_contents, 'utf-8')
new_contents = Path(plt.__file__).read_text()
if orig_contents != new_contents: subprocess.run([sys.executable, str(gen_script), str(plt_file)],
diff_msg = '\n'.join( check=True)
difflib.unified_diff( new_contents = plt_file.read_text('utf-8')
orig_contents.split('\n'), new_contents.split('\n'),
fromfile='found pyplot.py', if orig_contents != new_contents:
tofile='expected pyplot.py', diff_msg = '\n'.join(
n=0, lineterm='')) difflib.unified_diff(
pytest.fail( orig_contents.split('\n'), new_contents.split('\n'),
"pyplot.py is not up-to-date. Please run " fromfile='found pyplot.py',
"'python tools/boilerplate.py' to update pyplot.py. " tofile='expected pyplot.py',
"This needs to be done from an environment where your " n=0, lineterm=''))
"current working copy is installed (e.g. 'pip install -e'd). " pytest.fail(
"Here is a diff of unexpected differences:\n%s" % diff_msg "pyplot.py is not up-to-date. Please run "
) "'python tools/boilerplate.py' to update pyplot.py. "
finally: "This needs to be done from an environment where your "
Path(plt.__file__).write_text(orig_contents) "current working copy is installed (e.g. 'pip install -e'd). "
"Here is a diff of unexpected differences:\n%s" % diff_msg
)
def test_pyplot_box(): def test_pyplot_box():

Some files were not shown because too many files have changed in this diff Show More