diff --git a/news/4759.vendor.rst b/news/4759.vendor.rst new file mode 100644 index 00000000..e14dadd8 --- /dev/null +++ b/news/4759.vendor.rst @@ -0,0 +1,5 @@ +Switch the dependency resolver from ``pip-tools`` to `pip`. + +Update vendor libraries: +- Update ``requirementslib`` from ``1.5.16`` to ``1.6.1`` +- Update ``pip-shims`` from ``0.5.6`` to ``0.6.0`` diff --git a/pipenv/vendor/attr/LICENSE b/pipenv/vendor/attr/LICENSE deleted file mode 100644 index 7ae3df93..00000000 --- a/pipenv/vendor/attr/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Hynek Schlawack - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/pipenv/vendor/dotenv/LICENSE b/pipenv/vendor/dotenv/LICENSE deleted file mode 100644 index 39372fee..00000000 --- a/pipenv/vendor/dotenv/LICENSE +++ /dev/null @@ -1,87 +0,0 @@ -python-dotenv -Copyright (c) 2014, Saurabh Kumar - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of python-dotenv nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -django-dotenv-rw -Copyright (c) 2013, Ted Tieken - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of django-dotenv nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Original django-dotenv -Copyright (c) 2013, Jacob Kaplan-Moss - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of django-dotenv nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pipenv/vendor/packaging/LICENSE.APACHE b/pipenv/vendor/packaging/LICENSE.APACHE deleted file mode 100644 index f433b1a5..00000000 --- a/pipenv/vendor/packaging/LICENSE.APACHE +++ /dev/null @@ -1,177 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS diff --git a/pipenv/vendor/packaging/LICENSE.BSD b/pipenv/vendor/packaging/LICENSE.BSD deleted file mode 100644 index 42ce7b75..00000000 --- a/pipenv/vendor/packaging/LICENSE.BSD +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) Donald Stufft and individual contributors. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pipenv/vendor/pip_shims/LICENSE b/pipenv/vendor/pip_shims/LICENSE index e1a278e7..b8978687 100644 --- a/pipenv/vendor/pip_shims/LICENSE +++ b/pipenv/vendor/pip_shims/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018, Dan Ryan +Copyright (c) 2018-2021, Dan Ryan and Frost Ming Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/pipenv/vendor/pip_shims/__init__.py b/pipenv/vendor/pip_shims/__init__.py index 0b262dc4..c66a075a 100644 --- a/pipenv/vendor/pip_shims/__init__.py +++ b/pipenv/vendor/pip_shims/__init__.py @@ -25,19 +25,16 @@ import sys from . import shims -__version__ = "0.5.3" +__version__ = "0.6.0" if "pip_shims" in sys.modules: # mainly to keep a reference to the old module on hand so it doesn't get # weakref'd away - if __name__ != "pip_shims": - del sys.modules["pip_shims"] -if __name__ in sys.modules: - old_module = sys.modules[__name__] + old_module = sys.modules["pip_shims"] -module = sys.modules[__name__] = sys.modules["pip_shims"] = shims._new() +module = sys.modules["pip_shims"] = shims._new() module.shims = shims module.__dict__.update( { diff --git a/pipenv/vendor/pip_shims/compat.py b/pipenv/vendor/pip_shims/compat.py index cd377661..eac29930 100644 --- a/pipenv/vendor/pip_shims/compat.py +++ b/pipenv/vendor/pip_shims/compat.py @@ -1,8 +1,6 @@ -# -*- coding=utf-8 -*- """ Backports and helper functionality to support using new functionality. """ -from __future__ import absolute_import, print_function import atexit import contextlib @@ -13,7 +11,6 @@ import re import sys import types -import six from packaging import specifiers from .environment import MYPY_RUNNING @@ -27,19 +24,14 @@ from .utils import ( ) if sys.version_info[:2] < (3, 5): - from pipenv.vendor.vistir.compat import TemporaryDirectory + from backports.tempfile import TemporaryDirectory else: from tempfile import TemporaryDirectory -if six.PY3: - from contextlib import ExitStack -else: - from pipenv.vendor.contextlib2 import ExitStack - +from contextlib import ExitStack if MYPY_RUNNING: from optparse import Values - from requests import Session from typing import ( Any, Callable, @@ -55,7 +47,10 @@ if MYPY_RUNNING: TypeVar, Union, ) - from .utils import TShimmedPath, TShim, TShimmedFunc + + from requests import Session + + from .utils import TShim, TShimmedFunc, TShimmedPath TFinder = TypeVar("TFinder") TResolver = TypeVar("TResolver") @@ -662,11 +657,16 @@ def get_package_finder( if python_versions: py_version_info_python = max(python_versions) py_version_info = tuple([int(part) for part in py_version_info_python]) - target_python = target_python_builder( - platform=platform, - abi=abi, - implementation=implementation, - py_version_info=py_version_info, + target_python_args = { + "platform": platform, + "platforms": [platform] if platform else None, + "abi": abi, + "abis": [abi] if abi else None, + "implementation": implementation, + "py_version_info": py_version_info, + } + target_python = call_function_with_correct_args( + target_python_builder, **target_python_args ) build_kwargs["target_python"] = target_python elif any( @@ -762,11 +762,13 @@ def shim_unpack( unpack_kwargs["only_download"] = only_download if session is not None and "session" in required_args: unpack_kwargs["session"] = session - if downloader_provider is not None and any(arg in required_args for arg in ("download", "downloader")): + if ( + "download" in required_args or "downloader" in required_args + ) and downloader_provider is not None: + arg_name = "download" if "download" in required_args else "downloader" assert session is not None assert progress_bar is not None - arg = {"download", "downloader"}.intersection(required_args).pop() - unpack_kwargs[arg] = downloader_provider(session, progress_bar) + unpack_kwargs[arg_name] = downloader_provider(session, progress_bar) return unpack_fn(**unpack_kwargs) # type: ignore @@ -920,6 +922,8 @@ def make_preparer( preparer_args["finder"] = finder if downloader_is_required: preparer_args["downloader"] = downloader_provider(session, progress_bar) + if "in_tree_build" in required_args: + preparer_args["in_tree_build"] = True req_tracker_fn = nullcontext if not req_tracker_fn else req_tracker_fn with req_tracker_fn() as tracker_ctx: if "req_tracker" in required_args: @@ -1318,7 +1322,7 @@ def resolve( # noqa:C901 build_location_kwargs = { "build_dir": kwargs["build_dir"], "autodelete": True, - "parallel_builds": False + "parallel_builds": False, } call_function_with_correct_args(ireq.build_location, **build_location_kwargs) if reqset_provider is None: @@ -1419,6 +1423,8 @@ def build_wheel( # noqa:C901 cache_dir=None, # type: Optional[str] use_user_site=False, # type: bool use_pep517=None, # type: Optional[bool] + verify=False, # type: bool + editable=False, # type: bool format_control_provider=None, # type: Optional[TShimmedFunc] wheel_cache_provider=None, # type: Optional[TShimmedFunc] preparer_provider=None, # type: Optional[TShimmedFunc] @@ -1526,7 +1532,15 @@ def build_wheel( # noqa:C901 if req and not reqset and not output_dir: output_dir = get_ireq_output_path(wheel_cache, req) if not reqset and build_one_provider: - yield build_one_provider(req, output_dir, build_options, global_options) + build_one_kwargs = { + "req": req, + "output_dir": output_dir, + "verify": verify, + "editable": editable, + "build_options": build_options, + "global_options": global_options, + } + yield call_function_with_correct_args(build_one_provider, **build_one_kwargs) elif build_many_provider: yield build_many_provider( reqset, wheel_cache, build_options, global_options, check_binary_allowed diff --git a/pipenv/vendor/pip_shims/models.py b/pipenv/vendor/pip_shims/models.py index eb58834f..0a344c84 100644 --- a/pipenv/vendor/pip_shims/models.py +++ b/pipenv/vendor/pip_shims/models.py @@ -12,8 +12,7 @@ import operator import sys import types import weakref - -import six +from collections.abc import Mapping, Sequence from . import compat from .environment import BASE_IMPORT_PATH, MYPY_RUNNING, get_pip_version @@ -36,18 +35,6 @@ from .utils import ( suppress_setattr, ) -# format: off -six.add_move( - six.MovedAttribute("Sequence", "collections", "collections.abc") -) # type: ignore # noqa -six.add_move( - six.MovedAttribute("Mapping", "collections", "collections.abc") -) # type: ignore # noqa -from six.moves import Sequence, Mapping # type: ignore # noqa # isort:skip - -# format: on - - if MYPY_RUNNING: import packaging.version @@ -393,7 +380,7 @@ class ShimmedPath(object): item_value = make_method(item_value)(item_name) elif "cls" not in callable_args and creating_classmethods: item_value = make_classmethod(item_value)(item_name) - elif isinstance(item_value, six.string_types): + elif isinstance(item_value, str): module_path, name = split_package(item_value) module = cls._import_module(module_path) item_value = getattr(module, name, None) @@ -442,8 +429,6 @@ class ShimmedPath(object): if not methods and not classmethods: return provided classname = provided.__name__ - if six.PY2: - classname = classname.encode(sys.getdefaultencoding()) type_ = type(classname, (provided,), {}) if classmethods: @@ -640,7 +625,7 @@ class ShimmedPathCollection(object): self.pre_shim_functions = [] # type: List[Callable] self.aliases = [] # type: List[List[str]] if paths is not None: - if isinstance(paths, six.string_types): + if isinstance(paths, str): self.create_path(paths, version_start=lookup_current_pip_version()) else: self.paths.update(set(paths)) @@ -819,7 +804,7 @@ get_installed_distributions = ShimmedPathCollection( "get_installed_distributions", ImportTypes.FUNCTION ) get_installed_distributions.create_path( - "utils.misc.get_installed_distributions", "10", "9999" + "utils.misc.get_installed_distributions", "10", "21.2.999" ) get_installed_distributions.create_path("utils.get_installed_distributions", "7", "9.0.3") diff --git a/pipenv/vendor/pip_shims/utils.py b/pipenv/vendor/pip_shims/utils.py index 162b4a20..ec32082d 100644 --- a/pipenv/vendor/pip_shims/utils.py +++ b/pipenv/vendor/pip_shims/utils.py @@ -8,21 +8,13 @@ import contextlib import copy import inspect import sys +from collections.abc import Callable from functools import wraps import packaging.version -import six from .environment import MYPY_RUNNING -# format: off -six.add_move( - six.MovedAttribute("Callable", "collections", "collections.abc") -) # type: ignore # noqa -from six.moves import Callable # type: ignore # isort:skip # noqa - -# format: on - if MYPY_RUNNING: from types import ModuleType from typing import ( @@ -109,7 +101,7 @@ def memoize(obj): def _parse(version): # type: (str) -> Tuple[int, ...] if isinstance(version, STRING_TYPES): - return tuple((int(i) for i in version.split("."))) + return tuple(int(i) for i in version.split(".")) return version @@ -117,7 +109,7 @@ def _parse(version): def parse_version(version): # type: (str) -> packaging.version._BaseVersion if not isinstance(version, STRING_TYPES): - raise TypeError("Can only derive versions from string, got {0!r}".format(version)) + raise TypeError("Can only derive versions from string, got {!r}".format(version)) return packaging.version.parse(version) @@ -196,12 +188,8 @@ def set_default_kwargs(basecls, method, *args, **default_kwargs): prepended_defaults = prepended_defaults + (default_kwargs[arg],) if not prepended_defaults: return basecls - if six.PY2 and inspect.ismethod(target_method): - new_defaults = prepended_defaults + target_func.__defaults__ - target_method.__func__.__defaults__ = new_defaults - else: - new_defaults = prepended_defaults + target_method.__defaults__ - target_method.__defaults__ = new_defaults + new_defaults = prepended_defaults + target_method.__defaults__ + target_method.__defaults__ = new_defaults setattr(basecls, method, target_method) return basecls @@ -227,7 +215,7 @@ def ensure_function(parent, funcname, func): if parent_is_module: module = parent.__name__ elif parent_is_class: - qualname = "{0}.{1}".format(parent.__name__, qualname) + qualname = "{}.{}".format(parent.__name__, qualname) module = getattr(parent, "__module__", None) else: module = getattr(parent, "__module__", None) diff --git a/pipenv/vendor/python-dateutil.LICENSE b/pipenv/vendor/python-dateutil.LICENSE deleted file mode 100644 index 1e65815c..00000000 --- a/pipenv/vendor/python-dateutil.LICENSE +++ /dev/null @@ -1,54 +0,0 @@ -Copyright 2017- Paul Ganssle -Copyright 2017- dateutil contributors (see AUTHORS file) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -The above license applies to all contributions after 2017-12-01, as well as -all contributions that have been re-licensed (see AUTHORS file for the list of -contributors who have re-licensed their code). --------------------------------------------------------------------------------- -dateutil - Extensions to the standard Python datetime module. - -Copyright (c) 2003-2011 - Gustavo Niemeyer -Copyright (c) 2012-2014 - Tomi Pieviläinen -Copyright (c) 2014-2016 - Yaron de Leeuw -Copyright (c) 2015- - Paul Ganssle -Copyright (c) 2015- - dateutil contributors (see AUTHORS file) - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The above BSD License Applies to all code, even that also covered by Apache 2.0. \ No newline at end of file diff --git a/pipenv/vendor/pythonfinder/LICENSE b/pipenv/vendor/pythonfinder/LICENSE deleted file mode 100644 index c7ac395f..00000000 --- a/pipenv/vendor/pythonfinder/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2016 Steve Dower - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/pipenv/vendor/pythonfinder/LICENSE.txt b/pipenv/vendor/pythonfinder/LICENSE.txt deleted file mode 100644 index 4715db36..00000000 --- a/pipenv/vendor/pythonfinder/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2018 Dan Ryan - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/pipenv/vendor/requirementslib/LICENSE b/pipenv/vendor/requirementslib/LICENSE index a6b8c96a..21aaa475 100644 --- a/pipenv/vendor/requirementslib/LICENSE +++ b/pipenv/vendor/requirementslib/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright 2019 Dan Ryan. +Copyright 2019-2021 Dan Ryan and Frost Ming. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/pipenv/vendor/requirementslib/__init__.py b/pipenv/vendor/requirementslib/__init__.py index a3ce1d75..dc8520ab 100644 --- a/pipenv/vendor/requirementslib/__init__.py +++ b/pipenv/vendor/requirementslib/__init__.py @@ -4,13 +4,11 @@ from __future__ import absolute_import, print_function import logging import warnings -from vistir.compat import ResourceWarning - from .models.lockfile import Lockfile from .models.pipfile import Pipfile from .models.requirements import Requirement -__version__ = "1.5.16" +__version__ = "1.6.1" logger = logging.getLogger(__name__) diff --git a/pipenv/vendor/requirementslib/environment.py b/pipenv/vendor/requirementslib/environment.py index 2a7d9b0e..69d9d513 100644 --- a/pipenv/vendor/requirementslib/environment.py +++ b/pipenv/vendor/requirementslib/environment.py @@ -1,8 +1,9 @@ # -*- coding=utf-8 -*- -from __future__ import print_function, absolute_import +from __future__ import absolute_import, print_function import os -from appdirs import user_cache_dir + +from platformdirs import user_cache_dir def is_type_checking(): @@ -13,5 +14,7 @@ def is_type_checking(): return TYPE_CHECKING -REQUIREMENTSLIB_CACHE_DIR = os.getenv("REQUIREMENTSLIB_CACHE_DIR", user_cache_dir("pipenv")) +REQUIREMENTSLIB_CACHE_DIR = os.getenv( + "REQUIREMENTSLIB_CACHE_DIR", user_cache_dir("pipenv") +) MYPY_RUNNING = os.environ.get("MYPY_RUNNING", is_type_checking()) diff --git a/pipenv/vendor/requirementslib/exceptions.py b/pipenv/vendor/requirementslib/exceptions.py index d11dbce9..eacef437 100644 --- a/pipenv/vendor/requirementslib/exceptions.py +++ b/pipenv/vendor/requirementslib/exceptions.py @@ -5,20 +5,6 @@ import errno import os import sys -import six -from vistir.compat import FileNotFoundError - -if six.PY2: - - class FileExistsError(OSError): - def __init__(self, *args, **kwargs): - self.errno = errno.EEXIST - super(FileExistsError, self).__init__(*args, **kwargs) - - -else: - from six.moves.builtins import FileExistsError - class RequirementError(Exception): pass @@ -44,7 +30,7 @@ class FileCorruptException(OSError): if not backup_path and args: args = reversed(args) backup_path = args.pop() - if not isinstance(backup_path, six.string_types) or not os.path.exists( + if not isinstance(backup_path, str) or not os.path.exists( os.path.abspath(os.path.dirname(backup_path)) ): args.append(backup_path) diff --git a/pipenv/vendor/requirementslib/models/cache.py b/pipenv/vendor/requirementslib/models/cache.py index f1639ea2..6da15d57 100644 --- a/pipenv/vendor/requirementslib/models/cache.py +++ b/pipenv/vendor/requirementslib/models/cache.py @@ -6,18 +6,15 @@ import copy import hashlib import json import os +import pathlib import sys import vistir - -from appdirs import user_cache_dir -from pip_shims.shims import FAVORITE_HASH, SafeFileCache from packaging.requirements import Requirement +from pip_shims.shims import FAVORITE_HASH, SafeFileCache +from platformdirs import user_cache_dir -from .utils import as_tuple, key_from_req, lookup_table, get_pinned_version - -from ..exceptions import FileExistsError - +from .utils import as_tuple, get_pinned_version, key_from_req, lookup_table CACHE_DIR = os.environ.get("PIPENV_CACHE_DIR", user_cache_dir("pipenv")) @@ -29,64 +26,64 @@ class CorruptCacheError(Exception): def __str__(self): lines = [ - 'The dependency cache seems to have been corrupted.', - 'Inspect, or delete, the following file:', - ' {}'.format(self.path), + "The dependency cache seems to have been corrupted.", + "Inspect, or delete, the following file:", + " {}".format(self.path), ] return os.linesep.join(lines) def read_cache_file(cache_file_path): - with open(cache_file_path, 'r') as cache_file: + with open(cache_file_path, "r") as cache_file: try: doc = json.load(cache_file) except ValueError: raise CorruptCacheError(cache_file_path) # Check version and load the contents - assert doc['__format__'] == 1, 'Unknown cache file format' - return doc['dependencies'] + assert doc["__format__"] == 1, "Unknown cache file format" + return doc["dependencies"] class DependencyCache(object): - """ - Creates a new persistent dependency cache for the current Python version. - The cache file is written to the appropriate user cache dir for the - current platform, i.e. + """Creates a new persistent dependency cache for the current Python + version. The cache file is written to the appropriate user cache dir for + the current platform, i.e. ~/.cache/pip-tools/depcache-pyX.Y.json Where X.Y indicates the Python version. """ + def __init__(self, cache_dir=None): if cache_dir is None: cache_dir = CACHE_DIR - if not vistir.compat.Path(CACHE_DIR).absolute().is_dir(): + if not pathlib.Path(CACHE_DIR).absolute().is_dir(): try: vistir.path.mkdir_p(os.path.abspath(cache_dir)) - except (FileExistsError, OSError): + except OSError: pass - py_version = '.'.join(str(digit) for digit in sys.version_info[:2]) - cache_filename = 'depcache-py{}.json'.format(py_version) + py_version = ".".join(str(digit) for digit in sys.version_info[:2]) + cache_filename = "depcache-py{}.json".format(py_version) self._cache_file = os.path.join(cache_dir, cache_filename) self._cache = None @property def cache(self): - """ - The dictionary that is the actual in-memory cache. This property - lazily loads the cache from disk. + """The dictionary that is the actual in-memory cache. + + This property lazily loads the cache from disk. """ if self._cache is None: self.read_cache() return self._cache def as_cache_key(self, ireq): - """ - Given a requirement, return its cache key. This behavior is a little weird in order to allow backwards - compatibility with cache files. For a requirement without extras, this will return, for example: + """Given a requirement, return its cache key. This behavior is a little + weird in order to allow backwards compatibility with cache files. For a + requirement without extras, this will return, for example: ("ipython", "2.1.0") @@ -112,10 +109,10 @@ class DependencyCache(object): def write_cache(self): """Writes the cache to disk as JSON.""" doc = { - '__format__': 1, - 'dependencies': self._cache, + "__format__": 1, + "dependencies": self._cache, } - with open(self._cache_file, 'w') as f: + with open(self._cache_file, "w") as f: json.dump(doc, f, sort_keys=True) def clear(self): @@ -149,20 +146,20 @@ class DependencyCache(object): return self.cache.get(pkgname, {}).get(pkgversion_and_extras, default) def reverse_dependencies(self, ireqs): - """ - Returns a lookup table of reverse dependencies for all the given ireqs. + """Returns a lookup table of reverse dependencies for all the given + ireqs. Since this is all static, it only works if the dependency cache - contains the complete data, otherwise you end up with a partial view. - This is typically no problem if you use this function after the entire - dependency tree is resolved. + contains the complete data, otherwise you end up with a partial + view. This is typically no problem if you use this function + after the entire dependency tree is resolved. """ ireqs_as_cache_values = [self.as_cache_key(ireq) for ireq in ireqs] return self._reverse_dependencies(ireqs_as_cache_values) def _reverse_dependencies(self, cache_keys): - """ - Returns a lookup table of reverse dependencies for all the given cache keys. + """Returns a lookup table of reverse dependencies for all the given + cache keys. Example input: @@ -177,35 +174,39 @@ class DependencyCache(object): 'flake8': [], 'mccabe': ['flake8'], 'pyflakes': ['flake8']} - """ # First, collect all the dependencies into a sequence of (parent, child) tuples, like [('flake8', 'pep8'), # ('flake8', 'mccabe'), ...] - return lookup_table((key_from_req(Requirement(dep_name)), name) - for name, version_and_extras in cache_keys - for dep_name in self.cache[name][version_and_extras]) + return lookup_table( + (key_from_req(Requirement(dep_name)), name) + for name, version_and_extras in cache_keys + for dep_name in self.cache[name][version_and_extras] + ) class HashCache(SafeFileCache): """Caches hashes of PyPI artifacts so we do not need to re-download them. - Hashes are only cached when the URL appears to contain a hash in it and the - cache key includes the hash value returned from the server). This ought to - avoid ssues where the location on the server changes. + Hashes are only cached when the URL appears to contain a hash in it + and the cache key includes the hash value returned from the server). + This ought to avoid ssues where the location on the server changes. """ + def __init__(self, *args, **kwargs): session = kwargs.pop("session", None) if not session: import requests + session = requests.session() atexit.register(session.close) - cache_dir = kwargs.pop('cache_dir', CACHE_DIR) + cache_dir = kwargs.pop("cache_dir", CACHE_DIR) self.session = session - kwargs.setdefault('directory', os.path.join(cache_dir, 'hash-cache')) + kwargs.setdefault("directory", os.path.join(cache_dir, "hash-cache")) super(HashCache, self).__init__(*args, **kwargs) def get_hash(self, location): from pip_shims import VcsSupport + # if there is no location hash (i.e., md5 / sha256 / etc) we on't want to store it hash_value = None vcs = VcsSupport() @@ -216,13 +217,17 @@ class HashCache(SafeFileCache): can_hash = new_location.hash if can_hash: # hash url WITH fragment - hash_value = self._get_file_hash(new_location.url) if not new_location.url.startswith("ssh") else None + hash_value = ( + self._get_file_hash(new_location.url) + if not new_location.url.startswith("ssh") + else None + ) if not hash_value: hash_value = self._get_file_hash(new_location) - hash_value = hash_value.encode('utf8') + hash_value = hash_value.encode("utf8") if can_hash: self.set(new_location.url, hash_value) - return hash_value.decode('utf8') + return hash_value.decode("utf8") def _get_file_hash(self, location): h = hashlib.new(FAVORITE_HASH) @@ -242,6 +247,7 @@ class _JSONCache(object): Where X.Y indicates the Python version. """ + filename_format = None def __init__(self, cache_dir=CACHE_DIR): @@ -287,21 +293,19 @@ class _JSONCache(object): return name, "{}{}".format(version, extras_string) def read_cache(self): - """Reads the cached contents into memory. - """ + """Reads the cached contents into memory.""" if os.path.exists(self._cache_file): self._cache = read_cache_file(self._cache_file) else: self._cache = {} def write_cache(self): - """Writes the cache to disk as JSON. - """ + """Writes the cache to disk as JSON.""" doc = { - '__format__': 1, - 'dependencies': self._cache, + "__format__": 1, + "dependencies": self._cache, } - with open(self._cache_file, 'w') as f: + with open(self._cache_file, "w") as f: json.dump(doc, f, sort_keys=True) def clear(self): @@ -336,6 +340,6 @@ class _JSONCache(object): class RequiresPythonCache(_JSONCache): - """Cache a candidate's Requires-Python information. - """ + """Cache a candidate's Requires-Python information.""" + filename_format = "pyreqcache-py{python_version}.json" diff --git a/pipenv/vendor/requirementslib/models/dependencies.py b/pipenv/vendor/requirementslib/models/dependencies.py index 2608479a..21cdd3b6 100644 --- a/pipenv/vendor/requirementslib/models/dependencies.py +++ b/pipenv/vendor/requirementslib/models/dependencies.py @@ -5,6 +5,8 @@ import contextlib import copy import functools import os +from contextlib import ExitStack +from json import JSONDecodeError import attr import packaging.markers @@ -12,7 +14,7 @@ import packaging.version import pip_shims.shims import requests from packaging.utils import canonicalize_name -from vistir.compat import JSONDecodeError, fs_str +from vistir.compat import fs_str from vistir.contextmanagers import cd, temp_environ from vistir.path import create_tracked_tempdir @@ -32,32 +34,28 @@ from .utils import ( version_from_ireq, ) -try: - from contextlib import ExitStack -except ImportError: - from contextlib2 import ExitStack - if MYPY_RUNNING: from typing import ( Any, Dict, - List, Generator, + List, Optional, - Union, + Set, + Text, Tuple, TypeVar, - Text, - Set, + Union, ) - from pip_shims.shims import ( - InstallRequirement, - InstallationCandidate, - PackageFinder, - Command, - ) - from packaging.requirements import Requirement as PackagingRequirement + from packaging.markers import Marker + from packaging.requirements import Requirement as PackagingRequirement + from pip_shims.shims import ( + Command, + InstallationCandidate, + InstallRequirement, + PackageFinder, + ) TRequirement = TypeVar("TRequirement") RequirementType = TypeVar( @@ -88,8 +86,8 @@ def _get_filtered_versions(ireq, versions, prereleases): def find_all_matches(finder, ireq, pre=False): # type: (PackageFinder, InstallRequirement, bool) -> List[InstallationCandidate] - """Find all matching dependencies using the supplied finder and the - given ireq. + """Find all matching dependencies using the supplied finder and the given + ireq. :param finder: A package finder for discovering matching candidates. :type finder: :class:`~pip._internal.index.PackageFinder` @@ -130,7 +128,8 @@ class AbstractDependency(object): @property def version_set(self): - """Return the set of versions for the candidates in this abstract dependency. + """Return the set of versions for the candidates in this abstract + dependency. :return: A set of matching versions :rtype: set(str) @@ -141,8 +140,8 @@ class AbstractDependency(object): return set(packaging.version.parse(version_from_ireq(c)) for c in self.candidates) def compatible_versions(self, other): - """Find compatible version numbers between this abstract - dependency and another one. + """Find compatible version numbers between this abstract dependency and + another one. :param other: An abstract dependency to compare with. :type other: :class:`~requirementslib.models.dependency.AbstractDependency` @@ -230,8 +229,9 @@ class AbstractDependency(object): @classmethod def from_requirement(cls, requirement, parent=None): - """Creates a new :class:`~requirementslib.models.dependency.AbstractDependency` - from a :class:`~requirementslib.models.requirements.Requirement` object. + """Creates a new + :class:`~requirementslib.models.dependency.AbstractDependency` from a + :class:`~requirementslib.models.requirements.Requirement` object. This class is used to find all candidates matching a given set of specifiers and a given requirement. @@ -358,7 +358,8 @@ def get_dependencies(ireq, sources=None, parent=None): def get_dependencies_from_wheel_cache(ireq): # type: (pip_shims.shims.InstallRequirement) -> Optional[Set[pip_shims.shims.InstallRequirement]] - """Retrieves dependencies for the given install requirement from the wheel cache. + """Retrieves dependencies for the given install requirement from the wheel + cache. :param ireq: A single InstallRequirement :type ireq: :class:`~pip._internal.req.req_install.InstallRequirement` @@ -384,7 +385,8 @@ def _marker_contains_extra(ireq): def get_dependencies_from_json(ireq): - """Retrieves dependencies for the given install requirement from the json api. + """Retrieves dependencies for the given install requirement from the json + api. :param ireq: A single InstallRequirement :type ireq: :class:`~pip._internal.req.req_install.InstallRequirement` @@ -433,7 +435,8 @@ def get_dependencies_from_json(ireq): def get_dependencies_from_cache(ireq): - """Retrieves dependencies for the given install requirement from the dependency cache. + """Retrieves dependencies for the given install requirement from the + dependency cache. :param ireq: A single InstallRequirement :type ireq: :class:`~pip._internal.req.req_install.InstallRequirement` @@ -474,7 +477,8 @@ def is_python(section): def get_dependencies_from_index(dep, sources=None, pip_options=None, wheel_cache=None): - """Retrieves dependencies for the given install requirement from the pip resolver. + """Retrieves dependencies for the given install requirement from the pip + resolver. :param dep: A single InstallRequirement :type dep: :class:`~pip._internal.req.req_install.InstallRequirement` @@ -506,8 +510,8 @@ def get_dependencies_from_index(dep, sources=None, pip_options=None, wheel_cache return requirements -def get_pip_options(args=[], sources=None, pip_command=None): - """Build a pip command from a list of sources +def get_pip_options(args=None, sources=None, pip_command=None): + """Build a pip command from a list of sources. :param args: positional arguments passed through to the pip parser :param sources: A list of pipfile-formatted sources, defaults to None @@ -523,7 +527,7 @@ def get_pip_options(args=[], sources=None, pip_command=None): if not sources: sources = [{"url": "https://pypi.org/simple", "name": "pypi", "verify_ssl": True}] _ensure_dir(CACHE_DIR) - pip_args = args + pip_args = args or [] pip_args = prepare_pip_source_args(sources, pip_args) pip_options, _ = pip_command.parser.parse_args(pip_args) pip_options.cache_dir = CACHE_DIR @@ -532,7 +536,7 @@ def get_pip_options(args=[], sources=None, pip_command=None): def get_finder(sources=None, pip_command=None, pip_options=None): # type: (List[Dict[S, Union[S, bool]]], Optional[Command], Any) -> PackageFinder - """Get a package finder for looking up candidates to install + """Get a package finder for looking up candidates to install. :param sources: A list of pipfile-formatted sources, defaults to None :param sources: list[dict], optional @@ -567,7 +571,8 @@ def start_resolver(finder=None, session=None, wheel_cache=None): :param :class:`~requests.Session` session: A session instance :param :class:`~pip._internal.cache.WheelCache` wheel_cache: A pip WheelCache instance :return: A 3-tuple of finder, preparer, resolver - :rtype: (:class:`~pip._internal.operations.prepare.RequirementPreparer`, :class:`~pip._internal.resolve.Resolver`) + :rtype: (:class:`~pip._internal.operations.prepare.RequirementPreparer`, + :class:`~pip._internal.resolve.Resolver`) """ pip_command = get_pip_command() diff --git a/pipenv/vendor/requirementslib/models/lockfile.py b/pipenv/vendor/requirementslib/models/lockfile.py index 3eabc504..ce41c702 100644 --- a/pipenv/vendor/requirementslib/models/lockfile.py +++ b/pipenv/vendor/requirementslib/models/lockfile.py @@ -4,11 +4,11 @@ from __future__ import absolute_import, print_function import copy import itertools import os +from json import JSONDecodeError +from pathlib import Path import attr import plette.lockfiles -import six -from vistir.compat import FileNotFoundError, JSONDecodeError, Path from ..exceptions import LockfileCorruptException, MissingParameter, PipfileNotFound from ..utils import is_editable, is_vcs, merge_items @@ -16,11 +16,11 @@ from .project import ProjectFile from .requirements import Requirement from .utils import optional_instance_of -DEFAULT_NEWLINES = six.text_type("\n") +DEFAULT_NEWLINES = "\n" def preferred_newlines(f): - if isinstance(f.newlines, six.text_type): + if isinstance(f.newlines, str): return f.newlines return DEFAULT_NEWLINES @@ -36,7 +36,7 @@ class Lockfile(object): _dev_requirements = attr.ib(default=attr.Factory(list), type=list) projectfile = attr.ib(validator=is_projectfile, type=ProjectFile) _lockfile = attr.ib(validator=is_lockfile, type=plette.lockfiles.Lockfile) - newlines = attr.ib(default=DEFAULT_NEWLINES, type=six.text_type) + newlines = attr.ib(default=DEFAULT_NEWLINES, type=str) @path.default def _get_path(self): @@ -118,7 +118,8 @@ class Lockfile(object): @classmethod def read_projectfile(cls, path): - """Read the specified project file and provide an interface for writing/updating. + """Read the specified project file and provide an interface for + writing/updating. :param str path: Path to the target file. :return: A project file with the model and location for interaction @@ -261,7 +262,8 @@ class Lockfile(object): return self._lockfile.default def get_requirements(self, dev=True, only=False): - """Produces a generator which generates requirements from the desired section. + """Produces a generator which generates requirements from the desired + section. :param bool dev: Indicates whether to use dev requirements, defaults to False :return: Requirements from the relevant the relevant pipfile @@ -297,7 +299,7 @@ class Lockfile(object): self.projectfile.write() def as_requirements(self, include_hashes=False, dev=False): - """Returns a list of requirements in pip-style format""" + """Returns a list of requirements in pip-style format.""" lines = [] section = self.dev_requirements if dev else self.requirements for req in section: diff --git a/pipenv/vendor/requirementslib/models/markers.py b/pipenv/vendor/requirementslib/models/markers.py index 8593326b..6149558d 100644 --- a/pipenv/vendor/requirementslib/models/markers.py +++ b/pipenv/vendor/requirementslib/models/markers.py @@ -2,25 +2,22 @@ import itertools import operator import re +from collections.abc import Mapping, Set +from functools import lru_cache, reduce import attr import distlib.markers import packaging.version -import six from packaging.markers import InvalidMarker, Marker from packaging.specifiers import Specifier, SpecifierSet -from vistir.compat import Mapping, Set, lru_cache from vistir.misc import dedup from ..environment import MYPY_RUNNING from ..exceptions import RequirementError from .utils import filter_none, validate_markers -from six.moves import reduce # isort:skip - - if MYPY_RUNNING: - from typing import Optional, List, Type, Any, Tuple, Union, AnyStr, Text, Iterator + from typing import Any, AnyStr, Iterator, List, Optional, Text, Tuple, Type, Union STRING_TYPE = Union[str, bytes, Text] @@ -130,7 +127,7 @@ def _tuplize_version(version): @lru_cache(maxsize=1024) def _format_version(version): # type: (Tuple[int, ...]) -> STRING_TYPE - if not isinstance(version, six.string_types): + if not isinstance(version, str): return ".".join(str(i) for i in version) return version @@ -212,7 +209,8 @@ def _group_by_op(specs): # TODO: rename this to something meaningful def normalize_specifier_set(specs): # type: (Union[str, SpecifierSet]) -> Optional[Set[Specifier]] - """Given a specifier set, a string, or an iterable, normalize the specifiers + """Given a specifier set, a string, or an iterable, normalize the + specifiers. .. note:: This function exists largely to deal with ``pyzmq`` which handles the ``requires_python`` specifier incorrectly, using ``3.7*`` rather than @@ -228,7 +226,7 @@ def normalize_specifier_set(specs): if isinstance(specs, set): return specs # when we aren't dealing with a string at all, we can normalize this as usual - elif not isinstance(specs, six.string_types): + elif not isinstance(specs, str): return {_format_pyspec(spec) for spec in specs} spec_list = [] for spec in specs.split(","): @@ -368,10 +366,11 @@ def _strip_pyversion(elements): def _strip_marker_elem(elem_name, elements): """Remove the supplied element from the marker. - This is not a comprehensive implementation, but relies on an important - characteristic of metadata generation: The element's operand is always - associated with an "and" operator. This means that we can simply remove the - operand and the "and" operator associated with it. + This is not a comprehensive implementation, but relies on an + important characteristic of metadata generation: The element's + operand is always associated with an "and" operator. This means that + we can simply remove the operand and the "and" operator associated + with it. """ extra_indexes = [] @@ -425,8 +424,8 @@ def get_without_extra(marker): def get_without_pyversion(marker): """Built a new marker without the `python_version` part. - This could return `None` if the `python_version` section is the only section in the - marker. + This could return `None` if the `python_version` section is the only + section in the marker. """ return _get_stripped_marker(marker, _strip_pyversion) @@ -444,7 +443,7 @@ def _markers_collect_extras(markers, collection): def _markers_collect_pyversions(markers, collection): local_collection = [] marker_format_str = "{0}" - for i, el in enumerate(reversed(markers)): + for el in reversed(markers): if isinstance(el, tuple) and el[0].value == "python_version": new_marker = str(gen_marker(el)) local_collection.append(marker_format_str.format(new_marker)) @@ -490,8 +489,7 @@ def get_contained_extras(marker): @lru_cache(maxsize=1024) def get_contained_pyversions(marker): - """Collect all `python_version` operands from a marker. - """ + """Collect all `python_version` operands from a marker.""" collection = [] if not marker: @@ -522,8 +520,7 @@ def get_contained_pyversions(marker): @lru_cache(maxsize=128) def contains_extra(marker): - """Check whehter a marker contains an "extra == ..." operand. - """ + """Check whehter a marker contains an "extra == ..." operand.""" if not marker: return False marker = _ensure_marker(marker) @@ -532,8 +529,7 @@ def contains_extra(marker): @lru_cache(maxsize=128) def contains_pyversion(marker): - """Check whether a marker contains a python_version operand. - """ + """Check whether a marker contains a python_version operand.""" if not marker: return False @@ -543,8 +539,8 @@ def contains_pyversion(marker): def _split_specifierset_str(specset_str, prefix="=="): # type: (str, str) -> Set[Specifier] - """ - Take a specifierset string and split it into a list to join for specifier sets + """Take a specifierset string and split it into a list to join for + specifier sets. :param str specset_str: A string containing python versions, often comma separated :param str prefix: A prefix to use when generating the specifier set @@ -564,8 +560,7 @@ def _split_specifierset_str(specset_str, prefix="=="): def _get_specifiers_from_markers(marker_item): - """ - Given a marker item, get specifiers from the version marker + """Given a marker item, get specifiers from the version marker. :param :class:`~packaging.markers.Marker` marker_sequence: A marker describing a version constraint :return: A set of specifiers corresponding to the marker constraint diff --git a/pipenv/vendor/requirementslib/models/metadata.py b/pipenv/vendor/requirementslib/models/metadata.py index b45b1f02..28bc4b73 100644 --- a/pipenv/vendor/requirementslib/models/metadata.py +++ b/pipenv/vendor/requirementslib/models/metadata.py @@ -8,6 +8,8 @@ import operator import os import zipfile from collections import defaultdict +from functools import reduce +from typing import Sequence import attr import dateutil.parser @@ -15,7 +17,6 @@ import distlib.metadata import distlib.wheel import packaging.version import requests -import six import vistir from packaging.markers import Marker from packaging.requirements import Requirement as PackagingRequirement @@ -35,12 +36,6 @@ from .markers import ( from .requirements import Requirement from .utils import filter_dict, get_pinned_version, is_pinned_requirement -# fmt: off -from six.moves import Sequence # type: ignore # isort:skip -from six.moves import reduce # type: ignore # isort:skip -# fmt: on # isort:skip - - ch = logging.StreamHandler() formatter = logging.Formatter("%(asctime)s %(levelname)s: %(message)s") ch.setFormatter(formatter) @@ -64,7 +59,9 @@ if MYPY_RUNNING: TypeVar, Union, ) + from attr import Attribute # noqa + from .setup_info import SetupInfo TAttrsClass = TypeVar("TAttrsClass") @@ -318,7 +315,9 @@ class Dependency(object): return cls( name=req.name, specifier=req.specifier, - extras=tuple(sorted(set(req.extras))) if req.extras is not None else req.extras, + extras=tuple(sorted(set(req.extras))) + if req.extras is not None + else req.extras, requirement=req, from_extras=from_extras, python_version=python_version, @@ -364,7 +363,9 @@ class Dependency(object): return cls( name=info.name, specifier=req.specifier, - extras=tuple(sorted(set(req.extras))) if req.extras is not None else req.extras, + extras=tuple(sorted(set(req.extras))) + if req.extras is not None + else req.extras, requirement=req, from_extras=None, python_version=SpecifierSet(requires_python_str), @@ -625,15 +626,15 @@ class ReleaseUrl(object): # type: (TReleaseUrlDict, Optional[str]) -> "ReleaseUrl" valid_digest_keys = set("{0}_digest".format(k) for k in VALID_ALGORITHMS.keys()) digest_keys = set(release_dict.keys()) & valid_digest_keys - creation_kwargs = {} # type: Dict[str, Union[bool, int, str, Digest, TDigestDict]] - creation_kwargs = { - k: v for k, v in release_dict.items() if k not in digest_keys - } + creation_kwargs = ( + {} + ) # type: Dict[str, Union[bool, int, str, Digest, TDigestDict]] + creation_kwargs = {k: v for k, v in release_dict.items() if k not in digest_keys} if name is not None: creation_kwargs["name"] = name for k in digest_keys: digest = release_dict[k] - if not isinstance(digest, six.string_types): + if not isinstance(digest, str): raise TypeError("Digests must be strings, got {!r}".format(digest)) creation_kwargs[k] = Digest.create(k.replace("_digest", ""), digest) release_url = cls(**filter_dict(creation_kwargs)) # type: ignore @@ -827,7 +828,8 @@ def get_releases_from_package(releases, name=None): @attr.s(frozen=True) class ReleaseCollection(object): releases = attr.ib( - factory=list, converter=instance_check_converter(list, get_releases_from_package), # type: ignore + factory=list, + converter=instance_check_converter(list, get_releases_from_package), # type: ignore ) # type: List[Release] def __iter__(self): @@ -894,7 +896,7 @@ def convert_releases_to_collection(releases, name=None): def split_keywords(value): # type: (Union[str, List]) -> List[str] - if value and isinstance(value, six.string_types): + if value and isinstance(value, str): return value.split(",") elif isinstance(value, list): return value @@ -1027,7 +1029,9 @@ class Package(object): @urls.default def _get_urls_collection(self): - return functools.partial(convert_release_urls_to_collection, urls=[], name=self.name) + return functools.partial( + convert_release_urls_to_collection, urls=[], name=self.name + ) @property def name(self): @@ -1173,7 +1177,9 @@ class Package(object): try: version = next(iter(specset.filter((r.version for r in sorted_releases)))) except StopIteration: - logger.info("No version of {0} matches specifier: {1}".format(sub_dep, specset)) + logger.info( + "No version of {0} matches specifier: {1}".format(sub_dep, specset) + ) logger.info( "Available versions: {0}".format( " ".join([r.version for r in sorted_releases]) diff --git a/pipenv/vendor/requirementslib/models/pipfile.py b/pipenv/vendor/requirementslib/models/pipfile.py index 9c0aea4e..a1816cd0 100644 --- a/pipenv/vendor/requirementslib/models/pipfile.py +++ b/pipenv/vendor/requirementslib/models/pipfile.py @@ -5,13 +5,12 @@ from __future__ import absolute_import, print_function, unicode_literals import copy import itertools import os -import sys +from pathlib import Path import attr import plette.models.base import plette.pipfiles import tomlkit -from vistir.compat import FileNotFoundError, Path from ..environment import MYPY_RUNNING from ..exceptions import RequirementError @@ -21,7 +20,7 @@ from .requirements import Requirement from .utils import get_url_name, optional_instance_of, tomlkit_value_to_python if MYPY_RUNNING: - from typing import Union, Any, Dict, Iterable, Mapping, List, Text + from typing import Any, Dict, Iterable, List, Mapping, Text, Union package_type = Dict[Text, Dict[Text, Union[List[Text], Text]]] source_type = Dict[Text, Union[Text, bool]] @@ -68,8 +67,8 @@ class PipfileLoader(plette.pipfiles.Pipfile): @classmethod def ensure_package_sections(cls, data): # type: (tomlkit.toml_document.TOMLDocument[Text, Any]) -> tomlkit.toml_document.TOMLDocument[Text, Any] - """ - Ensure that all pipfile package sections are present in the given toml document + """Ensure that all pipfile package sections are present in the given + toml document. :param :class:`~tomlkit.toml_document.TOMLDocument` data: The toml document to ensure package sections are present on @@ -256,7 +255,8 @@ class Pipfile(object): @classmethod def read_projectfile(cls, path): # type: (Text) -> ProjectFile - """Read the specified project file and provide an interface for writing/updating. + """Read the specified project file and provide an interface for + writing/updating. :param Text path: Path to the target file. :return: A project file with the model and location for interaction @@ -268,8 +268,7 @@ class Pipfile(object): @classmethod def load_projectfile(cls, path, create=False): # type: (Text, bool) -> ProjectFile - """ - Given a path, load or create the necessary pipfile. + """Given a path, load or create the necessary pipfile. :param Text path: Path to the project root or pipfile :param bool create: Whether to create the pipfile if not found, defaults to True @@ -294,8 +293,7 @@ class Pipfile(object): @classmethod def load(cls, path, create=False): # type: (Text, bool) -> Pipfile - """ - Given a path, load or create the necessary pipfile. + """Given a path, load or create the necessary pipfile. :param Text path: Path to the project root or pipfile :param bool create: Whether to create the pipfile if not found, defaults to True @@ -378,7 +376,6 @@ class Pipfile(object): @property def build_backend(self): # type: () -> Text - pyproject = self.path.parent.joinpath("pyproject.toml") if not self.build_system: self._read_pyproject() return self.build_system.get("build-backend", None) diff --git a/pipenv/vendor/requirementslib/models/project.py b/pipenv/vendor/requirementslib/models/project.py index 7c1b0e81..8e1af95d 100644 --- a/pipenv/vendor/requirementslib/models/project.py +++ b/pipenv/vendor/requirementslib/models/project.py @@ -11,9 +11,7 @@ import packaging.markers import packaging.utils import plette import plette.models -import six import tomlkit -from vistir.compat import FileNotFoundError SectionDifference = collections.namedtuple("SectionDifference", ["inthis", "inthat"]) FileDifference = collections.namedtuple("FileDifference", ["default", "develop"]) @@ -39,15 +37,14 @@ DEFAULT_NEWLINES = "\n" def preferred_newlines(f): - if isinstance(f.newlines, six.text_type): + if isinstance(f.newlines, str): return f.newlines return DEFAULT_NEWLINES @attr.s class ProjectFile(object): - """A file in the Pipfile project. - """ + """A file in the Pipfile project.""" location = attr.ib() line_ending = attr.ib() @@ -74,7 +71,7 @@ class ProjectFile(object): self.model.dump(f) def dumps(self): - strio = six.StringIO() + strio = io.StringIO() self.model.dump(strio) return strio.getvalue() diff --git a/pipenv/vendor/requirementslib/models/requirements.py b/pipenv/vendor/requirementslib/models/requirements.py index 6831a7c8..5c131d54 100644 --- a/pipenv/vendor/requirementslib/models/requirements.py +++ b/pipenv/vendor/requirementslib/models/requirements.py @@ -8,10 +8,13 @@ import os import sys from contextlib import contextmanager from distutils.sysconfig import get_python_lib +from functools import lru_cache +from pathlib import Path +from urllib import parse as urllib_parse +from urllib.parse import unquote import attr import pip_shims -import six from cached_property import cached_property from packaging.markers import Marker from packaging.requirements import Requirement as PackagingRequirement @@ -22,9 +25,6 @@ from packaging.specifiers import ( SpecifierSet, ) from packaging.utils import canonicalize_name -from six.moves.urllib import parse as urllib_parse -from six.moves.urllib.parse import unquote -from vistir.compat import FileNotFoundError, Path, lru_cache from vistir.contextmanagers import temp_path from vistir.misc import dedup from vistir.path import ( @@ -47,9 +47,7 @@ from ..utils import ( is_vcs, strip_ssh_from_git_uri, ) -from .markers import ( - normalize_marker_str, -) +from .markers import normalize_marker_str from .setup_info import ( SetupInfo, _prepare_wheel_building_kwargs, @@ -87,34 +85,36 @@ from .utils import ( if MYPY_RUNNING: from typing import ( - Optional, - TypeVar, - List, - Dict, - Union, Any, - Tuple, + AnyStr, + Dict, + FrozenSet, + Generator, + List, + Optional, Sequence, Set, - AnyStr, Text, - Generator, - FrozenSet, + Tuple, + TypeVar, + Union, ) + from pip_shims.shims import ( - Link, - InstallRequirement, - PackageFinder, InstallationCandidate, + InstallRequirement, + Link, + PackageFinder, ) RequirementType = TypeVar( "RequirementType", covariant=True, bound=PackagingRequirement ) F = TypeVar("F", "FileRequirement", "VCSRequirement", covariant=True) - from six.moves.urllib.parse import SplitResult - from .vcs import VCSRepository + from urllib.parse import SplitResult + from .dependencies import AbstractDependency + from .vcs import VCSRepository NON_STRING_ITERABLE = Union[List, Set, Tuple] STRING_TYPE = Union[str, bytes, Text] @@ -446,7 +446,7 @@ class Line(object): def specifiers(self, specifiers): # type: (Union[Text, str, SpecifierSet]) -> None if not isinstance(specifiers, SpecifierSet): - if isinstance(specifiers, six.string_types): + if isinstance(specifiers, str): specifiers = SpecifierSet(specifiers) else: raise TypeError("Must pass a string or a SpecifierSet") @@ -887,7 +887,7 @@ class Line(object): # type: () -> Dict[Any, Any] if self.is_local and self.path and is_installable_dir(self.path): if self.setup_py: - return ast_parse_setup_py(self.setup_py) + return ast_parse_setup_py(self.setup_py, raising=False) return {} @vcsrepo.setter @@ -1004,7 +1004,7 @@ class Line(object): parsed_setup_py = self.parsed_setup_py if parsed_setup_py: name = parsed_setup_py.get("name", "") - if name and isinstance(name, six.string_types): + if name and isinstance(name, str): return name return None @@ -1374,7 +1374,7 @@ class NamedRequirement(object): creation_args["version"] = version # type: ignore req = init_requirement("{0}{1}".format(name, version)) if req and extras and req.extras and isinstance(req.extras, tuple): - if isinstance(extras, six.string_types): + if isinstance(extras, str): req.extras = (extras) + tuple(["{0}".format(xtra) for xtra in req.extras]) elif isinstance(extras, (tuple, list)): req.extras += tuple(extras) @@ -1648,7 +1648,7 @@ class FileRequirement(object): elif ( getattr(self, "req", None) and self.req is not None - and getattr(self.req, "url") + and getattr(self.req, "url", None) ): return self.req.url elif self.link is not None: @@ -1713,7 +1713,7 @@ class FileRequirement(object): elif ( getattr(self, "req", None) and self.req is not None - and (getattr(self.req, "url") and self.req.url is not None) + and (getattr(self.req, "url", None) and self.req.url is not None) ): uri = self.req.url if uri and is_file_url(uri): @@ -1765,7 +1765,7 @@ class FileRequirement(object): uri = pipfile.get("uri") fil = pipfile.get("file") path = pipfile.get("path") - if path and isinstance(path, six.string_types): + if path and isinstance(path, str): if isinstance(path, Path) and not path.is_absolute(): path = get_converted_relative_path(path.as_posix()) elif not os.path.isabs(path): @@ -1790,7 +1790,7 @@ class FileRequirement(object): if not uri: uri = pip_shims.shims.path_to_url(path) link_info = None # type: Optional[LinkInfo] - if uri and isinstance(uri, six.string_types): + if uri and isinstance(uri, str): link_info = cls.get_link_from_line(uri) else: raise ValueError( @@ -1826,7 +1826,7 @@ class FileRequirement(object): else: if link: line = link.url - elif uri and isinstance(uri, six.string_types): + elif uri and isinstance(uri, str): line = uri else: raise ValueError( @@ -2259,7 +2259,7 @@ class VCSRequirement(FileRequirement): if key in VCS_LIST and key in pipfile_keys: creation_args["vcs"] = key target = pipfile[key] - if isinstance(target, six.string_types): + if isinstance(target, str): drive, path = os.path.splitdrive(target) if ( not drive @@ -2305,9 +2305,7 @@ class VCSRequirement(FileRequirement): self._parsed_line.is_direct_url and self._parsed_line.line_with_prefix ): return self._parsed_line.line_with_prefix - elif getattr(self, "_base_line", None) and ( - isinstance(self._base_line, six.string_types) - ): + elif getattr(self, "_base_line", None) and (isinstance(self._base_line, str)): base = self._base_line else: base = getattr(self, "link", self.get_link()).url @@ -2439,7 +2437,7 @@ class Requirement(object): new_hashes = set() # type: Set[STRING_TYPE] if self.hashes is not None: new_hashes |= set(self.hashes) - if isinstance(hashes, six.string_types): + if isinstance(hashes, str): new_hashes.add(hashes) else: new_hashes |= set(hashes) @@ -2462,7 +2460,7 @@ class Requirement(object): def hashes_as_pip(self): # type: () -> STRING_TYPE hashes = self.get_hashes_as_pip() - assert isinstance(hashes, six.string_types) + assert isinstance(hashes, str) return hashes @property @@ -2972,8 +2970,8 @@ class Requirement(object): from .dependencies import ( AbstractDependency, - get_dependencies, get_abstract_dependencies, + get_dependencies, ) if not self.abstract_dep: @@ -3003,7 +3001,7 @@ class Requirement(object): :rtype: list[ :class:`~pip._internal.index.InstallationCandidate` ] """ - from .dependencies import get_finder, find_all_matches + from .dependencies import find_all_matches, get_finder if not finder: _, finder = get_finder(sources=sources) diff --git a/pipenv/vendor/requirementslib/models/resolvers.py b/pipenv/vendor/requirementslib/models/resolvers.py index 43590523..8c360c45 100644 --- a/pipenv/vendor/requirementslib/models/resolvers.py +++ b/pipenv/vendor/requirementslib/models/resolvers.py @@ -2,7 +2,6 @@ from contextlib import contextmanager import attr -import six from pip_shims.shims import Wheel from .cache import HashCache @@ -62,8 +61,8 @@ class DependencyResolver(object): return list(self.pinned_deps.values()) def add_abstract_dep(self, dep): - """Add an abstract dependency by either creating a new entry or - merging with an old one. + """Add an abstract dependency by either creating a new entry or merging + with an old one. :param dep: An abstract dependency to add :type dep: :class:`~requirementslib.models.dependency.AbstractDependency` @@ -85,10 +84,12 @@ class DependencyResolver(object): self.dep_dict[dep.name] = dep def pin_deps(self): - """Pins the current abstract dependencies and adds them to the history dict. + """Pins the current abstract dependencies and adds them to the history + dict. - Adds any new dependencies to the abstract dependencies already present by - merging them together to form new, compatible abstract dependencies. + Adds any new dependencies to the abstract dependencies already + present by merging them together to form new, compatible + abstract dependencies. """ for name in list(self.dep_dict.keys()): @@ -122,7 +123,8 @@ class DependencyResolver(object): break def resolve(self, root_nodes, max_rounds=20): - """Resolves dependencies using a backtracking resolver and multiple endpoints. + """Resolves dependencies using a backtracking resolver and multiple + endpoints. Note: this resolver caches aggressively. Runs for *max_rounds* or until any two pinning rounds yield the same outcome. @@ -141,11 +143,11 @@ class DependencyResolver(object): # Coerce input into AbstractDependency instances. # We accept str, Requirement, and AbstractDependency as input. - from .dependencies import AbstractDependency from ..utils import log + from .dependencies import AbstractDependency for dep in root_nodes: - if isinstance(dep, six.string_types): + if isinstance(dep, str): dep = AbstractDependency.from_string(dep) elif not isinstance(dep, AbstractDependency): dep = AbstractDependency.from_requirement(dep) @@ -227,11 +229,11 @@ class DependencyResolver(object): @contextmanager def allow_all_wheels(self): - """ - Monkey patches pip.Wheel to allow wheels from all platforms and Python versions. + """Monkey patches pip.Wheel to allow wheels from all platforms and + Python versions. - This also saves the candidate cache and set a new one, or else the results from the - previous non-patched calls will interfere. + This also saves the candidate cache and set a new one, or else + the results from the previous non-patched calls will interfere. """ def _wheel_supported(self, tags=None): diff --git a/pipenv/vendor/requirementslib/models/setup_info.py b/pipenv/vendor/requirementslib/models/setup_info.py index 58ea9979..4c74c139 100644 --- a/pipenv/vendor/requirementslib/models/setup_info.py +++ b/pipenv/vendor/requirementslib/models/setup_info.py @@ -3,30 +3,29 @@ from __future__ import absolute_import, print_function import ast import atexit +import configparser import contextlib import importlib -import io import operator import os import shutil import sys -from functools import partial +from collections.abc import Iterable, Mapping +from functools import lru_cache, partial +from pathlib import Path +from urllib.parse import urlparse, urlunparse +from weakref import finalize import attr -import chardet import packaging.specifiers import packaging.utils import packaging.version import pep517.envbuild import pep517.wrappers -import six -from appdirs import user_cache_dir from distlib.wheel import Wheel from packaging.markers import Marker from pip_shims.utils import call_function_with_correct_args -from six.moves import configparser -from six.moves.urllib.parse import urlparse, urlunparse -from vistir.compat import FileNotFoundError, Iterable, Mapping, Path, finalize, lru_cache +from platformdirs import user_cache_dir from vistir.contextmanagers import cd, temp_path from vistir.misc import run from vistir.path import create_tracked_tempdir, ensure_mkdir_p, mkdir_p, rmtree @@ -38,58 +37,45 @@ from .utils import ( get_name_variants, get_pyproject, init_requirement, - read_source, split_vcs_method_from_uri, strip_extras_markers_from_requirement, ) try: import pkg_resources.extern.packaging.requirements as pkg_resources_requirements -except ImportError: +except ModuleNotFoundError: pkg_resources_requirements = None try: - from setuptools.dist import distutils, Distribution + from setuptools.dist import Distribution, distutils except ImportError: import distutils from distutils.core import Distribution -try: - from contextlib import ExitStack -except ImportError: - from contextlib2 import ExitStack - -try: - from os import scandir -except ImportError: - from scandir import scandir - +from contextlib import ExitStack +from os import scandir if MYPY_RUNNING: from typing import ( Any, - Callable, + AnyStr, Dict, - List, Generator, + List, Optional, - Union, + Sequence, + Set, + Text, Tuple, TypeVar, - Text, - Set, - AnyStr, - Sequence, + Union, ) + import requests - from pip_shims.shims import InstallRequirement, PackageFinder - from pkg_resources import ( - PathMetadata, - DistInfoDistribution, - EggInfoDistribution, - Requirement as PkgResourcesRequirement, - ) from packaging.requirements import Requirement as PackagingRequirement + from pip_shims.shims import InstallRequirement, PackageFinder + from pkg_resources import DistInfoDistribution, EggInfoDistribution, PathMetadata + from pkg_resources import Requirement as PkgResourcesRequirement TRequirement = TypeVar("TRequirement") RequirementType = TypeVar( @@ -151,6 +137,7 @@ class BuildEnv(pep517.envbuild.BuildEnvironment): class HookCaller(pep517.wrappers.Pep517HookCaller): def __init__(self, source_dir, build_backend, backend_path=None): + super().__init__(source_dir, build_backend, backend_path=backend_path) self.source_dir = os.path.abspath(source_dir) self.build_backend = build_backend self._subprocess_runner = pep517_subprocess_runner @@ -161,43 +148,6 @@ class HookCaller(pep517.wrappers.Pep517HookCaller): self.backend_path = backend_path -def parse_special_directives(setup_entry, package_dir=None): - # type: (S, Optional[STRING_TYPE]) -> S - rv = setup_entry - if not package_dir: - package_dir = os.getcwd() - if setup_entry.startswith("file:"): - _, path = setup_entry.split("file:") - path = path.strip() - if os.path.exists(path): - rv = read_source(path) - elif setup_entry.startswith("attr:"): - _, resource = setup_entry.split("attr:") - resource = resource.strip() - with temp_path(): - sys.path.insert(0, package_dir) - if "." in resource: - resource, _, attribute = resource.rpartition(".") - package, _, path = resource.partition(".") - base_path = os.path.join(package_dir, package) - if path: - path = os.path.join(base_path, os.path.join(*path.split("."))) - else: - path = base_path - if not os.path.exists(path) and os.path.exists("{0}.py".format(path)): - path = "{0}.py".format(path) - elif os.path.isdir(path): - path = os.path.join(path, "__init__.py") - rv = ast_parse_attribute_from_file(path, attribute) - if rv: - return str(rv) - module = importlib.import_module(resource) - rv = getattr(module, attribute) - if not isinstance(rv, six.string_types): - rv = str(rv) - return rv - - def make_base_requirements(reqs): # type: (Sequence[STRING_TYPE]) -> Set[BaseRequirement] requirements = set() @@ -210,132 +160,384 @@ def make_base_requirements(reqs): req, pkg_resources_requirements.Requirement ): requirements.add(BaseRequirement.from_req(req)) - elif req and isinstance(req, six.string_types) and not req.startswith("#"): + elif req and isinstance(req, str) and not req.startswith("#"): requirements.add(BaseRequirement.from_string(req)) return requirements +def suppress_unparsable(func, *args, **kwargs): + try: + return func(*args, **kwargs) + except Unparsable: + return None + + +class Unparsable(ValueError): + """Not able to parse from setup.py.""" + + +class SetupReader: + """Class that reads a setup.py file without executing it.""" + + @classmethod + def read_setup_py(cls, file: Path, raising: bool = True) -> "Dict[str, Any]": + + with file.open(encoding="utf-8") as f: + content = f.read() + + body = ast.parse(content).body + + setup_call, body = cls._find_setup_call(body) + if not setup_call: + return {} + + if raising: + + def caller(func, *args, **kwargs): + return func(*args, **kwargs) + + else: + caller = suppress_unparsable + + return { + "name": caller(cls._find_single_string, setup_call, body, "name"), + "version": caller(cls._find_single_string, setup_call, body, "version"), + "install_requires": caller(cls._find_install_requires, setup_call, body), + "extras_require": caller(cls._find_extras_require, setup_call, body), + "python_requires": caller( + cls._find_single_string, setup_call, body, "python_requires" + ), + } + + @staticmethod + def read_setup_cfg(file: Path) -> "Dict[str, Any]": + parser = configparser.ConfigParser() + + parser.read(str(file)) + + name = None + version = None + if parser.has_option("metadata", "name"): + name = parser.get("metadata", "name") + + if parser.has_option("metadata", "version"): + version = parser.get("metadata", "version") + + install_requires = [] + extras_require: "Dict[str, List[str]]" = {} + python_requires = None + if parser.has_section("options"): + if parser.has_option("options", "install_requires"): + for dep in parser.get("options", "install_requires").split("\n"): + dep = dep.strip() + if not dep: + continue + + install_requires.append(dep) + + if parser.has_option("options", "python_requires"): + python_requires = parser.get("options", "python_requires") + + if parser.has_section("options.extras_require"): + for group in parser.options("options.extras_require"): + extras_require[group] = [] + deps = parser.get("options.extras_require", group) + for dep in deps.split("\n"): + dep = dep.strip() + if not dep: + continue + + extras_require[group].append(dep) + + return { + "name": name, + "version": version, + "install_requires": install_requires, + "extras_require": extras_require, + "python_requires": python_requires, + } + + @classmethod + def _find_setup_call( + cls, elements: "List[Any]" + ) -> "Tuple[Optional[ast.Call], Optional[List[Any]]]": + funcdefs = [] + for i, element in enumerate(elements): + if isinstance(element, ast.If) and i == len(elements) - 1: + # Checking if the last element is an if statement + # and if it is 'if __name__ == "__main__"' which + # could contain the call to setup() + test = element.test + if not isinstance(test, ast.Compare): + continue + + left = test.left + if not isinstance(left, ast.Name): + continue + + if left.id != "__name__": + continue + + setup_call, body = cls._find_sub_setup_call([element]) + if not setup_call: + continue + + return setup_call, body + elements + if not isinstance(element, ast.Expr): + if isinstance(element, ast.FunctionDef): + funcdefs.append(element) + + continue + + value = element.value + if not isinstance(value, ast.Call): + continue + + func = value.func + if not (isinstance(func, ast.Name) and func.id == "setup") and not ( + isinstance(func, ast.Attribute) + and isinstance(func.value, ast.Name) + and func.value.id == "setuptools" + and func.attr == "setup" + ): + continue + + return value, elements + + # Nothing, we inspect the function definitions + return cls._find_sub_setup_call(funcdefs) + + @classmethod + def _find_sub_setup_call( + cls, elements: "List[Any]" + ) -> "Tuple[Optional[ast.Call], Optional[List[Any]]]": + for element in elements: + if not isinstance(element, (ast.FunctionDef, ast.If)): + continue + + setup_call = cls._find_setup_call(element.body) + if setup_call != (None, None): + setup_call, body = setup_call + + body = elements + body + + return setup_call, body + + return None, None + + @classmethod + def _find_install_requires(cls, call: ast.Call, body: "Iterable[Any]") -> "List[str]": + value = cls._find_in_call(call, "install_requires") + if value is None: + # Trying to find in kwargs + kwargs = cls._find_call_kwargs(call) + + if kwargs is None: + return [] + + if not isinstance(kwargs, ast.Name): + raise Unparsable() + + variable = cls._find_variable_in_body(body, kwargs.id) + if not isinstance(variable, (ast.Dict, ast.Call)): + raise Unparsable() + + if isinstance(variable, ast.Call): + if not isinstance(variable.func, ast.Name): + raise Unparsable() + + if variable.func.id != "dict": + raise Unparsable() + + value = cls._find_in_call(variable, "install_requires") + else: + value = cls._find_in_dict(variable, "install_requires") + + if value is None: + return [] + + if isinstance(value, ast.List): + return [el.s for el in value.elts] + elif isinstance(value, ast.Name): + variable = cls._find_variable_in_body(body, value.id) + + if variable is not None and isinstance(variable, ast.List): + return [el.s for el in variable.elts] + + raise Unparsable() + + @classmethod + def _find_extras_require( + cls, call: ast.Call, body: "Iterable[Any]" + ) -> "Dict[str, List[str]]": + extras_require: "Dict[str, List[str]]" = {} + value = cls._find_in_call(call, "extras_require") + if value is None: + # Trying to find in kwargs + kwargs = cls._find_call_kwargs(call) + + if kwargs is None: + return extras_require + + if not isinstance(kwargs, ast.Name): + raise Unparsable() + + variable = cls._find_variable_in_body(body, kwargs.id) + if not isinstance(variable, (ast.Dict, ast.Call)): + raise Unparsable() + + if isinstance(variable, ast.Call): + if not isinstance(variable.func, ast.Name): + raise Unparsable() + + if variable.func.id != "dict": + raise Unparsable() + + value = cls._find_in_call(variable, "extras_require") + else: + value = cls._find_in_dict(variable, "extras_require") + + if value is None: + return extras_require + + if isinstance(value, ast.Dict): + for key, val in zip(value.keys, value.values): + if isinstance(val, ast.Name): + val = cls._find_variable_in_body(body, val.id) + + if isinstance(val, ast.List): + extras_require[key.s] = [e.s for e in val.elts] + else: + raise Unparsable() + elif isinstance(value, ast.Name): + variable = cls._find_variable_in_body(body, value.id) + + if variable is None or not isinstance(variable, ast.Dict): + raise Unparsable() + + for key, val in zip(variable.keys, variable.values): + if isinstance(val, ast.Name): + val = cls._find_variable_in_body(body, val.id) + + if isinstance(val, ast.List): + extras_require[key.s] = [e.s for e in val.elts] + else: + raise Unparsable() + else: + raise Unparsable() + + return extras_require + + @classmethod + def _find_single_string( + cls, call: ast.Call, body: "List[Any]", name: str + ) -> "Optional[str]": + value = cls._find_in_call(call, name) + if value is None: + # Trying to find in kwargs + kwargs = cls._find_call_kwargs(call) + if kwargs is None: + return None + + if not isinstance(kwargs, ast.Name): + raise Unparsable() + + variable = cls._find_variable_in_body(body, kwargs.id) + if not isinstance(variable, (ast.Dict, ast.Call)): + raise Unparsable() + + if isinstance(variable, ast.Call): + if not isinstance(variable.func, ast.Name): + raise Unparsable() + + if variable.func.id != "dict": + raise Unparsable() + + value = cls._find_in_call(variable, name) + else: + value = cls._find_in_dict(variable, name) + + if value is None: + return None + + if isinstance(value, ast.Str): + return value.s + elif isinstance(value, ast.Name): + variable = cls._find_variable_in_body(body, value.id) + + if variable is not None and isinstance(variable, ast.Str): + return variable.s + + raise Unparsable() + + @staticmethod + def _find_in_call(call: ast.Call, name: str) -> "Optional[Any]": + for keyword in call.keywords: + if keyword.arg == name: + return keyword.value + return None + + @staticmethod + def _find_call_kwargs(call: ast.Call) -> "Optional[Any]": + kwargs = None + for keyword in call.keywords: + if keyword.arg is None: + kwargs = keyword.value + + return kwargs + + @staticmethod + def _find_variable_in_body(body: "Iterable[Any]", name: str) -> "Optional[Any]": + for elem in body: + + if not isinstance(elem, (ast.Assign, ast.AnnAssign)): + continue + + if getattr(elem, "target", None) and elem.target.id == name: + return elem.value + + for target in elem.targets: + if not isinstance(target, ast.Name): + continue + + if target.id == name: + return elem.value + return None + + @staticmethod + def _find_in_dict(dict_: ast.Dict, name: str) -> "Optional[Any]": + for key, val in zip(dict_.keys, dict_.values): + if isinstance(key, ast.Str) and key.s == name: + return val + return None + + def setuptools_parse_setup_cfg(path): from setuptools.config import read_configuration parsed = read_configuration(path) results = parsed.get("metadata", {}) results.update(parsed.get("options", {})) - results["install_requires"] = make_base_requirements( - results.get("install_requires", []) - ) - extras = {} - for extras_section, extras_reqs in results.get("extras_require", {}).items(): - new_reqs = tuple(make_base_requirements(extras_reqs)) - if new_reqs: - extras[extras_section] = new_reqs - results["extras_require"] = extras - results["setup_requires"] = make_base_requirements(results.get("setup_requires", [])) + if "install_requires" in results: + results["install_requires"] = make_base_requirements( + results.get("install_requires", []) + ) + if "extras_require" in results: + extras = {} + for extras_section, extras_reqs in results.get("extras_require", {}).items(): + new_reqs = tuple(make_base_requirements(extras_reqs)) + if new_reqs: + extras[extras_section] = new_reqs + results["extras_require"] = extras + if "setup_requires" in results: + results["setup_requires"] = make_base_requirements( + results.get("setup_requires", []) + ) return results -def get_package_dir_from_setupcfg(parser, base_dir=None): - # type: (configparser.ConfigParser, STRING_TYPE) -> Text - if base_dir is not None: - package_dir = base_dir - else: - package_dir = os.getcwd() - if parser.has_option("options.packages.find", "where"): - pkg_dir = parser.get("options.packages.find", "where") - if isinstance(pkg_dir, Mapping): - pkg_dir = pkg_dir.get("where") - package_dir = os.path.join(package_dir, pkg_dir) - elif parser.has_option("options", "packages"): - pkg_dir = parser.get("options", "packages") - if "find:" in pkg_dir: - _, pkg_dir = pkg_dir.split("find:") - pkg_dir = pkg_dir.strip() - package_dir = os.path.join(package_dir, pkg_dir) - elif os.path.exists(os.path.join(package_dir, "setup.py")): - setup_py = ast_parse_setup_py(os.path.join(package_dir, "setup.py")) - if "package_dir" in setup_py: - package_lookup = setup_py["package_dir"] - if not isinstance(package_lookup, Mapping): - package_dir = package_lookup - package_dir = package_lookup.get( - next(iter(list(package_lookup.keys()))), package_dir - ) - if not os.path.isabs(package_dir): - if not base_dir: - package_dir = os.path.join(os.path.getcwd(), package_dir) - else: - package_dir = os.path.join(base_dir, package_dir) - return package_dir - - -def get_name_and_version_from_setupcfg(parser, package_dir): - # type: (configparser.ConfigParser, STRING_TYPE) -> Tuple[Optional[S], Optional[S]] - name, version = None, None - if parser.has_option("metadata", "name"): - name = parse_special_directives(parser.get("metadata", "name"), package_dir) - if parser.has_option("metadata", "version"): - version = parse_special_directives(parser.get("metadata", "version"), package_dir) - return name, version - - -def get_extras_from_setupcfg(parser): - # type: (configparser.ConfigParser) -> Dict[STRING_TYPE, Tuple[BaseRequirement, ...]] - extras = {} # type: Dict[STRING_TYPE, Tuple[BaseRequirement, ...]] - if "options.extras_require" not in parser.sections(): - return extras - extras_require_section = parser.options("options.extras_require") - for section in extras_require_section: - if section in ["options", "metadata"]: - continue - section_contents = parser.get("options.extras_require", section) - section_list = section_contents.split("\n") - section_extras = tuple(make_base_requirements(section_list)) - if section_extras: - extras[section] = section_extras - return extras - - -def parse_setup_cfg( - setup_cfg_contents, # type: S - base_dir, # type: S -): - # type: (...) -> Dict[S, Union[S, None, Set[BaseRequirement], List[S], Dict[STRING_TYPE, Tuple[BaseRequirement]]]] - default_opts = { - "metadata": {"name": "", "version": ""}, - "options": { - "install_requires": "", - "python_requires": "", - "build_requires": "", - "setup_requires": "", - "extras": "", - "packages.find": {"where": "."}, - }, - } - parser = configparser.ConfigParser(default_opts) - if six.PY2: - buff = io.BytesIO(setup_cfg_contents) - parser.readfp(buff) - else: - parser.read_string(setup_cfg_contents) - results = {} - package_dir = get_package_dir_from_setupcfg(parser, base_dir=base_dir) - name, version = get_name_and_version_from_setupcfg(parser, package_dir) - results["name"] = name - results["version"] = version - install_requires = set() # type: Set[BaseRequirement] - if parser.has_option("options", "install_requires"): - install_requires = make_base_requirements( - parser.get("options", "install_requires").split("\n") - ) - results["install_requires"] = install_requires - if parser.has_option("options", "python_requires"): - results["python_requires"] = parse_special_directives( - parser.get("options", "python_requires"), package_dir - ) - if parser.has_option("options", "build_requires"): - results["build_requires"] = parser.get("options", "build_requires") - results["extras_require"] = get_extras_from_setupcfg(parser) - return results +def parse_setup_cfg(path: str) -> "Dict[str, Any]": + return SetupReader.read_setup_cfg(Path(path)) @contextlib.contextmanager @@ -405,13 +607,25 @@ def ensure_reqs(reqs): for req in reqs: if not req: continue - if isinstance(req, six.string_types): + if isinstance(req, str): req = pkg_resources.Requirement.parse("{0}".format(str(req))) # req = strip_extras_markers_from_requirement(req) new_reqs.append(req) return new_reqs +def any_valid_values(data: "Dict[str, Any]", fields: "Iterable[str]") -> bool: + def is_valid(value: "Any") -> bool: + if isinstance(value, (list, tuple)): + return all(map(is_valid, value)) + elif isinstance(value, dict): + return all(map(is_valid, value.values())) + return isinstance(value, str) + + fields = [field for field in fields if field in data] + return fields and all(is_valid(data[field]) for field in fields) + + def _prepare_wheel_building_kwargs( ireq=None, # type: Optional[InstallRequirement] src_root=None, # type: Optional[STRING_TYPE] @@ -587,7 +801,7 @@ def get_extra_name_from_marker(marker): def get_metadata_from_wheel(wheel_path): # type: (S) -> Dict[Any, Any] - if not isinstance(wheel_path, six.string_types): + if not isinstance(wheel_path, str): raise TypeError("Expected string instance, received {0!r}".format(wheel_path)) try: dist = Wheel(wheel_path) @@ -662,604 +876,8 @@ def get_metadata_from_dist(dist): } -AST_BINOP_MAP = dict( - ( - (ast.Add, operator.add), - (ast.Sub, operator.sub), - (ast.Mult, operator.mul), - (ast.Div, operator.floordiv), - (ast.Mod, operator.mod), - (ast.Pow, operator.pow), - (ast.LShift, operator.lshift), - (ast.RShift, operator.rshift), - (ast.BitAnd, operator.and_), - (ast.BitOr, operator.or_), - (ast.BitXor, operator.xor), - ) -) - - -AST_COMPARATORS = dict( - ( - (ast.Lt, operator.lt), - (ast.LtE, operator.le), - (ast.Eq, operator.eq), - (ast.Gt, operator.gt), - (ast.GtE, operator.ge), - (ast.NotEq, operator.ne), - (ast.Is, operator.is_), - (ast.IsNot, operator.is_not), - (ast.And, operator.and_), - (ast.Or, operator.or_), - (ast.Not, operator.not_), - (ast.In, lambda a, b: operator.contains(b, a)), - ) -) - -if getattr(ast, "AnnAssign", None): - ASSIGN_NODES = (ast.Assign, ast.AnnAssign) -else: - ASSIGN_NODES = (ast.Assign,) - - -class Analyzer(ast.NodeVisitor): - def __init__(self): - self.name_types = [] - self.function_map = {} # type: Dict[Any, Any] - self.function_names = {} - self.resolved_function_names = {} - self.functions = [] - self.strings = [] - self.assignments = {} - self.binOps = [] - self.binOps_map = {} - self.recurse = True - super(Analyzer, self).__init__() - - def generic_visit(self, node): - if isinstance(node, ast.Call): - self.functions.append(node) - self.function_map.update(ast_unparse(node, initial_mapping=True)) - if isinstance(node, ast.Name): - self.name_types.append(node) - if isinstance(node, ast.Str): - self.strings.append(node) - if isinstance(node, ASSIGN_NODES): - self.assignments.update(ast_unparse(node, initial_mapping=True)) - super(Analyzer, self).generic_visit(node) - - @contextlib.contextmanager - def no_recurse(self): - original_recurse_val = self.recurse - try: - self.recurse = False - yield - finally: - self.recurse = original_recurse_val - - def visit_BinOp(self, node): - node = ast_unparse(node, initial_mapping=True) - self.binOps.append(node) - - def unmap_binops(self): - for binop in self.binOps: - self.binOps_map[binop] = ast_unparse(binop, analyzer=self) - - def match_assignment_str(self, match): - matches = [k for k in self.assignments if getattr(k, "id", "") == match] - if matches: - return matches[-1] - return None - - def match_assignment_name(self, match): - matches = [k for k in self.assignments if getattr(k, "id", "") == match.id] - if matches: - return matches[-1] - return None - - def generic_unparse(self, item): - if any(isinstance(item, k) for k in AST_BINOP_MAP.keys()): - return AST_BINOP_MAP[type(item)] - elif any(isinstance(item, k) for k in AST_COMPARATORS.keys()): - return AST_COMPARATORS[type(item)] - return item - - def unparse(self, item): - unparser = getattr( - self, "unparse_{0}".format(item.__class__.__name__), self.generic_unparse - ) - return unparser(item) - - def unparse_Dict(self, item): - # unparsed = dict(zip(unparse(item.keys), unparse(item.values))) - return dict( - (self.unparse(k), self.unparse(v)) for k, v in zip(item.keys, item.values) - ) - - def unparse_List(self, item): - return [self.unparse(el) for el in item.elts] - - def unparse_Tuple(self, item): - return tuple([self.unparse(el) for el in item.elts]) - - def unparse_Str(self, item): - return item.s - - def unparse_Subscript(self, item): - unparsed = self.unparse(item.value) - if isinstance(item.slice, ast.Index): - try: - unparsed = unparsed[self.unparse(item.slice.value)] - except (KeyError, TypeError): - # not everything can be looked up before runtime - unparsed = item - return unparsed - - def unparse_Num(self, item): - return item.n - - def unparse_BinOp(self, item): - if item in self.binOps_map: - unparsed = self.binOps_map[item] - else: - right_item = self.unparse(item.right) - left_item = self.unparse(item.left) - op = getattr(item, "op", None) - op_func = self.unparse(op) if op is not None else op - try: - unparsed = op_func(left_item, right_item) - except Exception: - unparsed = (left_item, op_func, right_item) - return unparsed - - def unparse_Name(self, item): - unparsed = item.id - if not self.recurse: - return unparsed - if item in self.assignments and self.recurse: - items = self.unparse(self.assignments[item]) - unparsed = items.get(item.id, item.id) - else: - assignment = self.match_assignment_name(item) - if assignment is not None: - items = self.unparse(self.assignments[assignment]) - unparsed = items.get(item.id, item.id) - return unparsed - - def unparse_NameConstant(self, item): - return item.value - - def unparse_Constant(self, item): - return item.value - - def unparse_Ellipsis(self, item): - return item.value - - def unparse_Attribute(self, item): - attr_name = getattr(item, "value", None) - attr_attr = getattr(item, "attr", None) - name = None - name = self.unparse(attr_name) if attr_name is not None else attr_attr - if attr_name and not self.recurse: - name = attr_name - elif name and attr_attr: - if isinstance(name, six.string_types): - unparsed = ".".join([item for item in (name, attr_attr) if item]) - else: - unparsed = item - elif attr_attr and not name: - unparsed = attr_attr - else: - unparsed = name if not unparsed else unparsed - return unparsed - - def unparse_Compare(self, item): - if isinstance(item.left, ast.Attribute) or isinstance(item.left, ast.Str): - import importlib - - left = self.unparse(item.left) - if "." in left: - name, _, val = left.rpartition(".") - left = getattr(importlib.import_module(name), val, left) - comparators = [] - for comparator in item.comparators: - right = self.unparse(comparator) - if isinstance(comparator, ast.Attribute) and "." in right: - name, _, val = right.rpartition(".") - right = getattr(importlib.import_module(name), val, right) - comparators.append(right) - unparsed = (left, self.unparse(item.ops), comparators) - else: - unparsed = item - return unparsed - - def unparse_IfExp(self, item): - ops, truth_vals = [], [] - if isinstance(item.test, ast.Compare): - left, ops, right = self.unparse(item.test) - else: - result = self.unparse(item.test) - if isinstance(result, dict): - k, v = result.popitem() - if not v: - truth_vals = [False] - for i, op in enumerate(ops): - if i == 0: - truth_vals.append(op(left, right[i])) - else: - truth_vals.append(op(right[i - 1], right[i])) - if all(truth_vals): - unparsed = self.unparse(item.body) - else: - unparsed = self.unparse(item.orelse) - return unparsed - - def unparse_Call(self, item): - unparsed = {} - if isinstance(item.func, (ast.Name, ast.Attribute)): - func_name = self.unparse(item.func) - else: - try: - func_name = self.unparse(item.func) - except Exception: - func_name = None - if not func_name: - return {} - if isinstance(func_name, dict): - unparsed.update(func_name) - func_name = next(iter(func_name.keys())) - else: - unparsed[func_name] = {} - for key in ("kwargs", "keywords"): - val = getattr(item, key, []) - if val is None: - continue - for keyword in self.unparse(val): - unparsed[func_name].update(self.unparse(keyword)) - return unparsed - - def unparse_keyword(self, item): - return {self.unparse(item.arg): self.unparse(item.value)} - - def unparse_Assign(self, item): - # XXX: DO NOT UNPARSE THIS - # XXX: If we unparse this it becomes impossible to map it back - # XXX: To the original node in the AST so we can find the - # XXX: Original reference - with self.no_recurse(): - target = self.unparse(next(iter(item.targets))) - val = self.unparse(item.value) - if isinstance(target, (tuple, set, list)): - unparsed = dict(zip(target, val)) - else: - unparsed = {target: val} - return unparsed - - def unparse_Mapping(self, item): - unparsed = {} - for k, v in item.items(): - try: - unparsed[self.unparse(k)] = self.unparse(v) - except TypeError: - unparsed[k] = self.unparse(v) - return unparsed - - def unparse_list(self, item): - return type(item)([self.unparse(el) for el in item]) - - def unparse_tuple(self, item): - return self.unparse_list(item) - - def unparse_str(self, item): - return item - - def parse_function_names(self, should_retry=True, function_map=None): - if function_map is None: - function_map = {} - retries = [] - for k, v in function_map.items(): - fn_name = "" - if k in self.function_names: - fn_name = self.function_names[k] - elif isinstance(k, ast.Name): - fn_name = k.id - elif isinstance(k, ast.Attribute): - try: - fn = ast_unparse(k, analyzer=self) - except Exception: - if should_retry: - retries.append((k, v)) - continue - else: - if isinstance(fn, six.string_types): - _, _, fn_name = fn.rpartition(".") - if fn_name: - self.resolved_function_names[fn_name] = ast_unparse(v, analyzer=self) - return retries - - def parse_functions(self): - retries = self.parse_function_names(function_map=self.function_map) - if retries: - failures = self.parse_function_names( - should_retry=False, function_map=dict(retries) - ) - return self.resolved_function_names - - def parse_setup_function(self): - setup = {} # type: Dict[Any, Any] - self.unmap_binops() - function_names = self.parse_functions() - if "setup" in function_names: - setup = self.unparse(function_names["setup"]) - keys = list(setup.keys()) - if len(keys) == 1 and keys[0] is None: - _, setup = setup.popitem() - keys = list(setup.keys()) - for k in keys: - # XXX: Remove unresolved functions from the setup dictionary - if isinstance(setup[k], dict): - if not setup[k]: - continue - key = next(iter(setup[k].keys())) - val = setup[k][key] - if key in function_names and val is None or val == {}: - setup.pop(k) - return setup - - -def _ensure_hashable(item): - try: - hash(item) - except TypeError: - return str(item) - else: - return item - - -def ast_unparse(item, initial_mapping=False, analyzer=None, recurse=True): # noqa:C901 - # type: (Any, bool, Optional[Analyzer], bool) -> Union[List[Any], Dict[Any, Any], Tuple[Any, ...], STRING_TYPE] - unparse = partial( - ast_unparse, initial_mapping=initial_mapping, analyzer=analyzer, recurse=recurse - ) - if getattr(ast, "Constant", None): - constant = (ast.Constant, ast.Ellipsis) - else: - constant = ast.Ellipsis - unparsed = item - if isinstance(item, ast.Dict): - unparsed = dict( - zip(map(_ensure_hashable, unparse(item.keys)), unparse(item.values)) - ) - elif isinstance(item, ast.List): - unparsed = [unparse(el) for el in item.elts] - elif isinstance(item, ast.Tuple): - unparsed = tuple([unparse(el) for el in item.elts]) - elif isinstance(item, ast.Str): - unparsed = item.s - elif isinstance(item, ast.Subscript): - unparsed = unparse(item.value) - if not initial_mapping: - if isinstance(item.slice, ast.Index): - try: - unparsed = unparsed[unparse(item.slice.value)] - except (KeyError, TypeError): - # not everything can be looked up before runtime - unparsed = item - elif any(isinstance(item, k) for k in AST_BINOP_MAP.keys()): - unparsed = AST_BINOP_MAP[type(item)] - elif isinstance(item, ast.Num): - unparsed = item.n - elif isinstance(item, ast.BinOp): - if analyzer and item in analyzer.binOps_map: - unparsed = analyzer.binOps_map[item] - else: - right_item = unparse(item.right) - left_item = unparse(item.left) - op = getattr(item, "op", None) - op_func = unparse(op) if op is not None else op - if not initial_mapping: - try: - unparsed = op_func(left_item, right_item) - except Exception: - unparsed = (left_item, op_func, right_item) - else: - item.left = left_item - item.right = right_item - item.op = op_func - unparsed = item - elif isinstance(item, ast.Name): - if not initial_mapping: - unparsed = item.id - if analyzer and recurse: - if item in analyzer.assignments: - items = unparse(analyzer.assignments[item]) - unparsed = items.get(item.id, item.id) - else: - assignment = analyzer.match_assignment_name(item) - if assignment is not None: - items = unparse(analyzer.assignments[assignment]) - unparsed = items.get(item.id, item.id) - else: - unparsed = item - elif six.PY3 and isinstance(item, ast.NameConstant): - unparsed = item.value - elif any(isinstance(item, k) for k in AST_COMPARATORS.keys()): - unparsed = AST_COMPARATORS[type(item)] - elif isinstance(item, constant): - unparsed = item.value - elif isinstance(item, ast.Compare): - if isinstance(item.left, ast.Attribute) or isinstance(item.left, ast.Str): - import importlib - - left = unparse(item.left) - if "." in left: - name, _, val = left.rpartition(".") - left = getattr(importlib.import_module(name), val, left) - comparators = [] - for comparator in item.comparators: - right = unparse(comparator) - if isinstance(comparator, ast.Attribute) and "." in right: - name, _, val = right.rpartition(".") - right = getattr(importlib.import_module(name), val, right) - comparators.append(right) - unparsed = (left, unparse(item.ops), comparators) - elif isinstance(item, ast.IfExp): - if initial_mapping: - unparsed = item - else: - ops, truth_vals = [], [] - if isinstance(item.test, ast.Compare): - left, ops, right = unparse(item.test) - else: - result = ast_unparse(item.test) - if isinstance(result, dict): - k, v = result.popitem() - if not v: - truth_vals = [False] - for i, op in enumerate(ops): - if i == 0: - truth_vals.append(op(left, right[i])) - else: - truth_vals.append(op(right[i - 1], right[i])) - if all(truth_vals): - unparsed = unparse(item.body) - else: - unparsed = unparse(item.orelse) - elif isinstance(item, ast.Attribute): - attr_name = getattr(item, "value", None) - attr_attr = getattr(item, "attr", None) - name = None - if initial_mapping: - unparsed = item - elif attr_name and not recurse: - name = attr_name - else: - name = unparse(attr_name) if attr_name is not None else attr_attr - if name and attr_attr: - if not initial_mapping and isinstance(name, six.string_types): - unparsed = ".".join([item for item in (name, attr_attr) if item]) - else: - unparsed = item - elif attr_attr and not name and not initial_mapping: - unparsed = attr_attr - else: - unparsed = name if not unparsed else unparsed - elif isinstance(item, ast.Call): - unparsed = {} - if isinstance(item.func, (ast.Name, ast.Attribute)): - func_name = unparse(item.func) - else: - try: - func_name = unparse(item.func) - except Exception: - func_name = None - if func_name and not isinstance(func_name, dict): - unparsed[func_name] = {} - if isinstance(func_name, dict): - unparsed.update(func_name) - func_name = next(iter(func_name.keys())) - if func_name: - for key in ("kwargs", "keywords"): - val = getattr(item, key, []) - if val is None: - continue - if isinstance(val, ast.Name): - unparsed[func_name] = val - else: - for keyword in unparse(val): - unparsed[func_name].update(unparse(keyword)) - elif isinstance(item, ast.keyword): - unparsed = {unparse(item.arg): unparse(item.value)} - elif isinstance(item, ASSIGN_NODES): - # XXX: DO NOT UNPARSE THIS - # XXX: If we unparse this it becomes impossible to map it back - # XXX: To the original node in the AST so we can find the - # XXX: Original reference - try: - targets = item.targets # for ast.Assign - except AttributeError: # for ast.AnnAssign - targets = (item.target,) - if not initial_mapping: - target = unparse(next(iter(targets)), recurse=False) - val = unparse(item.value, recurse=False) - if isinstance(target, (tuple, set, list)): - unparsed = dict(zip(target, val)) - else: - unparsed = {target: val} - else: - unparsed = {next(iter(targets)): item} - elif isinstance(item, Mapping): - unparsed = {} - for k, v in item.items(): - try: - unparsed[unparse(k)] = unparse(v) - except TypeError: - unparsed[k] = unparse(v) - elif isinstance(item, (list, tuple)): - unparsed = type(item)([unparse(el) for el in item]) - elif isinstance(item, six.string_types): - unparsed = item - return unparsed - - -def ast_parse_attribute_from_file(path, attribute): - # type: (S) -> Any - analyzer = ast_parse_file(path) - target_value = None - for k, v in analyzer.assignments.items(): - name = "" - if isinstance(k, ast.Name): - name = k.id - elif isinstance(k, ast.Attribute): - fn = ast_unparse(k) - if isinstance(fn, six.string_types): - _, _, name = fn.rpartition(".") - if name == attribute: - target_value = ast_unparse(v, analyzer=analyzer) - break - if isinstance(target_value, Mapping) and attribute in target_value: - return target_value[attribute] - return target_value - - -def ast_parse_file(path): - # type: (S) -> Analyzer - try: - tree = ast.parse(read_source(path)) - except SyntaxError: - # The source may be encoded strangely, e.g. azure-storage - # which has a setup.py encoded with utf-8-sig - with open(path, "rb") as fh: - contents = fh.read() - encoding = chardet.detect(contents)["encoding"] - tree = ast.parse(contents.decode(encoding)) - ast_analyzer = Analyzer() - ast_analyzer.visit(tree) - return ast_analyzer - - -def ast_parse_setup_py(path): - # type: (S) -> Dict[Any, Any] - ast_analyzer = ast_parse_file(path) - setup = {} # type: Dict[Any, Any] - ast_analyzer.unmap_binops() - function_names = ast_analyzer.parse_functions() - if "setup" in function_names: - setup = ast_unparse(function_names["setup"], analyzer=ast_analyzer) - keys = list(setup.keys()) - if len(keys) == 1 and keys[0] is None: - _, setup = setup.popitem() - keys = list(setup.keys()) - for k in keys: - # XXX: Remove unresolved functions from the setup dictionary - if isinstance(setup[k], dict): - if not setup[k]: - continue - key = next(iter(setup[k].keys())) - val = setup[k][key] - if key in function_names and val is None or val == {}: - setup.pop(k) - return setup +def ast_parse_setup_py(path: str, raising: bool = True) -> "Dict[str, Any]": + return SetupReader.read_setup_py(Path(path), raising) def run_setup(script_path, egg_base=None): @@ -1287,26 +905,16 @@ def run_setup(script_path, egg_base=None): script_name = os.path.basename(script_path) g = {"__file__": script_name, "__name__": "__main__"} sys.path.insert(0, target_cwd) - local_dict = {} - if sys.version_info < (3, 5): - save_argv = sys.argv - else: - save_argv = sys.argv.copy() + + save_argv = sys.argv.copy() try: global _setup_distribution, _setup_stop_after _setup_stop_after = "run" sys.argv[0] = script_name sys.argv[1:] = args with open(script_name, "rb") as f: - contents = f.read() - if six.PY3: - contents.replace(br"\r\n", br"\n") - else: - contents.replace(r"\r\n", r"\n") - if sys.version_info < (3, 5): - exec(contents, g, local_dict) - else: - exec(contents, g) + contents = f.read().replace(br"\r\n", br"\n") + exec(contents, g) # We couldn't import everything needed to run setup except Exception: python = os.environ.get("PIP_PYTHON_PATH", sys.executable) @@ -1479,7 +1087,7 @@ class SetupInfo(object): def update_from_dict(self, metadata): name = metadata.get("name", self.name) - if isinstance(name, six.string_types): + if isinstance(name, str): self.name = self.name if self.name else name version = metadata.get("version", None) if version: @@ -1511,14 +1119,14 @@ class SetupInfo(object): self.python_requires = metadata.get("python_requires", self.python_requires) extras_require = metadata.get("extras_require", {}) extras_tuples = [] - for section in set(list(extras_require.keys())) - set(list(self.extras.keys())): + if self._extras_requirements is None: + self._extras_requirements = () + for section in set(extras_require) - {v[0] for v in self._extras_requirements}: extras = extras_require[section] extras_set = make_base_requirements(extras) if self.ireq and self.ireq.extras and section in self.ireq.extras: requirements |= extras_set extras_tuples.append((section, tuple(extras_set))) - if self._extras_requirements is None: - self._extras_requirements = () self._extras_requirements += tuple(extras_tuples) build_backend = metadata.get("build_backend", "setuptools.build_meta:__legacy__") if not self.build_backend: @@ -1539,14 +1147,10 @@ class SetupInfo(object): def parse_setup_cfg(self): # type: () -> Dict[STRING_TYPE, Any] if self.setup_cfg is not None and self.setup_cfg.exists(): - contents = self.setup_cfg.read_text() - base_dir = self.setup_cfg.absolute().parent.as_posix() try: parsed = setuptools_parse_setup_cfg(self.setup_cfg.as_posix()) except Exception: - if six.PY2: - contents = self.setup_cfg.read_bytes() - parsed = parse_setup_cfg(contents, base_dir) + parsed = parse_setup_cfg(self.setup_cfg.as_posix()) if not parsed: return {} return parsed @@ -1615,7 +1219,7 @@ class SetupInfo(object): ['"{0}"'.format(r) for r in self.build_requires] ) self.pyproject.write_text( - six.text_type( + str( """ [build-system] requires = [{0}] @@ -1648,7 +1252,7 @@ build-backend = "{1}" ['"{0}"'.format(r) for r in self.build_requires] ) self.pyproject.write_text( - six.text_type( + str( """ [build-system] requires = [{0}] @@ -1771,7 +1375,12 @@ build-backend = "{1}" _metadata += (k, v) self.metadata = _metadata cleaned = metadata.copy() - cleaned.update({"install_requires": metadata.get("requires", [])}) + cleaned.update( + { + "install_requires": metadata.get("requires", []), + "extras_require": metadata.get("extras", {}), + } + ) if cleaned: self.update_from_dict(cleaned.copy()) else: @@ -1785,7 +1394,6 @@ build-backend = "{1}" :return: The current instance :rtype: `SetupInfo` """ - if self.pyproject and self.pyproject.exists(): result = get_pyproject(self.pyproject.parent) if result is not None: @@ -1806,32 +1414,36 @@ build-backend = "{1}" # type: () -> Dict[S, Any] parse_setupcfg = False parse_setuppy = False + self.run_pyproject() if self.setup_cfg and self.setup_cfg.exists(): parse_setupcfg = True if self.setup_py and self.setup_py.exists(): parse_setuppy = True - if parse_setuppy or parse_setupcfg: - with cd(self.base_dir): - if parse_setuppy: - self.update_from_dict(self.parse_setup_py()) - if parse_setupcfg: - self.update_from_dict(self.parse_setup_cfg()) - if self.name is not None and any( - [ - self.requires, - self.setup_requires, - self._extras_requirements, - self.build_backend, - ] - ): + if ( + self.build_backend.startswith("setuptools") + and parse_setuppy + or parse_setupcfg + ): + parsed = {} + try: + with cd(self.base_dir): + if parse_setuppy: + parsed.update(self.parse_setup_py()) + if parse_setupcfg: + parsed.update(self.parse_setup_cfg()) + except Unparsable: + pass + else: + self.update_from_dict(parsed) return self.as_dict() + return self.get_info() def get_info(self): # type: () -> Dict[S, Any] - with cd(self.base_dir): - self.run_pyproject() - self.build() + if self.metadata is None: + with cd(self.base_dir): + self.build() if self.setup_py and self.setup_py.exists() and self.metadata is None: if not self.requires or not self.name: @@ -1893,8 +1505,7 @@ build-backend = "{1}" cmd = pip_shims.shims.InstallCommand() options, _ = cmd.parser.parse_args([]) session = cmd._build_session(options) - finder = cmd._build_package_finder(options, session) - tempdir_manager = stack.enter_context(pip_shims.shims.global_tempdir_manager()) + stack.enter_context(pip_shims.shims.global_tempdir_manager()) vcs, uri = split_vcs_method_from_uri(ireq.link.url_without_fragment) parsed = urlparse(uri) if "file" in parsed.scheme: diff --git a/pipenv/vendor/requirementslib/models/url.py b/pipenv/vendor/requirementslib/models/url.py index 8f5d8488..106d6d4c 100644 --- a/pipenv/vendor/requirementslib/models/url.py +++ b/pipenv/vendor/requirementslib/models/url.py @@ -1,11 +1,13 @@ # -*- coding=utf-8 -*- from __future__ import absolute_import, print_function +from urllib.parse import quote +from urllib.parse import unquote as url_unquote +from urllib.parse import unquote_plus + import attr import pip_shims.shims from orderedmultidict import omdict -from six.moves.urllib.parse import quote, unquote_plus, unquote as url_unquote -from urllib3 import util as urllib3_util from urllib3.util import parse_url as urllib3_parse from urllib3.util.url import Url @@ -14,9 +16,9 @@ from ..utils import is_installable_file from .utils import extras_to_string, parse_extras if MYPY_RUNNING: - from typing import Dict, List, Optional, Text, Tuple, TypeVar, Union + from typing import Dict, Optional, Text, Tuple, TypeVar, Union + from pip_shims.shims import Link - from vistir.compat import Path _T = TypeVar("_T") STRING_TYPE = Union[bytes, str, Text] diff --git a/pipenv/vendor/requirementslib/models/utils.py b/pipenv/vendor/requirementslib/models/utils.py index 59900c68..c0f4b239 100644 --- a/pipenv/vendor/requirementslib/models/utils.py +++ b/pipenv/vendor/requirementslib/models/utils.py @@ -7,9 +7,10 @@ import re import string import sys from collections import defaultdict +from functools import lru_cache from itertools import chain, groupby +from pathlib import Path -import six import tomlkit from attr import validators from packaging.markers import InvalidMarker, Marker, Op, Value, Variable @@ -20,7 +21,6 @@ from tomlkit.container import Container from tomlkit.items import AoT, Array, Bool, InlineTable, Item, String, Table from urllib3 import util as urllib3_util from urllib3.util import parse_url as urllib3_parse -from vistir.compat import lru_cache from vistir.misc import dedup from vistir.path import is_valid_url @@ -28,33 +28,31 @@ from ..environment import MYPY_RUNNING from ..utils import SCHEME_LIST, VCS_LIST, is_star if MYPY_RUNNING: + from typing import Iterable # noqa + from typing import ( + Any, + AnyStr, + Dict, + List, + Match, + Optional, + Sequence, + Set, + Text, + Tuple, + TypeVar, + Union, + ) + from attr import _ValidatorType # noqa + from packaging.markers import Marker as PkgResourcesMarker + from packaging.markers import Op as PkgResourcesOp + from packaging.markers import Value as PkgResourcesValue + from packaging.markers import Variable as PkgResourcesVariable from packaging.requirements import Requirement as PackagingRequirement from pip_shims.shims import Link from pkg_resources import Requirement as PkgResourcesRequirement - from pkg_resources.extern.packaging.markers import ( - Op as PkgResourcesOp, - Variable as PkgResourcesVariable, - Value as PkgResourcesValue, - Marker as PkgResourcesMarker, - ) - from typing import ( - Union, - Optional, - List, - Set, - Any, - TypeVar, - Tuple, - Sequence, - Dict, - Text, - AnyStr, - Match, - Iterable, # noqa - ) from urllib3.util.url import Url - from vistir.compat import Path _T = TypeVar("_T") TMarker = Union[Marker, PkgResourcesMarker] @@ -115,9 +113,9 @@ def optional_instance_of(cls): def create_link(link): # type: (AnyStr) -> Link - if not isinstance(link, six.string_types): + if not isinstance(link, str): raise TypeError("must provide a string to instantiate a new link") - from pip_shims.shims import Link + from pip_shims.shims import Link # noqa: F811 return Link(link) @@ -178,14 +176,13 @@ def tomlkit_dict_to_python(toml_dict): def get_url_name(url): # type: (AnyStr) -> AnyStr - """ - Given a url, derive an appropriate name to use in a pipfile. + """Given a url, derive an appropriate name to use in a pipfile. :param str url: A url to derive a string from :returns: The name of the corresponding pipfile entry :rtype: Text """ - if not isinstance(url, six.string_types): + if not isinstance(url, str): raise TypeError("Expected a string, got {0!r}".format(url)) return urllib3_util.parse_url(url).host @@ -193,7 +190,7 @@ def get_url_name(url): def init_requirement(name): # type: (AnyStr) -> TRequirement - if not isinstance(name, six.string_types): + if not isinstance(name, str): raise TypeError("must supply a name to generate a requirement") from pkg_resources import Requirement @@ -207,13 +204,13 @@ def init_requirement(name): def extras_to_string(extras): # type: (Iterable[S]) -> S - """Turn a list of extras into a string + """Turn a list of extras into a string. :param List[str]] extras: a list of extras to format :return: A string of extras :rtype: str """ - if isinstance(extras, six.string_types): + if isinstance(extras, str): if extras.startswith("["): return extras else: @@ -225,7 +222,7 @@ def extras_to_string(extras): def parse_extras(extras_str): # type: (AnyStr) -> List[AnyStr] - """Turn a string of extras into a parsed extras list + """Turn a string of extras into a parsed extras list. :param str extras_str: An extras string :return: A sorted list of extras @@ -240,7 +237,7 @@ def parse_extras(extras_str): def specs_to_string(specs): # type: (List[Union[STRING_TYPE, Specifier]]) -> AnyStr - """Turn a list of specifier tuples into a string + """Turn a list of specifier tuples into a string. :param List[Union[Specifier, str]] specs: a list of specifiers to format :return: A string of specifiers @@ -248,7 +245,7 @@ def specs_to_string(specs): """ if specs: - if isinstance(specs, six.string_types): + if isinstance(specs, str): return specs try: extras = ",".join(["".join(spec) for spec in specs]) @@ -288,8 +285,7 @@ def build_vcs_uri( def _get_parsed_url(url): # type: (S) -> Url - """ - This is a stand-in function for `urllib3.util.parse_url` + """This is a stand-in function for `urllib3.util.parse_url` The orignal function doesn't handle special characters very well, this simply splits out the authentication section, creates the parsed url, then puts the authentication @@ -311,7 +307,7 @@ def _get_parsed_url(url): def convert_direct_url_to_url(direct_url): # type: (AnyStr) -> AnyStr - """Converts direct URLs to standard, link-style URLs + """Converts direct URLs to standard, link-style URLs. Given a direct url as defined by *PEP 508*, convert to a :class:`~pip_shims.shims.Link` compatible URL by moving the name and extras into an **egg_fragment**. @@ -352,8 +348,7 @@ def convert_direct_url_to_url(direct_url): def convert_url_to_direct_url(url, name=None): # type: (AnyStr, Optional[AnyStr]) -> AnyStr - """ - Converts normal link-style URLs to direct urls. + """Converts normal link-style URLs to direct urls. Given a :class:`~pip_shims.shims.Link` compatible URL, convert to a direct url as defined by *PEP 508* by extracting the name and extras from the **egg_fragment**. @@ -366,7 +361,7 @@ def convert_url_to_direct_url(url, name=None): :raises ValueError: Raised when the URL can't be parsed or a name can't be found. :raises TypeError: When a non-string input is provided. """ - if not isinstance(url, six.string_types): + if not isinstance(url, str): raise TypeError( "Expected a string to convert to a direct url, got {0!r}".format(url) ) @@ -410,15 +405,14 @@ def get_version(pipfile_entry): return "" return pipfile_entry.get("version", "").strip().lstrip("(").rstrip(")") - if isinstance(pipfile_entry, six.string_types): + if isinstance(pipfile_entry, str): return pipfile_entry.strip().lstrip("(").rstrip(")") return "" def strip_extras_markers_from_requirement(req): # type: (TRequirement) -> TRequirement - """ - Strips extras markers from requirement instances. + """Strips extras markers from requirement instances. Given a :class:`~packaging.requirements.Requirement` instance with markers defining *extra == 'name'*, strip out the extras from the markers and return the cleaned @@ -485,9 +479,8 @@ def get_default_pyproject_backend(): def get_pyproject(path): # type: (Union[STRING_TYPE, Path]) -> Optional[Tuple[List[STRING_TYPE], STRING_TYPE]] - """ - Given a base path, look for the corresponding ``pyproject.toml`` file and return its - build_requires and build_backend. + """Given a base path, look for the corresponding ``pyproject.toml`` file + and return its build_requires and build_backend. :param AnyStr path: The root path of the project, should be a directory (will be truncated) :return: A 2 tuple of build requirements and the build backend @@ -495,7 +488,6 @@ def get_pyproject(path): """ if not path: return - from vistir.compat import Path if not isinstance(path, Path): path = Path(path) @@ -510,7 +502,7 @@ def get_pyproject(path): backend = get_default_pyproject_backend() else: pyproject_data = {} - with io.open(pp_toml.as_posix(), encoding="utf-8") as fh: + with open(pp_toml.as_posix(), encoding="utf-8") as fh: pyproject_data = tomlkit.loads(fh.read()) build_system = pyproject_data.get("build-system", None) if build_system is None: @@ -530,7 +522,7 @@ def get_pyproject(path): def split_markers_from_line(line): # type: (AnyStr) -> Tuple[AnyStr, Optional[AnyStr]] - """Split markers from a dependency""" + """Split markers from a dependency.""" quote_chars = ["'", '"'] line_quote = next( iter(quote for quote in quote_chars if line.startswith(quote)), None @@ -562,15 +554,14 @@ def split_vcs_method_from_uri(uri): def split_ref_from_uri(uri): # type: (AnyStr) -> Tuple[AnyStr, Optional[AnyStr]] - """ - Given a path or URI, check for a ref and split it from the path if it is present, - returning a tuple of the original input and the ref or None. + """Given a path or URI, check for a ref and split it from the path if it is + present, returning a tuple of the original input and the ref or None. :param AnyStr uri: The path or URI to split :returns: A 2-tuple of the path or URI and the ref :rtype: Tuple[AnyStr, Optional[AnyStr]] """ - if not isinstance(uri, six.string_types): + if not isinstance(uri, str): raise TypeError("Expected a string, received {0!r}".format(uri)) parsed = _get_parsed_url(uri) path = parsed.path if parsed.path else "" @@ -738,8 +729,7 @@ def get_pinned_version(ireq): def is_pinned_requirement(ireq): - """ - Returns whether an InstallRequirement is a "pinned" requirement. + """Returns whether an InstallRequirement is a "pinned" requirement. An InstallRequirement is considered pinned if: @@ -763,9 +753,8 @@ def is_pinned_requirement(ireq): def as_tuple(ireq): - """ - Pulls out the (name: str, version:str, extras:(str)) tuple from the pinned InstallRequirement. - """ + """Pulls out the (name: str, version:str, extras:(str)) tuple from the + pinned InstallRequirement.""" if not is_pinned_requirement(ireq): raise TypeError("Expected a pinned InstallRequirement, got {}".format(ireq)) @@ -777,24 +766,19 @@ def as_tuple(ireq): def full_groupby(iterable, key=None): - """ - Like groupby(), but sorts the input on the group key first. - """ + """Like groupby(), but sorts the input on the group key first.""" return groupby(sorted(iterable, key=key), key=key) def flat_map(fn, collection): - """ - Map a function over a collection and flatten the result by one-level - """ + """Map a function over a collection and flatten the result by one-level.""" return chain.from_iterable(map(fn, collection)) def lookup_table(values, key=None, keyval=None, unique=False, use_lists=False): - """ - Builds a dict-based lookup table (index) elegantly. + """Builds a dict-based lookup table (index) elegantly. Supports building normal and unique lookup tables. For example: @@ -855,7 +839,7 @@ def lookup_table(values, key=None, keyval=None, unique=False, use_lists=False): def name_from_req(req): - """Get the name of the requirement""" + """Get the name of the requirement.""" if hasattr(req, "project_name"): # from pkg_resources, such as installed dists for pip-sync return req.project_name @@ -867,8 +851,7 @@ def name_from_req(req): def make_install_requirement( name, version=None, extras=None, markers=None, constraint=False ): - """ - Generates an :class:`~pip._internal.req.req_install.InstallRequirement`. + """Generates an :class:`~pip._internal.req.req_install.InstallRequirement`. Create an InstallRequirement from the supplied metadata. @@ -903,7 +886,8 @@ def make_install_requirement( def version_from_ireq(ireq): - """version_from_ireq Extract the version from a supplied :class:`~pip._internal.req.req_install.InstallRequirement` + """version_from_ireq Extract the version from a supplied + :class:`~pip._internal.req.req_install.InstallRequirement` :param ireq: An InstallRequirement :type ireq: :class:`~pip._internal.req.req_install.InstallRequirement` @@ -924,7 +908,8 @@ def _get_requires_python(candidate): def clean_requires_python(candidates): - """Get a cleaned list of all the candidates with valid specifiers in the `requires_python` attributes.""" + """Get a cleaned list of all the candidates with valid specifiers in the + `requires_python` attributes.""" all_candidates = [] sys_version = ".".join(map(str, sys.version_info[:3])) from packaging.version import parse as parse_version @@ -985,25 +970,24 @@ def normalize_name(pkg): :rtype: AnyStr """ - assert isinstance(pkg, six.string_types) + assert isinstance(pkg, str) return pkg.replace("_", "-").lower() def get_name_variants(pkg): # type: (STRING_TYPE) -> Set[STRING_TYPE] - """ - Given a packager name, get the variants of its name for both the canonicalized - and "safe" forms. + """Given a packager name, get the variants of its name for both the + canonicalized and "safe" forms. :param AnyStr pkg: The package to lookup :returns: A list of names. :rtype: Set """ - if not isinstance(pkg, six.string_types): + if not isinstance(pkg, str): raise TypeError("must provide a string to derive package names") - from pkg_resources import safe_name from packaging.utils import canonicalize_name + from pkg_resources import safe_name pkg = pkg.lower() names = {safe_name(pkg), canonicalize_name(pkg), pkg.replace("-", "_")} @@ -1012,29 +996,26 @@ def get_name_variants(pkg): def read_source(path, encoding="utf-8"): # type: (S, S) -> S - """ - Read a source file and get the contents with proper encoding for Python 2/3. + """Read a source file and get the contents with proper encoding for Python + 2/3. :param AnyStr path: the file path :param AnyStr encoding: the encoding that defaults to UTF-8 :returns: The contents of the source file :rtype: AnyStr """ - if six.PY3: - with open(path, "r", encoding=encoding) as fp: - return fp.read() - else: - with open(path, "r") as fp: - return fp.read() + with open(path, "r", encoding=encoding) as fp: + return fp.read() def expand_env_variables(line): # type: (AnyStr) -> AnyStr """Expand the env vars in a line following pip's standard. - https://pip.pypa.io/en/stable/reference/pip_install/#id10 + https://pip.pypa.io/en/stable/reference/pip_install/#id10. - Matches environment variable-style values in '${MY_VARIABLE_1}' with the - variable name consisting of only uppercase letters, digits or the '_' + Matches environment variable-style values in '${MY_VARIABLE_1}' with + the variable name consisting of only uppercase letters, digits or + the '_' """ def replace_with_env(match): diff --git a/pipenv/vendor/requirementslib/models/vcs.py b/pipenv/vendor/requirementslib/models/vcs.py index d4a2f160..18adb085 100644 --- a/pipenv/vendor/requirementslib/models/vcs.py +++ b/pipenv/vendor/requirementslib/models/vcs.py @@ -7,7 +7,6 @@ import sys import attr import pip_shims -import six from ..environment import MYPY_RUNNING from .url import URI @@ -124,13 +123,11 @@ class VCSRepository(object): # set the default to not write stdout, the first option sets this value new_defaults = [False] + list(run_command_defaults)[1:] new_defaults = tuple(new_defaults) - if six.PY3: - try: - pip_vcs.VersionControl.run_command.__defaults__ = new_defaults - except AttributeError: - pip_vcs.VersionControl.run_command.__func__.__defaults__ = new_defaults - else: + try: + pip_vcs.VersionControl.run_command.__defaults__ = new_defaults + except AttributeError: pip_vcs.VersionControl.run_command.__func__.__defaults__ = new_defaults + sys.modules[target_module] = pip_vcs cls.DEFAULT_RUN_ARGS = new_defaults return new_defaults diff --git a/pipenv/vendor/requirementslib/utils.py b/pipenv/vendor/requirementslib/utils.py index d76f82e9..712e8fdd 100644 --- a/pipenv/vendor/requirementslib/utils.py +++ b/pipenv/vendor/requirementslib/utils.py @@ -4,37 +4,20 @@ from __future__ import absolute_import, print_function import logging import os import sys +from collections.abc import ItemsView, Mapping, Sequence, Set +from pathlib import Path +from urllib.parse import urlparse, urlsplit, urlunparse import pip_shims.shims -import six -import six.moves import tomlkit import vistir -from six.moves.urllib.parse import urlparse, urlsplit, urlunparse -from vistir.compat import Path, fs_decode +from vistir.compat import fs_decode from vistir.path import ensure_mkdir_p, is_valid_url from .environment import MYPY_RUNNING -# fmt: off -six.add_move( # type: ignore - six.MovedAttribute("Mapping", "collections", "collections.abc") # type: ignore -) # noqa # isort:skip -six.add_move( # type: ignore - six.MovedAttribute("Sequence", "collections", "collections.abc") # type: ignore -) # noqa # isort:skip -six.add_move( # type: ignore - six.MovedAttribute("Set", "collections", "collections.abc") # type: ignore -) # noqa # isort:skip -six.add_move( # type: ignore - six.MovedAttribute("ItemsView", "collections", "collections.abc") # type: ignore -) # noqa -from six.moves import ItemsView, Mapping, Sequence, Set # type: ignore # noqa # isort:skip -# fmt: on - - if MYPY_RUNNING: - from typing import Dict, Any, Optional, Union, Tuple, List, Iterable, Text, TypeVar + from typing import Any, Dict, Iterable, List, Optional, Text, Tuple, TypeVar, Union STRING_TYPE = Union[bytes, str, Text] S = TypeVar("S", bytes, str, Text) @@ -104,8 +87,8 @@ def is_installable_dir(path): def strip_ssh_from_git_uri(uri): # type: (S) -> S - """Return git+ssh:// formatted URI to git+git@ format""" - if isinstance(uri, six.string_types): + """Return git+ssh:// formatted URI to git+git@ format.""" + if isinstance(uri, str): if "git+ssh://" in uri: parsed = urlparse(uri) # split the path on the first separating / so we can put the first segment @@ -121,8 +104,8 @@ def strip_ssh_from_git_uri(uri): def add_ssh_scheme_to_git_uri(uri): # type: (S) -> S - """Cleans VCS uris from pipenv.patched.notpip format""" - if isinstance(uri, six.string_types): + """Cleans VCS uris from pipenv.patched.notpip format.""" + if isinstance(uri, str): # Add scheme for parsing purposes, this is also what pip does if uri.startswith("git+") and "://" not in uri: uri = uri.replace("git+", "git+ssh://", 1) @@ -140,7 +123,7 @@ def is_vcs(pipfile_entry): if isinstance(pipfile_entry, Mapping): return any(key for key in pipfile_entry.keys() if key in VCS_LIST) - elif isinstance(pipfile_entry, six.string_types): + elif isinstance(pipfile_entry, str): if not is_valid_url(pipfile_entry) and pipfile_entry.startswith("git+"): pipfile_entry = add_ssh_scheme_to_git_uri(pipfile_entry) @@ -153,21 +136,21 @@ def is_editable(pipfile_entry): # type: (PipfileType) -> bool if isinstance(pipfile_entry, Mapping): return pipfile_entry.get("editable", False) is True - if isinstance(pipfile_entry, six.string_types): + if isinstance(pipfile_entry, str): return pipfile_entry.startswith("-e ") return False def is_star(val): # type: (PipfileType) -> bool - return (isinstance(val, six.string_types) and val == "*") or ( + return (isinstance(val, str) and val == "*") or ( isinstance(val, Mapping) and val.get("version", "") == "*" ) def convert_entry_to_path(path): # type: (Dict[S, Union[S, bool, Tuple[S], List[S]]]) -> S - """Convert a pipfile entry to a string""" + """Convert a pipfile entry to a string.""" if not isinstance(path, Mapping): raise TypeError("expecting a mapping, received {0!r}".format(path)) @@ -187,7 +170,7 @@ def convert_entry_to_path(path): def is_installable_file(path): # type: (PipfileType) -> bool - """Determine if a path can potentially be installed""" + """Determine if a path can potentially be installed.""" from packaging import specifiers if isinstance(path, Mapping): @@ -211,7 +194,7 @@ def is_installable_file(path): or (len(parsed.scheme) == 1 and os.name == "nt") ) if parsed.scheme and parsed.scheme == "file": - path = vistir.compat.fs_decode(vistir.path.url_to_path(path)) + path = fs_decode(vistir.path.url_to_path(path)) normalized_path = vistir.path.normalize_path(path) if is_local and not os.path.exists(normalized_path): return False @@ -230,9 +213,10 @@ def is_installable_file(path): def get_dist_metadata(dist): - import pkg_resources from email.parser import FeedParser + import pkg_resources + if isinstance(dist, pkg_resources.DistInfoDistribution) and dist.has_metadata( "METADATA" ): @@ -343,10 +327,8 @@ _REMAP_EXIT = object() class PathAccessError(KeyError, IndexError, TypeError): - """An amalgamation of KeyError, IndexError, and TypeError, - representing what can occur when looking up a path in a nested - object. - """ + """An amalgamation of KeyError, IndexError, and TypeError, representing + what can occur when looking up a path in a nested object.""" def __init__(self, exc, seg, path): self.exc = exc @@ -368,6 +350,7 @@ class PathAccessError(KeyError, IndexError, TypeError): def get_path(root, path, default=_UNSET): """Retrieve a value from a nested object via a tuple representing the lookup path. + >>> root = {'a': {'b': {'c': [[1], [2], [3]]}}} >>> get_path(root, ('a', 'b', 'c', 2, 0)) 3 @@ -391,7 +374,7 @@ def get_path(root, path, default=_UNSET): default: The value to be returned should any ``PathAccessError`` exceptions be raised. """ - if isinstance(path, six.string_types): + if isinstance(path, str): path = path.split(".") cur = root try: @@ -426,8 +409,12 @@ _orig_default_visit = default_visit # Modified from https://github.com/mahmoud/boltons/blob/master/boltons/iterutils.py def dict_path_enter(path, key, value): - if isinstance(value, six.string_types): + if isinstance(value, str): return value, False + elif isinstance(value, (tomlkit.items.Table, tomlkit.items.InlineTable)): + return value.__class__( + tomlkit.container.Container(), value.trivia, False + ), ItemsView(value) elif isinstance(value, (Mapping, dict)): return value.__class__(), ItemsView(value) elif isinstance(value, tomlkit.items.Array): @@ -479,16 +466,16 @@ def dict_path_exit(path, key, old_parent, new_parent, new_items): def remap( root, visit=default_visit, enter=dict_path_enter, exit=dict_path_exit, **kwargs ): - """The remap ("recursive map") function is used to traverse and - transform nested structures. Lists, tuples, sets, and dictionaries - are just a few of the data structures nested into heterogenous - tree-like structures that are so common in programming. - Unfortunately, Python's built-in ways to manipulate collections - are almost all flat. List comprehensions may be fast and succinct, - but they do not recurse, making it tedious to apply quick changes - or complex transforms to real-world data. - remap goes where list comprehensions cannot. - Here's an example of removing all Nones from some data: + """The remap ("recursive map") function is used to traverse and transform + nested structures. Lists, tuples, sets, and dictionaries are just a few of + the data structures nested into heterogenous tree-like structures that are + so common in programming. Unfortunately, Python's built-in ways to + manipulate collections are almost all flat. List comprehensions may be fast + and succinct, but they do not recurse, making it tedious to apply quick + changes or complex transforms to real-world data. remap goes where list + comprehensions cannot. Here's an example of removing all Nones from some + data: + >>> from pprint import pprint >>> reviews = {'Star Trek': {'TNG': 10, 'DS9': 8.5, 'ENT': None}, ... 'Babylon 5': 6, 'Dr. Who': None} @@ -644,7 +631,7 @@ def merge_items(target_list, sourced=False): try: cur_val = get_path(ret, path + (key,)) - except KeyError as ke: + except KeyError: pass else: new_parent = cur_val diff --git a/pipenv/vendor/vendor.txt b/pipenv/vendor/vendor.txt index 1daf0a4f..9f34075f 100644 --- a/pipenv/vendor/vendor.txt +++ b/pipenv/vendor/vendor.txt @@ -26,7 +26,7 @@ packaging==21.0 parse==1.19.0 pep517==0.11.0 pexpect==4.8.0 -pip-shims==0.5.3 +pip-shims==0.6.0 pipdeptree==2.0.0 pipreqs==0.4.10 plette[validation]==0.2.3 @@ -36,7 +36,7 @@ python-dateutil==2.8.2 python-dotenv==0.19.0 pythonfinder==1.2.8 requests==2.26.0 -requirementslib==1.5.16 +requirementslib==1.6.1 shellingham==1.4.0 six==1.16.0 termcolor==1.1.0 diff --git a/tasks/vendoring/patches/vendor/pip_shims_module_names.patch b/tasks/vendoring/patches/vendor/pip_shims_module_names.patch deleted file mode 100644 index 7016dd82..00000000 --- a/tasks/vendoring/patches/vendor/pip_shims_module_names.patch +++ /dev/null @@ -1,42 +0,0 @@ -diff --git a/pipenv/vendor/pip_shims/__init__.py b/pipenv/vendor/pip_shims/__init__.py -index 2af4166e..598b9ad8 100644 ---- a/pipenv/vendor/pip_shims/__init__.py -+++ b/pipenv/vendor/pip_shims/__init__.py -@@ -11,10 +11,13 @@ __version__ = "0.5.3" - if "pip_shims" in sys.modules: - # mainly to keep a reference to the old module on hand so it doesn't get - # weakref'd away -- old_module = sys.modules["pip_shims"] -+ if __name__ != "pip_shims": -+ del sys.modules["pip_shims"] -+if __name__ in sys.modules: -+ old_module = sys.modules[__name__] - - --module = sys.modules["pip_shims"] = shims._new() -+module = sys.modules[__name__] = sys.modules["pip_shims"] = shims._new() - module.shims = shims - module.__dict__.update( - { -diff --git a/pipenv/vendor/pip_shims/compat.py b/pipenv/vendor/pip_shims/compat.py -index ed99d970..63061a6a 100644 ---- a/pipenv/vendor/pip_shims/compat.py -+++ b/pipenv/vendor/pip_shims/compat.py -@@ -25,14 +25,14 @@ from .utils import ( - ) - - if sys.version_info[:2] < (3, 5): -- from backports.tempfile import TemporaryDirectory -+ from pipenv.vendor.vistir.compat import TemporaryDirectory - else: - from tempfile import TemporaryDirectory - - if six.PY3: - from contextlib import ExitStack - else: -- from contextlib2 import ExitStack -+ from pipenv.vendor.contextlib2 import ExitStack - - - if MYPY_RUNNING: -