From 9703b797b410a70acb3c504d03bf278e2dcd01f9 Mon Sep 17 00:00:00 2001 From: nagaripratap <119724473+nagaripratap@users.noreply.github.com> Date: Tue, 29 Aug 2023 21:00:32 +0800 Subject: [PATCH 01/12] [fix] Update cacert.pem Removed vulnerable e-tugra certificates --- pipenv/patched/pip/_vendor/certifi/cacert.pem | 109 ------------------ 1 file changed, 109 deletions(-) diff --git a/pipenv/patched/pip/_vendor/certifi/cacert.pem b/pipenv/patched/pip/_vendor/certifi/cacert.pem index 5183934b..7fd6b96a 100644 --- a/pipenv/patched/pip/_vendor/certifi/cacert.pem +++ b/pipenv/patched/pip/_vendor/certifi/cacert.pem @@ -1676,49 +1676,6 @@ HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= -----END CERTIFICATE----- -# Issuer: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi -# Subject: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi -# Label: "E-Tugra Certification Authority" -# Serial: 7667447206703254355 -# MD5 Fingerprint: b8:a1:03:63:b0:bd:21:71:70:8a:6f:13:3a:bb:79:49 -# SHA1 Fingerprint: 51:c6:e7:08:49:06:6e:f3:92:d4:5c:a0:0d:6d:a3:62:8f:c3:52:39 -# SHA256 Fingerprint: b0:bf:d5:2b:b0:d7:d9:bd:92:bf:5d:4d:c1:3d:a2:55:c0:2c:54:2f:37:83:65:ea:89:39:11:f5:5e:55:f2:3c ------BEGIN CERTIFICATE----- -MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV -BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC -aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV -BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 -Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz -MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ -BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp -em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN -ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY -B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH -D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF -Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo -q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D -k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH -fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut -dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM -ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 -zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn -rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX -U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 -Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 -XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF -Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR -HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY -GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c -77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 -+GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK -vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 -FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl -yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P -AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD -y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d -NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== ------END CERTIFICATE----- # Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center # Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center @@ -4397,72 +4354,6 @@ ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR -----END CERTIFICATE----- -# Issuer: CN=E-Tugra Global Root CA RSA v3 O=E-Tugra EBG A.S. OU=E-Tugra Trust Center -# Subject: CN=E-Tugra Global Root CA RSA v3 O=E-Tugra EBG A.S. OU=E-Tugra Trust Center -# Label: "E-Tugra Global Root CA RSA v3" -# Serial: 75951268308633135324246244059508261641472512052 -# MD5 Fingerprint: 22:be:10:f6:c2:f8:03:88:73:5f:33:29:47:28:47:a4 -# SHA1 Fingerprint: e9:a8:5d:22:14:52:1c:5b:aa:0a:b4:be:24:6a:23:8a:c9:ba:e2:a9 -# SHA256 Fingerprint: ef:66:b0:b1:0a:3c:db:9f:2e:36:48:c7:6b:d2:af:18:ea:d2:bf:e6:f1:17:65:5e:28:c4:06:0d:a1:a3:f4:c2 ------BEGIN CERTIFICATE----- -MIIF8zCCA9ugAwIBAgIUDU3FzRYilZYIfrgLfxUGNPt5EDQwDQYJKoZIhvcNAQEL -BQAwgYAxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHEwZBbmthcmExGTAXBgNVBAoTEEUt -VHVncmEgRUJHIEEuUy4xHTAbBgNVBAsTFEUtVHVncmEgVHJ1c3QgQ2VudGVyMSYw -JAYDVQQDEx1FLVR1Z3JhIEdsb2JhbCBSb290IENBIFJTQSB2MzAeFw0yMDAzMTgw -OTA3MTdaFw00NTAzMTIwOTA3MTdaMIGAMQswCQYDVQQGEwJUUjEPMA0GA1UEBxMG -QW5rYXJhMRkwFwYDVQQKExBFLVR1Z3JhIEVCRyBBLlMuMR0wGwYDVQQLExRFLVR1 -Z3JhIFRydXN0IENlbnRlcjEmMCQGA1UEAxMdRS1UdWdyYSBHbG9iYWwgUm9vdCBD -QSBSU0EgdjMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCiZvCJt3J7 -7gnJY9LTQ91ew6aEOErxjYG7FL1H6EAX8z3DeEVypi6Q3po61CBxyryfHUuXCscx -uj7X/iWpKo429NEvx7epXTPcMHD4QGxLsqYxYdE0PD0xesevxKenhOGXpOhL9hd8 -7jwH7eKKV9y2+/hDJVDqJ4GohryPUkqWOmAalrv9c/SF/YP9f4RtNGx/ardLAQO/ -rWm31zLZ9Vdq6YaCPqVmMbMWPcLzJmAy01IesGykNz709a/r4d+ABs8qQedmCeFL -l+d3vSFtKbZnwy1+7dZ5ZdHPOrbRsV5WYVB6Ws5OUDGAA5hH5+QYfERaxqSzO8bG -wzrwbMOLyKSRBfP12baqBqG3q+Sx6iEUXIOk/P+2UNOMEiaZdnDpwA+mdPy70Bt4 -znKS4iicvObpCdg604nmvi533wEKb5b25Y08TVJ2Glbhc34XrD2tbKNSEhhw5oBO -M/J+JjKsBY04pOZ2PJ8QaQ5tndLBeSBrW88zjdGUdjXnXVXHt6woq0bM5zshtQoK -5EpZ3IE1S0SVEgpnpaH/WwAH0sDM+T/8nzPyAPiMbIedBi3x7+PmBvrFZhNb/FAH -nnGGstpvdDDPk1Po3CLW3iAfYY2jLqN4MpBs3KwytQXk9TwzDdbgh3cXTJ2w2Amo -DVf3RIXwyAS+XF1a4xeOVGNpf0l0ZAWMowIDAQABo2MwYTAPBgNVHRMBAf8EBTAD -AQH/MB8GA1UdIwQYMBaAFLK0ruYt9ybVqnUtdkvAG1Mh0EjvMB0GA1UdDgQWBBSy -tK7mLfcm1ap1LXZLwBtTIdBI7zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEL -BQADggIBAImocn+M684uGMQQgC0QDP/7FM0E4BQ8Tpr7nym/Ip5XuYJzEmMmtcyQ -6dIqKe6cLcwsmb5FJ+Sxce3kOJUxQfJ9emN438o2Fi+CiJ+8EUdPdk3ILY7r3y18 -Tjvarvbj2l0Upq7ohUSdBm6O++96SmotKygY/r+QLHUWnw/qln0F7psTpURs+APQ -3SPh/QMSEgj0GDSz4DcLdxEBSL9htLX4GdnLTeqjjO/98Aa1bZL0SmFQhO3sSdPk -vmjmLuMxC1QLGpLWgti2omU8ZgT5Vdps+9u1FGZNlIM7zR6mK7L+d0CGq+ffCsn9 -9t2HVhjYsCxVYJb6CH5SkPVLpi6HfMsg2wY+oF0Dd32iPBMbKaITVaA9FCKvb7jQ -mhty3QUBjYZgv6Rn7rWlDdF/5horYmbDB7rnoEgcOMPpRfunf/ztAmgayncSd6YA -VSgU7NbHEqIbZULpkejLPoeJVF3Zr52XnGnnCv8PWniLYypMfUeUP95L6VPQMPHF -9p5J3zugkaOj/s1YzOrfr28oO6Bpm4/srK4rVJ2bBLFHIK+WEj5jlB0E5y67hscM -moi/dkfv97ALl2bSRM9gUgfh1SxKOidhd8rXj+eHDjD/DLsE4mHDosiXYY60MGo8 -bcIHX0pzLz/5FooBZu+6kcpSV3uu1OYP3Qt6f4ueJiDPO++BcYNZ ------END CERTIFICATE----- - -# Issuer: CN=E-Tugra Global Root CA ECC v3 O=E-Tugra EBG A.S. OU=E-Tugra Trust Center -# Subject: CN=E-Tugra Global Root CA ECC v3 O=E-Tugra EBG A.S. OU=E-Tugra Trust Center -# Label: "E-Tugra Global Root CA ECC v3" -# Serial: 218504919822255052842371958738296604628416471745 -# MD5 Fingerprint: 46:bc:81:bb:f1:b5:1e:f7:4b:96:bc:14:e2:e7:27:64 -# SHA1 Fingerprint: 8a:2f:af:57:53:b1:b0:e6:a1:04:ec:5b:6a:69:71:6d:f6:1c:e2:84 -# SHA256 Fingerprint: 87:3f:46:85:fa:7f:56:36:25:25:2e:6d:36:bc:d7:f1:6f:c2:49:51:f2:64:e4:7e:1b:95:4f:49:08:cd:ca:13 ------BEGIN CERTIFICATE----- -MIICpTCCAiqgAwIBAgIUJkYZdzHhT28oNt45UYbm1JeIIsEwCgYIKoZIzj0EAwMw -gYAxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHEwZBbmthcmExGTAXBgNVBAoTEEUtVHVn -cmEgRUJHIEEuUy4xHTAbBgNVBAsTFEUtVHVncmEgVHJ1c3QgQ2VudGVyMSYwJAYD -VQQDEx1FLVR1Z3JhIEdsb2JhbCBSb290IENBIEVDQyB2MzAeFw0yMDAzMTgwOTQ2 -NThaFw00NTAzMTIwOTQ2NThaMIGAMQswCQYDVQQGEwJUUjEPMA0GA1UEBxMGQW5r -YXJhMRkwFwYDVQQKExBFLVR1Z3JhIEVCRyBBLlMuMR0wGwYDVQQLExRFLVR1Z3Jh -IFRydXN0IENlbnRlcjEmMCQGA1UEAxMdRS1UdWdyYSBHbG9iYWwgUm9vdCBDQSBF -Q0MgdjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASOmCm/xxAeJ9urA8woLNheSBkQ -KczLWYHMjLiSF4mDKpL2w6QdTGLVn9agRtwcvHbB40fQWxPa56WzZkjnIZpKT4YK -fWzqTTKACrJ6CZtpS5iB4i7sAnCWH/31Rs7K3IKjYzBhMA8GA1UdEwEB/wQFMAMB -Af8wHwYDVR0jBBgwFoAU/4Ixcj75xGZsrTie0bBRiKWQzPUwHQYDVR0OBBYEFP+C -MXI++cRmbK04ntGwUYilkMz1MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNp -ADBmAjEA5gVYaWHlLcoNy/EZCL3W/VGSGn5jVASQkZo1kTmZ+gepZpO6yGjUij/6 -7W4WAie3AjEA3VoXK3YdZUKWpqxdinlW2Iob35reX8dQj7FbcQwm32pAAOwzkSFx -vmjkI6TZraE3 ------END CERTIFICATE----- # Issuer: CN=Security Communication RootCA3 O=SECOM Trust Systems CO.,LTD. # Subject: CN=Security Communication RootCA3 O=SECOM Trust Systems CO.,LTD. From 22223f0084a0bc1602525ac4cbe6cb675c82d537 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sun, 27 Aug 2023 03:23:59 +0200 Subject: [PATCH 02/12] ruff rules SIM --- .pre-commit-config.yaml | 2 +- pipenv/environment.py | 8 ++-- pipenv/environments.py | 6 +-- pipenv/project.py | 15 ++++--- pipenv/resolver.py | 10 ++--- pipenv/routines/graph.py | 2 +- pipenv/routines/install.py | 13 +++--- pipenv/routines/lock.py | 6 +-- pipenv/utils/environment.py | 23 ++++++----- pipenv/utils/fileutils.py | 7 +--- pipenv/utils/funktools.py | 13 +++--- pipenv/utils/locking.py | 17 +++----- pipenv/utils/markers.py | 9 ++--- pipenv/utils/pip.py | 2 +- pipenv/utils/pipfile.py | 23 +++++------ pipenv/utils/requirementslib.py | 23 +++++------ pipenv/utils/resolver.py | 2 +- pipenv/utils/shell.py | 8 +--- pipenv/utils/toml.py | 7 ++-- pipenv/utils/virtualenv.py | 21 +++++----- tasks/vendoring/__init__.py | 18 ++++----- tests/integration/conftest.py | 20 +++++----- tests/integration/test_dot_venv.py | 48 +++++++++++------------ tests/integration/test_install_basic.py | 29 +++++++------- tests/integration/test_install_markers.py | 39 +++++++++--------- tests/integration/test_lock.py | 15 ++++--- tests/integration/test_pipenv.py | 15 ++++--- tests/integration/test_project.py | 17 ++++---- tests/integration/test_uninstall.py | 8 ++-- 29 files changed, 193 insertions(+), 233 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 371959e2..bc3e47f6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: exclude: .patch - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.285 + rev: v0.0.286 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/pipenv/environment.py b/pipenv/environment.py index 4187ba13..26b42e66 100644 --- a/pipenv/environment.py +++ b/pipenv/environment.py @@ -525,7 +525,7 @@ class Environment: if not loc.exists(): continue for pth in loc.iterdir(): - if not pth.suffix == ".egg-link": + if pth.suffix != ".egg-link": continue contents = [ normalize_path(line.strip()) for line in pth.read_text().splitlines() @@ -688,10 +688,10 @@ class Environment: tree = PackageDAG.from_pkgs(packages).sort() branch_keys = {r.key for r in flatten(tree.values())} - if pkg is not None: - nodes = [p for p in tree.keys() if p.key == pkg] + if pkg is None: + nodes = [p for p in tree if p.key not in branch_keys] else: - nodes = [p for p in tree.keys() if p.key not in branch_keys] + nodes = [p for p in tree if p.key == pkg] key_tree = {k.key: v for k, v in tree.items()} return [self._get_requirements_for_package(p, key_tree) for p in nodes] diff --git a/pipenv/environments.py b/pipenv/environments.py index fea1fd7f..03af5314 100644 --- a/pipenv/environments.py +++ b/pipenv/environments.py @@ -222,7 +222,7 @@ class Setting: _spinners.SPINNERS[None] = {"interval": 80, "frames": " "} self.PIPENV_SPINNER = None else: - pipenv_spinner = "dots" if not os.name == "nt" else "bouncingBar" + pipenv_spinner = "bouncingBar" if os.name == "nt" else "dots" self.PIPENV_SPINNER = get_from_env( "SPINNER", check_for_negation=False, default=pipenv_spinner ) @@ -397,10 +397,10 @@ class Setting: del self.PIPENV_VERBOSE def is_verbose(self, threshold=1): - return self.PIPENV_VERBOSITY >= threshold + return threshold <= self.PIPENV_VERBOSITY def is_quiet(self, threshold=-1): - return self.PIPENV_VERBOSITY <= threshold + return threshold >= self.PIPENV_VERBOSITY def is_using_venv() -> bool: diff --git a/pipenv/project.py b/pipenv/project.py index deabaa3c..ca173fbc 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -21,6 +21,8 @@ try: except ImportError: from pipenv.vendor import tomli as toml +import contextlib + from pipenv.cmdparse import Script from pipenv.environment import Environment from pipenv.environments import Setting, is_in_virtualenv, normalize_pipfile_path @@ -208,10 +210,8 @@ class Project: # Hack to skip this during pipenv run, or -r. if ("run" not in sys.argv) and chdir: - try: + with contextlib.suppress(TypeError, AttributeError): os.chdir(self.project_directory) - except (TypeError, AttributeError): - pass def path_to(self, p: str) -> str: """Returns the absolute path to a given relative path.""" @@ -1079,7 +1079,7 @@ class Project: if section is None: section = {} package_name = pep423_name(package_name) - for name in section.keys(): + for name in section: if pep423_name(name) == package_name: return name return None @@ -1218,10 +1218,9 @@ class Project: try: source = self.get_source(url=index) except SourceNotFound: - try: + with contextlib.suppress(SourceNotFound): source = self.get_source(name=index) - except SourceNotFound: - pass + if source is not None: return source["name"] source = {"url": index, "verify_ssl": verify_ssl} @@ -1312,7 +1311,7 @@ class Project: """ # Casing for section. changed_values = False - unknown_names = [k for k in section.keys() if k not in set(self.proper_names)] + unknown_names = [k for k in section if k not in set(self.proper_names)] # Replace each package with proper casing. for dep in unknown_names: try: diff --git a/pipenv/resolver.py b/pipenv/resolver.py index 7a499a46..f89a10c1 100644 --- a/pipenv/resolver.py +++ b/pipenv/resolver.py @@ -286,7 +286,7 @@ class Entry: @property def is_in_pipfile(self): - return True if self.pipfile_name else False + return bool(self.pipfile_name) @property def pipfile_packages(self): @@ -315,7 +315,7 @@ class Entry: def clean_specifier(specifier): from pipenv.patched.pip._vendor.packaging.specifiers import Specifier - if not any(specifier.startswith(k) for k in Specifier._operators.keys()): + if not any(specifier.startswith(k) for k in Specifier._operators): if specifier.strip().lower() in ["any", "", "*"]: return "*" specifier = f"=={specifier}" @@ -327,14 +327,12 @@ class Entry: def strip_version(specifier): from pipenv.patched.pip._vendor.packaging.specifiers import Specifier - op = next( - iter(k for k in Specifier._operators.keys() if specifier.startswith(k)), None - ) + op = next(iter(k for k in Specifier._operators if specifier.startswith(k)), None) if op: specifier = specifier[len(op) :] while op: op = next( - iter(k for k in Specifier._operators.keys() if specifier.startswith(k)), + iter(k for k in Specifier._operators if specifier.startswith(k)), None, ) if op: diff --git a/pipenv/routines/graph.py b/pipenv/routines/graph.py index 0a437303..63f63900 100644 --- a/pipenv/routines/graph.py +++ b/pipenv/routines/graph.py @@ -30,7 +30,7 @@ def do_graph(project, bare=False, json=False, json_tree=False, reverse=False): except RuntimeError: pass else: - if not os.name == "nt": # bugfix #4388 + if os.name != "nt": # bugfix #4388 python_path = Path(python_path).as_posix() pipdeptree_path = Path(pipdeptree_path).as_posix() diff --git a/pipenv/routines/install.py b/pipenv/routines/install.py index 4be447dd..1bb0692f 100644 --- a/pipenv/routines/install.py +++ b/pipenv/routines/install.py @@ -604,13 +604,12 @@ def do_init( if categories is None: categories = [] - if not system and not project.s.PIPENV_USE_SYSTEM: - if not project.virtualenv_exists: - try: - do_create_virtualenv(project, python=python, pypi_mirror=pypi_mirror) - except KeyboardInterrupt: - cleanup_virtualenv(project, bare=False) - sys.exit(1) + if not system and not project.s.PIPENV_USE_SYSTEM and not project.virtualenv_exists: + try: + do_create_virtualenv(project, python=python, pypi_mirror=pypi_mirror) + except KeyboardInterrupt: + cleanup_virtualenv(project, bare=False) + sys.exit(1) # Ensure the Pipfile exists. if not deploy: ensure_pipfile(project, system=system) diff --git a/pipenv/routines/lock.py b/pipenv/routines/lock.py index 32a86950..0a79cfc5 100644 --- a/pipenv/routines/lock.py +++ b/pipenv/routines/lock.py @@ -1,3 +1,5 @@ +import contextlib + from pipenv.utils.dependencies import ( get_pipfile_category_using_lockfile_section, ) @@ -54,10 +56,8 @@ def do_lock( ) # Prune old lockfile category as new one will be created. - try: + with contextlib.suppress(KeyError): old_lock_data = lockfile.pop(category) - except KeyError: - pass from pipenv.utils.resolver import venv_resolve_deps diff --git a/pipenv/utils/environment.py b/pipenv/utils/environment.py index 2e066eef..89bba8ea 100644 --- a/pipenv/utils/environment.py +++ b/pipenv/utils/environment.py @@ -41,15 +41,14 @@ def load_dot_env(project, as_dict=False, quiet=False): def ensure_environment(): # Skip this on Windows... - if os.name != "nt": - if "LANG" not in os.environ: - click.echo( - "{}: the environment variable {} is not set!" - "\nWe recommend setting this in {} (or equivalent) for " - "proper expected behavior.".format( - click.style("Warning", fg="red", bold=True), - click.style("LANG", bold=True), - click.style("~/.profile", fg="green"), - ), - err=True, - ) + if os.name != "nt" and "LANG" not in os.environ: + click.echo( + "{}: the environment variable {} is not set!" + "\nWe recommend setting this in {} (or equivalent) for " + "proper expected behavior.".format( + click.style("Warning", fg="red", bold=True), + click.style("LANG", bold=True), + click.style("~/.profile", fg="green"), + ), + err=True, + ) diff --git a/pipenv/utils/fileutils.py b/pipenv/utils/fileutils.py index b0c69762..f6fe5d2c 100644 --- a/pipenv/utils/fileutils.py +++ b/pipenv/utils/fileutils.py @@ -212,12 +212,9 @@ def create_tracked_tempdir(*args: Any, **kwargs: Any) -> str: def check_for_unc_path(path): # type: (Path) -> bool """Checks to see if a pathlib `Path` object is a unc path or not.""" - if ( + return bool( os.name == "nt" and len(path.drive) > 2 and not path.drive[0].isalpha() and path.drive[1] != ":" - ): - return True - else: - return False + ) diff --git a/pipenv/utils/funktools.py b/pipenv/utils/funktools.py index 9a056d66..5f33b1e2 100644 --- a/pipenv/utils/funktools.py +++ b/pipenv/utils/funktools.py @@ -348,13 +348,12 @@ def handle_remove_readonly(func, path, exc): try: func(path) except (OSError, FileNotFoundError, PermissionError) as e: # noqa:B014 - if e.errno in PERM_ERRORS: - if e.errno != errno.ENOENT: # File still exists - warnings.warn( - default_warning_message.format(path), - ResourceWarning, - stacklevel=2, - ) + if e.errno in PERM_ERRORS and e.errno != errno.ENOENT: # File still exists + warnings.warn( + default_warning_message.format(path), + ResourceWarning, + stacklevel=2, + ) return else: raise exc_exception diff --git a/pipenv/utils/locking.py b/pipenv/utils/locking.py index c0af54c0..c9552a57 100644 --- a/pipenv/utils/locking.py +++ b/pipenv/utils/locking.py @@ -2,7 +2,7 @@ import copy import itertools import os import stat -from contextlib import contextmanager +from contextlib import contextmanager, suppress from json import JSONDecodeError from pathlib import Path from tempfile import NamedTemporaryFile @@ -61,10 +61,7 @@ def format_requirement_for_lockfile( if req.link and req.link.is_vcs: vcs = req.link.scheme.split("+", 1)[0] entry["ref"] = determine_vcs_revision_hash(req, vcs, pipfile_entry.get("ref")) - if name in original_deps: - entry[vcs] = original_deps[name] - else: - entry[vcs] = req.link.url + entry[vcs] = original_deps.get(name, req.link.url) if pipfile_entry.get("subdirectory"): entry["subdirectory"] = pipfile_entry["subdirectory"] if req.req: @@ -218,18 +215,16 @@ def atomic_open_for_write(target, binary=False, newline=None, encoding=None) -> delete=False, ) # set permissions to 0644 - try: + with suppress(OSError): os.chmod(f.name, stat.S_IWUSR | stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) - except OSError: - pass + try: yield f except BaseException: f.close() - try: + with suppress(OSError): os.remove(f.name) - except OSError: - pass + raise else: f.close() diff --git a/pipenv/utils/markers.py b/pipenv/utils/markers.py index d1e177b9..dcb3384a 100644 --- a/pipenv/utils/markers.py +++ b/pipenv/utils/markers.py @@ -48,7 +48,7 @@ class PipenvMarkers(BaseModel): @classmethod def from_pipfile(cls, name, pipfile): attr_fields = list(cls.__fields__) - found_keys = [k for k in pipfile.keys() if k in attr_fields] + found_keys = [k for k in pipfile if k in attr_fields] marker_strings = [f"{k} {pipfile[k]}" for k in found_keys] if pipfile.get("markers"): marker_strings.append(pipfile.get("markers")) @@ -399,9 +399,8 @@ def _markers_contains_key(markers, key): for element in reversed(markers): if isinstance(element, tuple) and element[0].value == key: return True - elif isinstance(element, list): - if _markers_contains_key(element, key): - return True + elif isinstance(element, list) and _markers_contains_key(element, key): + return True return False @@ -628,7 +627,7 @@ def normalize_marker_str(marker) -> str: def marker_from_specifier(spec) -> Marker: - if not any(spec.startswith(k) for k in Specifier._operators.keys()): + if not any(spec.startswith(k) for k in Specifier._operators): if spec.strip().lower() in ["any", "", "*"]: return None spec = f"=={spec}" diff --git a/pipenv/utils/pip.py b/pipenv/utils/pip.py index feb02ee7..040d0170 100644 --- a/pipenv/utils/pip.py +++ b/pipenv/utils/pip.py @@ -136,7 +136,7 @@ def get_pip_args( "src_dir": src_dir, } arg_set = ["--no-input"] if project.settings.get("disable_pip_input", True) else [] - for key in arg_map.keys(): + for key in arg_map: if key in locals() and locals().get(key): arg_set.extend(arg_map.get(key)) arg_set += extra_pip_args or [] diff --git a/pipenv/utils/pipfile.py b/pipenv/utils/pipfile.py index e9b0786e..5ead79c7 100644 --- a/pipenv/utils/pipfile.py +++ b/pipenv/utils/pipfile.py @@ -1,3 +1,4 @@ +import contextlib import io import itertools import os @@ -55,11 +56,10 @@ def find_pipfile(max_depth=3): for c, _, _ in walk_up(os.getcwd()): i += 1 - if i < max_depth: - if "Pipfile": - p = os.path.join(c, "Pipfile") - if os.path.isfile(p): - return p + if i < max_depth and "Pipfile": + p = os.path.join(c, "Pipfile") + if os.path.isfile(p): + return p raise RuntimeError("No Pipfile found!") @@ -190,10 +190,8 @@ class PipfileLoader(pipfiles.Pipfile): for key, klass in pipfiles.PIPFILE_SECTIONS.items(): if key not in data or key == "sources": continue - try: + with contextlib.suppress(Exception): klass.validate(data[key]) - except Exception: - pass @classmethod def ensure_package_sections(cls, data): @@ -207,9 +205,7 @@ class PipfileLoader(pipfiles.Pipfile): sections are present :rtype: :class:`~tomlkit.toml_document.TOMLDocument` """ - package_keys = ( - k for k in pipfiles.PIPFILE_SECTIONS.keys() if k.endswith("packages") - ) + package_keys = (k for k in pipfiles.PIPFILE_SECTIONS if k.endswith("packages")) for key in package_keys: if key not in data: data.update({key: tomlkit.table()}) @@ -401,9 +397,8 @@ class Pipfile(BaseModel): project_path = pipfile_path.parent if not project_path.exists(): raise FileNotFoundError("%s is not a valid project path!" % path) - elif not pipfile_path.exists() or not pipfile_path.is_file(): - if not create: - raise RequirementError("%s is not a valid Pipfile" % pipfile_path) + elif (not pipfile_path.exists() or not pipfile_path.is_file()) and not create: + raise RequirementError("%s is not a valid Pipfile" % pipfile_path) return cls.read_projectfile(pipfile_path.as_posix()) @classmethod diff --git a/pipenv/utils/requirementslib.py b/pipenv/utils/requirementslib.py index 5bb46e78..ef78f4b5 100644 --- a/pipenv/utils/requirementslib.py +++ b/pipenv/utils/requirementslib.py @@ -63,15 +63,14 @@ VCS_SCHEMES = [ def strip_ssh_from_git_uri(uri): # type: (S) -> S """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 - # into the 'netloc' section with a : separator - path_part, _, path = parsed.path.lstrip("/").partition("/") - path = f"/{path}" - parsed = parsed._replace(netloc=f"{parsed.netloc}:{path_part}", path=path) - uri = urlunparse(parsed).replace("git+ssh://", "git+", 1) + if isinstance(uri, str) and "git+ssh://" in uri: + parsed = urlparse(uri) + # split the path on the first separating / so we can put the first segment + # into the 'netloc' section with a : separator + path_part, _, path = parsed.path.lstrip("/").partition("/") + path = f"/{path}" + parsed = parsed._replace(netloc=f"{parsed.netloc}:{path_part}", path=path) + uri = urlunparse(parsed).replace("git+ssh://", "git+", 1) return uri @@ -94,7 +93,7 @@ def is_vcs(pipfile_entry): # type: (PipfileType) -> bool """Determine if dictionary entry from Pipfile is for a vcs dependency.""" if isinstance(pipfile_entry, Mapping): - return any(key for key in pipfile_entry.keys() if key in VCS_LIST) + return any(key for key in pipfile_entry if key in VCS_LIST) elif isinstance(pipfile_entry, str): if not is_valid_url(pipfile_entry) and pipfile_entry.startswith("git+"): @@ -136,9 +135,7 @@ def convert_entry_to_path(path): elif "path" in path: path = path["path"] - if not os.name == "nt": - return os.fsdecode(path) - return Path(os.fsdecode(path)).as_posix() + return Path(os.fsdecode(path)).as_posix() if os.name == "nt" else os.fsdecode(path) def is_installable_file(path): diff --git a/pipenv/utils/resolver.py b/pipenv/utils/resolver.py index 34277872..7866c7dd 100644 --- a/pipenv/utils/resolver.py +++ b/pipenv/utils/resolver.py @@ -548,7 +548,7 @@ class Resolver: reqs = [(ireq,) for ireq in self.resolved_tree] results = {} for (ireq,) in reqs: - if normalize_name(ireq.name) in self.skipped.keys(): + if normalize_name(ireq.name) in self.skipped: continue collected_hashes = self.hashes.get(ireq, set()) if collected_hashes: diff --git a/pipenv/utils/shell.py b/pipenv/utils/shell.py index 77236525..dd7795ab 100644 --- a/pipenv/utils/shell.py +++ b/pipenv/utils/shell.py @@ -199,16 +199,12 @@ def get_workon_home(): def is_file(package): """Determine if a package name is for a File dependency.""" if hasattr(package, "keys"): - return any(key for key in package.keys() if key in ["file", "path"]) + return any(key for key in package if key in ["file", "path"]) if os.path.exists(str(package)): return True - for start in SCHEME_LIST: - if str(package).startswith(start): - return True - - return False + return any(str(package).startswith(start) for start in SCHEME_LIST) def is_virtual_environment(path): diff --git a/pipenv/utils/toml.py b/pipenv/utils/toml.py index 7fbdfcf1..1eec3fed 100644 --- a/pipenv/utils/toml.py +++ b/pipenv/utils/toml.py @@ -23,10 +23,9 @@ def cleanup_toml(tml): # Add newlines between TOML sections. for i, line in enumerate(toml.split("\n")): # Skip the first line. - if line.startswith("["): - if i > 0: - # Insert a newline before the heading. - new_toml.append("") + if line.startswith("[") and i > 0: + # Insert a newline before the heading. + new_toml.append("") new_toml.append(line) # adding new line at the end of the TOML file new_toml.append("") diff --git a/pipenv/utils/virtualenv.py b/pipenv/utils/virtualenv.py index dd1bf128..562d4ccc 100644 --- a/pipenv/utils/virtualenv.py +++ b/pipenv/utils/virtualenv.py @@ -1,3 +1,4 @@ +import contextlib import os import shutil import sys @@ -179,12 +180,11 @@ def ensure_virtualenv(project, python=None, site_packages=None, pypi_mirror=None # If VIRTUAL_ENV is set, there is a possibility that we are # going to remove the active virtualenv that the user cares # about, so confirm first. - if "VIRTUAL_ENV" in os.environ: - if not ( - project.s.PIPENV_YES - or click.confirm("Use existing virtualenv?", default=True) - ): - abort() + if "VIRTUAL_ENV" in os.environ and not ( + project.s.PIPENV_YES + or click.confirm("Use existing virtualenv?", default=True) + ): + abort() click.echo(click.style("Using existing virtualenv...", bold=True), err=True) # Remove the virtualenv. cleanup_virtualenv(project, bare=True) @@ -261,15 +261,12 @@ def ensure_python(project, python=None): # method of the user for new python installs. installer = None if not project.s.PIPENV_DONT_USE_PYENV: - try: + with contextlib.suppress(InstallerNotFound): installer = Pyenv(project) - except InstallerNotFound: - pass + if installer is None and not project.s.PIPENV_DONT_USE_ASDF: - try: + with contextlib.suppress(InstallerNotFound): installer = Asdf(project) - except InstallerNotFound: - pass if not installer: abort("Neither 'pyenv' nor 'asdf' could be found to install Python.") diff --git a/tasks/vendoring/__init__.py b/tasks/vendoring/__init__.py index 6157b58e..a469ee8b 100644 --- a/tasks/vendoring/__init__.py +++ b/tasks/vendoring/__init__.py @@ -395,9 +395,10 @@ def vendor(ctx, vendor_dir, package=None, rewrite=True): log("Rewriting imports for %s..." % item) rewrite_imports(item, vendored_libs) rename_if_needed(ctx, vendor_dir, item) - elif item.name not in FILE_WHITE_LIST: - if rewrite and not package or (package and item.stem.lower() in package): - rewrite_file_imports(item, vendored_libs) + elif item.name not in FILE_WHITE_LIST and ( + rewrite and not package or (package and item.stem.lower() in package) + ): + rewrite_file_imports(item, vendored_libs) if not package: apply_patches(ctx, patched=is_patched, pre=False) if is_patched: @@ -793,9 +794,8 @@ def vendor_artifact(ctx, package, version=None): dest_dir.mkdir() _, _, dest_path = urllib3_parse(link).path.rpartition("/") dest_file = dest_dir / dest_path - with open(dest_file.as_posix(), "wb") as target_handle: - with open_file(link) as fp: - if fp is None: - print(f"Error downloading {link}") - continue - shutil.copyfileobj(fp, target_handle) + with open(dest_file.as_posix(), "wb") as target_handle, open_file(link) as fp: + if fp is None: + print(f"Error downloading {link}") + continue + shutil.copyfileobj(fp, target_handle) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 1c8c0695..e16f7835 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -18,6 +18,7 @@ from pipenv.vendor import tomlkit from pipenv.utils.processes import subprocess_run from pipenv.utils.funktools import handle_remove_readonly from pipenv.utils.shell import temp_environ +import contextlib log = logging.getLogger(__name__) warnings.simplefilter("default", category=ResourceWarning) @@ -61,7 +62,7 @@ def check_github_ssh(): # registered with GitHub. Otherwise, the command will fail with # return_code=255 and say 'Permission denied (publickey).' c = subprocess_run('ssh -o StrictHostKeyChecking=no -o CheckHostIP=no -T git@github.com', timeout=30, shell=True) - res = True if c.returncode == 1 else False + res = c.returncode == 1 except KeyboardInterrupt: warnings.warn( "KeyboardInterrupt while checking GitHub ssh access", RuntimeWarning, stacklevel=1 @@ -145,9 +146,8 @@ class _Pipfile: def remove(self, package, dev=False): section = "packages" if not dev else "dev-packages" - if not dev and package not in self.document[section]: - if package in self.document["dev-packages"]: - section = "dev-packages" + if not dev and package not in self.document[section] and package in self.document["dev-packages"]: + section = "dev-packages" del self.document[section][package] self.write() @@ -164,7 +164,7 @@ class _Pipfile: if not self.document.get("source"): source_table = tomlkit.table() source_table["url"] = self.index - source_table["verify_ssl"] = True if self.index.startswith("https") else False + source_table["verify_ssl"] = bool(self.index.startswith("https")) source_table["name"] = "pipenv_test_index" self.document["source"].append(source_table) return tomlkit.dumps(self.document) @@ -204,10 +204,9 @@ class _PipenvInstance: self.pipfile_path = p_path if pipfile: - try: + with contextlib.suppress(FileNotFoundError): os.remove(p_path) - except FileNotFoundError: - pass + with open(p_path, 'a'): os.utime(p_path, None) @@ -221,10 +220,9 @@ class _PipenvInstance: def __exit__(self, *args): warn_msg = 'Failed to remove resource: {!r}' if self.pipfile_path: - try: + with contextlib.suppress(OSError): os.remove(self.pipfile_path) - except OSError: - pass + os.chdir(self.original_dir) if self._path: try: diff --git a/tests/integration/test_dot_venv.py b/tests/integration/test_dot_venv.py index 98074dcb..ce920e63 100644 --- a/tests/integration/test_dot_venv.py +++ b/tests/integration/test_dot_venv.py @@ -50,17 +50,16 @@ def test_venv_in_project_disabled_ignores_venv(false_value, pipenv_instance_pypi @pytest.mark.dotvenv @pytest.mark.parametrize("true_value", TRUE_VALUES) def test_venv_at_project_root(true_value, pipenv_instance_pypi): - with temp_environ(): - with pipenv_instance_pypi() as p: - os.environ['PIPENV_VENV_IN_PROJECT'] = true_value - c = p.pipenv('install') - assert c.returncode == 0 - assert normalize_drive(p.path) in p.pipenv('--venv').stdout - del os.environ['PIPENV_VENV_IN_PROJECT'] - os.mkdir('subdir') - os.chdir('subdir') - # should still detect installed - assert normalize_drive(p.path) in p.pipenv('--venv').stdout + with temp_environ(), pipenv_instance_pypi() as p: + os.environ['PIPENV_VENV_IN_PROJECT'] = true_value + c = p.pipenv('install') + assert c.returncode == 0 + assert normalize_drive(p.path) in p.pipenv('--venv').stdout + del os.environ['PIPENV_VENV_IN_PROJECT'] + os.mkdir('subdir') + os.chdir('subdir') + # should still detect installed + assert normalize_drive(p.path) in p.pipenv('--venv').stdout @pytest.mark.dotvenv @@ -136,22 +135,21 @@ def test_empty_venv_file(pipenv_instance_pypi): def test_venv_in_project_default_when_venv_exists(pipenv_instance_pypi): """Tests virtualenv creation when a .venv file exists at the project root. """ - with temp_environ(), pipenv_instance_pypi() as p: - with TemporaryDirectory( - prefix='pipenv-', suffix='-test_venv' - ) as venv_path: - file_path = os.path.join(p.path, '.venv') - with open(file_path, 'w') as f: - f.write(venv_path) + with temp_environ(), pipenv_instance_pypi() as p, TemporaryDirectory( + prefix='pipenv-', suffix='-test_venv' + ) as venv_path: + file_path = os.path.join(p.path, '.venv') + with open(file_path, 'w') as f: + f.write(venv_path) - c = p.pipenv('install') - assert c.returncode == 0 - c = p.pipenv('--venv') - assert c.returncode == 0 - venv_loc = Path(c.stdout.strip()) + c = p.pipenv('install') + assert c.returncode == 0 + c = p.pipenv('--venv') + assert c.returncode == 0 + venv_loc = Path(c.stdout.strip()) - assert venv_loc.joinpath('.project').exists() - assert venv_loc == Path(venv_path) + assert venv_loc.joinpath('.project').exists() + assert venv_loc == Path(venv_path) @pytest.mark.dotenv diff --git a/tests/integration/test_install_basic.py b/tests/integration/test_install_basic.py index 3f3f1d3d..02d5b855 100644 --- a/tests/integration/test_install_basic.py +++ b/tests/integration/test_install_basic.py @@ -31,8 +31,8 @@ def test_mirror_install(pipenv_instance_pypi): # Ensure the --pypi-mirror parameter hasn't altered the Pipfile or Pipfile.lock sources assert len(p.pipfile["source"]) == 1 assert len(p.lockfile["_meta"]["sources"]) == 1 - assert "https://pypi.org/simple" == p.pipfile["source"][0]["url"] - assert "https://pypi.org/simple" == p.lockfile["_meta"]["sources"][0]["url"] + assert p.pipfile["source"][0]["url"] == "https://pypi.org/simple" + assert p.lockfile["_meta"]["sources"][0]["url"] == "https://pypi.org/simple" assert "dataclasses-json" in p.pipfile["packages"] assert "dataclasses-json" in p.lockfile["default"] @@ -345,21 +345,20 @@ def test_editable_no_args(pipenv_instance_pypi): def test_install_venv_project_directory(pipenv_instance_pypi): """Test the project functionality during virtualenv creation. """ - with pipenv_instance_pypi() as p: - with temp_environ(), TemporaryDirectory( - prefix="pipenv-", suffix="temp_workon_home" - ) as workon_home: - os.environ["WORKON_HOME"] = workon_home + with pipenv_instance_pypi() as p, temp_environ(), TemporaryDirectory( + prefix="pipenv-", suffix="temp_workon_home" + ) as workon_home: + os.environ["WORKON_HOME"] = workon_home - c = p.pipenv("install six") - assert c.returncode == 0 + c = p.pipenv("install six") + assert c.returncode == 0 - venv_loc = None - for line in c.stderr.splitlines(): - if line.startswith("Virtualenv location:"): - venv_loc = Path(line.split(":", 1)[-1].strip()) - assert venv_loc is not None - assert venv_loc.joinpath(".project").exists() + venv_loc = None + for line in c.stderr.splitlines(): + if line.startswith("Virtualenv location:"): + venv_loc = Path(line.split(":", 1)[-1].strip()) + assert venv_loc is not None + assert venv_loc.joinpath(".project").exists() @pytest.mark.cli diff --git a/tests/integration/test_install_markers.py b/tests/integration/test_install_markers.py index f72a98d3..98c3ed9a 100644 --- a/tests/integration/test_install_markers.py +++ b/tests/integration/test_install_markers.py @@ -157,10 +157,9 @@ def test_resolver_unique_markers(pipenv_instance_pypi): @pytest.mark.project @pytest.mark.needs_internet def test_environment_variable_value_does_not_change_hash(pipenv_instance_private_pypi): - with pipenv_instance_private_pypi() as p: - with temp_environ(): - with open(p.pipfile_path, 'w') as f: - f.write(""" + with pipenv_instance_private_pypi() as p, temp_environ(): + with open(p.pipfile_path, 'w') as f: + f.write(""" [[source]] url = 'https://${PYPI_USERNAME}:${PYPI_PASSWORD}@pypi.org/simple' verify_ssl = true @@ -169,24 +168,24 @@ name = 'pypi' [packages] six = "*" """) - project = Project() + project = Project() - os.environ['PYPI_USERNAME'] = 'whatever' - os.environ['PYPI_PASSWORD'] = 'pass' - assert project.get_lockfile_hash() is None + os.environ['PYPI_USERNAME'] = 'whatever' + os.environ['PYPI_PASSWORD'] = 'pass' + assert project.get_lockfile_hash() is None - c = p.pipenv('install') - assert c.returncode == 0 - lock_hash = project.get_lockfile_hash() - assert lock_hash is not None - assert lock_hash == project.calculate_pipfile_hash() + c = p.pipenv('install') + assert c.returncode == 0 + lock_hash = project.get_lockfile_hash() + assert lock_hash is not None + assert lock_hash == project.calculate_pipfile_hash() - assert c.returncode == 0 - assert project.get_lockfile_hash() == project.calculate_pipfile_hash() + assert c.returncode == 0 + assert project.get_lockfile_hash() == project.calculate_pipfile_hash() - os.environ['PYPI_PASSWORD'] = 'pass2' - assert project.get_lockfile_hash() == project.calculate_pipfile_hash() + os.environ['PYPI_PASSWORD'] = 'pass2' + assert project.get_lockfile_hash() == project.calculate_pipfile_hash() - with open(p.pipfile_path, 'a') as f: - f.write('requests = "==2.14.0"\n') - assert project.get_lockfile_hash() != project.calculate_pipfile_hash() + with open(p.pipfile_path, 'a') as f: + f.write('requests = "==2.14.0"\n') + assert project.get_lockfile_hash() != project.calculate_pipfile_hash() diff --git a/tests/integration/test_lock.py b/tests/integration/test_lock.py index 7bc9ea68..91fd0c3e 100644 --- a/tests/integration/test_lock.py +++ b/tests/integration/test_lock.py @@ -220,19 +220,18 @@ allow_prereleases = true @flaky def test_complex_deps_lock_and_install_properly(pipenv_instance_pypi): # This uses the real PyPI because Maya has too many dependencies... - with pipenv_instance_pypi() as p: - with open(p.pipfile_path, 'w') as f: - contents = """ + with pipenv_instance_pypi() as p, open(p.pipfile_path, 'w') as f: + contents = """ [packages] maya = "*" """.strip() - f.write(contents) + f.write(contents) - c = p.pipenv('lock --verbose') - assert c.returncode == 0 + c = p.pipenv('lock --verbose') + assert c.returncode == 0 - c = p.pipenv('install') - assert c.returncode == 0 + c = p.pipenv('install') + assert c.returncode == 0 @pytest.mark.lock diff --git a/tests/integration/test_pipenv.py b/tests/integration/test_pipenv.py index 614af3a8..3fb69abd 100644 --- a/tests/integration/test_pipenv.py +++ b/tests/integration/test_pipenv.py @@ -74,11 +74,10 @@ def test_proper_names_unmanaged_virtualenv(pipenv_instance_pypi): @pytest.mark.cli def test_directory_with_leading_dash(pipenv_instance_pypi): - with temp_environ(): - with pipenv_instance_pypi() as p: - c = p.pipenv('run pip freeze') - assert c.returncode == 0 - c = p.pipenv('--venv') - assert c.returncode == 0 - venv_path = c.stdout.strip() - assert os.path.isdir(venv_path) + with temp_environ(), pipenv_instance_pypi() as p: + c = p.pipenv('run pip freeze') + assert c.returncode == 0 + c = p.pipenv('--venv') + assert c.returncode == 0 + venv_path = c.stdout.strip() + assert os.path.isdir(venv_path) diff --git a/tests/integration/test_project.py b/tests/integration/test_project.py index c4be350d..39f01fca 100644 --- a/tests/integration/test_project.py +++ b/tests/integration/test_project.py @@ -13,10 +13,9 @@ from pipenv.utils.fileutils import normalize_path @pytest.mark.sources @pytest.mark.environ def test_pipfile_envvar_expansion(pipenv_instance_pypi): - with pipenv_instance_pypi() as p: - with temp_environ(): - with open(p.pipfile_path, 'w') as f: - f.write(""" + with pipenv_instance_pypi() as p, temp_environ(): + with open(p.pipfile_path, 'w') as f: + f.write(""" [[source]] url = 'https://${TEST_HOST}/simple' verify_ssl = false @@ -25,11 +24,11 @@ name = "pypi" [packages] pytz = "*" """.strip()) - os.environ['TEST_HOST'] = 'localhost:5000' - project = Project() - assert project.sources[0]['url'] == 'https://localhost:5000/simple' - assert 'localhost:5000' not in str(Pipfile.load(open(p.pipfile_path))) - print(str(Pipfile.load(open(p.pipfile_path)))) + os.environ['TEST_HOST'] = 'localhost:5000' + project = Project() + assert project.sources[0]['url'] == 'https://localhost:5000/simple' + assert 'localhost:5000' not in str(Pipfile.load(open(p.pipfile_path))) + print(str(Pipfile.load(open(p.pipfile_path)))) @pytest.mark.project diff --git a/tests/integration/test_uninstall.py b/tests/integration/test_uninstall.py index 06892bdc..f9738598 100644 --- a/tests/integration/test_uninstall.py +++ b/tests/integration/test_uninstall.py @@ -60,8 +60,8 @@ def test_mirror_uninstall(pipenv_instance_pypi): # Ensure the --pypi-mirror parameter hasn't altered the Pipfile or Pipfile.lock sources assert len(p.pipfile["source"]) == 1 assert len(p.lockfile["_meta"]["sources"]) == 1 - assert "https://pypi.org/simple" == p.pipfile["source"][0]["url"] - assert "https://pypi.org/simple" == p.lockfile["_meta"]["sources"][0]["url"] + assert p.pipfile["source"][0]["url"] == "https://pypi.org/simple" + assert p.lockfile["_meta"]["sources"][0]["url"] == "https://pypi.org/simple" c = p.pipenv("run python -m django --version") assert c.returncode == 0 @@ -74,8 +74,8 @@ def test_mirror_uninstall(pipenv_instance_pypi): # Ensure the --pypi-mirror parameter hasn't altered the Pipfile or Pipfile.lock sources assert len(p.pipfile["source"]) == 1 assert len(p.lockfile["_meta"]["sources"]) == 1 - assert "https://pypi.org/simple" == p.pipfile["source"][0]["url"] - assert "https://pypi.org/simple" == p.lockfile["_meta"]["sources"][0]["url"] + assert p.pipfile["source"][0]["url"] == "https://pypi.org/simple" + assert p.lockfile["_meta"]["sources"][0]["url"] == "https://pypi.org/simple" c = p.pipenv("run python -m django --version") assert c.returncode > 0 From 90714e2268f8e0c3435b28b2c149197a17e3c5f7 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Thu, 31 Aug 2023 19:53:26 -0400 Subject: [PATCH 03/12] Relative paths improvements for editable installs (#5896) * Relative paths improvements for editable installs --- news/5896.bugfix.rst | 1 + pipenv/utils/dependencies.py | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 news/5896.bugfix.rst diff --git a/news/5896.bugfix.rst b/news/5896.bugfix.rst new file mode 100644 index 00000000..8fb6083a --- /dev/null +++ b/news/5896.bugfix.rst @@ -0,0 +1 @@ +Relative paths improvements for editable installs. diff --git a/pipenv/utils/dependencies.py b/pipenv/utils/dependencies.py index 36050f56..8865dbc7 100644 --- a/pipenv/utils/dependencies.py +++ b/pipenv/utils/dependencies.py @@ -645,10 +645,29 @@ def determine_path_specifier(package: InstallRequirement): if package.link.scheme in ["http", "https"]: return package.link.url_without_fragment if package.link.scheme == "file": + abs_path = Path(package.link.file_path).resolve() + current_dir = Path.cwd() + try: - return Path(package.link.file_path).relative_to(Path.cwd()).as_posix() + relative_path = abs_path.relative_to(current_dir) + return relative_path.as_posix() except ValueError: - return Path(package.link.file_path).as_posix() + # If the direct relative_to fails, manually compute the relative path + common_parts = 0 + for part_a, part_b in zip(abs_path.parts, current_dir.parts): + if part_a == part_b: + common_parts += 1 + else: + break + + # Number of ".." needed are the extra parts in the current directory + # beyond the common parts + up_levels = [".."] * (len(current_dir.parts) - common_parts) + # The relative path is constructed by going up as needed and then + # appending the non-common parts of the absolute path + rel_parts = up_levels + list(abs_path.parts[common_parts:]) + relative_path = Path(*rel_parts) + return relative_path.as_posix() def determine_vcs_specifier(package: InstallRequirement): From bf542b1f04266dabf7e4eb57e19d9e34cdeb7ace Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Thu, 31 Aug 2023 19:55:17 -0400 Subject: [PATCH 04/12] Set log level in resolver to WARN when verbose is not passed (#5897) * Set log level in resolver to WARN when verbose is not passed --- news/5897.bugfix.rst | 1 + pipenv/resolver.py | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 news/5897.bugfix.rst diff --git a/news/5897.bugfix.rst b/news/5897.bugfix.rst new file mode 100644 index 00000000..85844566 --- /dev/null +++ b/news/5897.bugfix.rst @@ -0,0 +1 @@ +Set log level in resolver to WARN when verbose is not passed. diff --git a/pipenv/resolver.py b/pipenv/resolver.py index f89a10c1..82e01ca3 100644 --- a/pipenv/resolver.py +++ b/pipenv/resolver.py @@ -1,5 +1,6 @@ import importlib.util import json +import logging import os import sys @@ -654,6 +655,9 @@ def main(argv=None): os.environ["PYTHONIOENCODING"] = "utf-8" os.environ["PYTHONUNBUFFERED"] = "1" parsed = handle_parsed_args(parsed) + if not parsed.verbose: + print(parsed.verbose) + logging.getLogger("pipenv").setLevel(logging.WARN) _main( parsed.pre, parsed.clear, From 4cf36f82a77437be006dc20212a207fe569d3d48 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Thu, 31 Aug 2023 20:16:07 -0400 Subject: [PATCH 05/12] Apply patch for install_search_all_sources = True (#5895) * Apply patch for install_search_all_sources = True * patch the patch * Add news fragment * add back test of install_search_all_sources --- news/5895.bugfix.rst | 1 + .../pip/_internal/models/search_scope.py | 8 ++++-- pipenv/utils/resolver.py | 2 +- .../patches/patched/pip_index_safety.patch | 20 +++++++------ tests/integration/test_install_uri.py | 6 ++-- tests/integration/test_lock.py | 28 +++++++++++++++++++ 6 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 news/5895.bugfix.rst diff --git a/news/5895.bugfix.rst b/news/5895.bugfix.rst new file mode 100644 index 00000000..9eeed1f8 --- /dev/null +++ b/news/5895.bugfix.rst @@ -0,0 +1 @@ +Apply patch for install_search_all_sources = True functionality. diff --git a/pipenv/patched/pip/_internal/models/search_scope.py b/pipenv/patched/pip/_internal/models/search_scope.py index 85b35f7f..a3d9929c 100644 --- a/pipenv/patched/pip/_internal/models/search_scope.py +++ b/pipenv/patched/pip/_internal/models/search_scope.py @@ -20,7 +20,7 @@ class SearchScope: Encapsulates the locations that pip is configured to search. """ - __slots__ = ["find_links", "index_urls", "no_index", "index_lookup"] + __slots__ = ["find_links", "index_urls", "no_index", "index_lookup", "index_restricted"] @classmethod def create( @@ -29,6 +29,7 @@ class SearchScope: index_urls: List[str], no_index: bool, index_lookup: Optional[Dict[str, List[str]]] = None, + index_restricted: bool = False, ) -> "SearchScope": """ Create a SearchScope object after normalizing the `find_links`. @@ -64,6 +65,7 @@ class SearchScope: index_urls=index_urls, no_index=no_index, index_lookup=index_lookup, + index_restricted=index_restricted, ) def __init__( @@ -72,11 +74,13 @@ class SearchScope: index_urls: List[str], no_index: bool, index_lookup: Optional[Dict[str, List[str]]] = None, + index_restricted: bool = False, ) -> None: self.find_links = find_links self.index_urls = index_urls self.no_index = no_index self.index_lookup = index_lookup if index_lookup else {} + self.index_restricted = index_restricted def get_formatted_locations(self) -> str: lines = [] @@ -136,6 +140,6 @@ class SearchScope: index_urls = self.index_urls if project_name in self.index_lookup: index_urls = [self.index_lookup[project_name]] - elif self.index_urls: + elif self.index_restricted and self.index_urls: index_urls = [self.index_urls[0]] return [mkurl_pypi_url(url) for url in index_urls] diff --git a/pipenv/utils/resolver.py b/pipenv/utils/resolver.py index 7866c7dd..bcdef0cc 100644 --- a/pipenv/utils/resolver.py +++ b/pipenv/utils/resolver.py @@ -245,7 +245,6 @@ class Resolver: resolver.skipped[package_name] = dep resolver.initial_constraints = constraints resolver.index_lookup = index_lookup - resolver.finder.index_lookup = index_lookup resolver.markers_lookup = markers_lookup return resolver @@ -340,6 +339,7 @@ class Resolver: finder = self.package_finder index_lookup = self.prepare_index_lookup() finder._link_collector.index_lookup = index_lookup + finder._link_collector.search_scope.index_restricted = True finder._link_collector.search_scope.index_lookup = index_lookup return finder diff --git a/tasks/vendoring/patches/patched/pip_index_safety.patch b/tasks/vendoring/patches/patched/pip_index_safety.patch index e8acac5e..cf5d6020 100644 --- a/tasks/vendoring/patches/patched/pip_index_safety.patch +++ b/tasks/vendoring/patches/patched/pip_index_safety.patch @@ -1,5 +1,5 @@ diff --git a/pipenv/patched/pip/_internal/index/collector.py b/pipenv/patched/pip/_internal/index/collector.py -index 0120610c..ead5227e 100644 +index b3e293ea3..f27a88725 100644 --- a/pipenv/patched/pip/_internal/index/collector.py +++ b/pipenv/patched/pip/_internal/index/collector.py @@ -412,9 +412,11 @@ class LinkCollector: @@ -36,7 +36,7 @@ index 0120610c..ead5227e 100644 return link_collector diff --git a/pipenv/patched/pip/_internal/models/search_scope.py b/pipenv/patched/pip/_internal/models/search_scope.py -index fe61e8116..dab85fbb9 100644 +index fe61e8116..98a2cc97f 100644 --- a/pipenv/patched/pip/_internal/models/search_scope.py +++ b/pipenv/patched/pip/_internal/models/search_scope.py @@ -3,7 +3,7 @@ import logging @@ -53,40 +53,44 @@ index fe61e8116..dab85fbb9 100644 """ - __slots__ = ["find_links", "index_urls", "no_index"] -+ __slots__ = ["find_links", "index_urls", "no_index", "index_lookup"] ++ __slots__ = ["find_links", "index_urls", "no_index", "index_lookup", "index_restricted"] @classmethod def create( -@@ -28,6 +28,7 @@ class SearchScope: +@@ -28,6 +28,8 @@ class SearchScope: find_links: List[str], index_urls: List[str], no_index: bool, + index_lookup: Optional[Dict[str, List[str]]] = None, ++ index_restricted: bool = False, ) -> "SearchScope": """ Create a SearchScope object after normalizing the `find_links`. -@@ -62,6 +63,7 @@ class SearchScope: +@@ -62,6 +64,8 @@ class SearchScope: find_links=built_find_links, index_urls=index_urls, no_index=no_index, + index_lookup=index_lookup, ++ index_restricted=index_restricted, ) def __init__( -@@ -69,10 +71,12 @@ class SearchScope: +@@ -69,10 +73,14 @@ class SearchScope: find_links: List[str], index_urls: List[str], no_index: bool, + index_lookup: Optional[Dict[str, List[str]]] = None, ++ index_restricted: bool = False, ) -> None: self.find_links = find_links self.index_urls = index_urls self.no_index = no_index + self.index_lookup = index_lookup if index_lookup else {} ++ self.index_restricted = index_restricted def get_formatted_locations(self) -> str: lines = [] -@@ -129,4 +133,9 @@ class SearchScope: +@@ -129,4 +137,9 @@ class SearchScope: loc = loc + "/" return loc @@ -94,6 +98,6 @@ index fe61e8116..dab85fbb9 100644 + index_urls = self.index_urls + if project_name in self.index_lookup: + index_urls = [self.index_lookup[project_name]] -+ elif self.index_urls: ++ elif self.index_restricted and self.index_urls: + index_urls = [self.index_urls[0]] + return [mkurl_pypi_url(url) for url in index_urls] diff --git a/tests/integration/test_install_uri.py b/tests/integration/test_install_uri.py index 01855f5e..b07f52a5 100644 --- a/tests/integration/test_install_uri.py +++ b/tests/integration/test_install_uri.py @@ -139,8 +139,8 @@ six = "*" @pytest.mark.install @pytest.mark.needs_internet @pytest.mark.skipif(sys.version_info >= (3, 12), reason="Package does not work with Python 3.12") -def test_install_specifying_index_url(pipenv_instance_pypi): - with pipenv_instance_pypi() as p: +def test_install_specifying_index_url(pipenv_instance_private_pypi): + with pipenv_instance_private_pypi() as p: with open(p.pipfile_path, "w") as f: contents = """ [[source]] @@ -153,6 +153,8 @@ six = "*" [dev-packages] +[pipenv] +install_search_all_sources = true """.strip() f.write(contents) c = p.pipenv("install pipenv-test-private-package --index https://test.pypi.org/simple") diff --git a/tests/integration/test_lock.py b/tests/integration/test_lock.py index 91fd0c3e..0259f6ba 100644 --- a/tests/integration/test_lock.py +++ b/tests/integration/test_lock.py @@ -646,3 +646,31 @@ dataclasses-json = {extras = ["dev"], version = "==0.5.7"} assert "dataclasses-json" in p.pipfile["packages"] assert "dataclasses-json" in p.lockfile["default"] assert p.lockfile["default"]["dataclasses-json"].get("markers", "") is not None + +@pytest.mark.index +@pytest.mark.install # private indexes need to be uncached for resolution +@pytest.mark.skip_lock +@pytest.mark.needs_internet +def test_private_index_skip_lock(pipenv_instance_private_pypi): + with pipenv_instance_private_pypi() as p: + with open(p.pipfile_path, 'w') as f: + contents = """ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[[source]] +url = "https://test.pypi.org/simple" +verify_ssl = true +name = "testpypi" + +[packages] +pipenv-test-private-package = {version = "*", index = "testpypi"} + +[pipenv] +install_search_all_sources = true + """.strip() + f.write(contents) + c = p.pipenv('install --skip-lock') + assert c.returncode == 0 From 705919b40bc77b7a3121e501686a91b9b7193c97 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 1 Sep 2023 03:27:00 +0200 Subject: [PATCH 06/12] Pipfile: Add build and twine (#5901) * Pipfile: Add build and twine --- Pipfile | 2 + Pipfile.lock | 357 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 334 insertions(+), 25 deletions(-) diff --git a/Pipfile b/Pipfile index 67e0637e..515d7ab1 100644 --- a/Pipfile +++ b/Pipfile @@ -26,6 +26,8 @@ invoke = "==2.0.0" exceptiongroup = "==1.1.0" tomli = "*" pyyaml = "==6.0.1" +build = "*" +twine = "*" [packages] pytz = "*" diff --git a/Pipfile.lock b/Pipfile.lock index a50d34de..4a82ff44 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "8a01aed3d68063b2b3880a1bbbb8113abeeb21fddea18c6d68dbc40f594d9c54" + "sha256": "262864edb3f18af99a16b3a0d7b9d06fe99a0b86d52486f66a9ac82d0460755f" }, "pipfile-spec": 6, "requires": {}, @@ -101,6 +101,23 @@ "markers": "python_version >= '3.7'", "version": "==23.3.0" }, + "bleach": { + "hashes": [ + "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414", + "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4" + ], + "markers": "python_version >= '3.7'", + "version": "==6.0.0" + }, + "build": { + "hashes": [ + "sha256:af266720050a66c893a6096a2f410989eeac74ff9a68ba194b3f6473e8e26171", + "sha256:d5b71264afdb5951d6704482aac78de887c80691c52b88a9ad195983ca2c9269" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==0.10.0" + }, "certifi": { "hashes": [ "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082", @@ -109,6 +126,75 @@ "markers": "python_version >= '3.6'", "version": "==2023.7.22" }, + "cffi": { + "hashes": [ + "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5", + "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef", + "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104", + "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426", + "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405", + "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375", + "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a", + "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e", + "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc", + "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf", + "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185", + "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497", + "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3", + "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35", + "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c", + "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83", + "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21", + "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca", + "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984", + "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac", + "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd", + "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee", + "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a", + "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2", + "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192", + "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7", + "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585", + "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f", + "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e", + "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27", + "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b", + "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e", + "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e", + "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d", + "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c", + "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415", + "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82", + "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02", + "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314", + "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325", + "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c", + "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3", + "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914", + "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045", + "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d", + "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9", + "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5", + "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2", + "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c", + "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3", + "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2", + "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8", + "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d", + "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d", + "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9", + "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162", + "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76", + "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4", + "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e", + "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9", + "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6", + "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b", + "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01", + "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0" + ], + "version": "==1.15.1" + }, "cfgv": { "hashes": [ "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426", @@ -292,6 +378,35 @@ "markers": "python_version >= '3.7'", "version": "==7.2.7" }, + "cryptography": { + "hashes": [ + "sha256:0d09fb5356f975974dbcb595ad2d178305e5050656affb7890a1583f5e02a306", + "sha256:23c2d778cf829f7d0ae180600b17e9fceea3c2ef8b31a99e3c694cbbf3a24b84", + "sha256:3fb248989b6363906827284cd20cca63bb1a757e0a2864d4c1682a985e3dca47", + "sha256:41d7aa7cdfded09b3d73a47f429c298e80796c8e825ddfadc84c8a7f12df212d", + "sha256:42cb413e01a5d36da9929baa9d70ca90d90b969269e5a12d39c1e0d475010116", + "sha256:4c2f0d35703d61002a2bbdcf15548ebb701cfdd83cdc12471d2bae80878a4207", + "sha256:4fd871184321100fb400d759ad0cddddf284c4b696568204d281c902fc7b0d81", + "sha256:5259cb659aa43005eb55a0e4ff2c825ca111a0da1814202c64d28a985d33b087", + "sha256:57a51b89f954f216a81c9d057bf1a24e2f36e764a1ca9a501a6964eb4a6800dd", + "sha256:652627a055cb52a84f8c448185922241dd5217443ca194d5739b44612c5e6507", + "sha256:67e120e9a577c64fe1f611e53b30b3e69744e5910ff3b6e97e935aeb96005858", + "sha256:6af1c6387c531cd364b72c28daa29232162010d952ceb7e5ca8e2827526aceae", + "sha256:6d192741113ef5e30d89dcb5b956ef4e1578f304708701b8b73d38e3e1461f34", + "sha256:7efe8041897fe7a50863e51b77789b657a133c75c3b094e51b5e4b5cec7bf906", + "sha256:84537453d57f55a50a5b6835622ee405816999a7113267739a1b4581f83535bd", + "sha256:8f09daa483aedea50d249ef98ed500569841d6498aa9c9f4b0531b9964658922", + "sha256:95dd7f261bb76948b52a5330ba5202b91a26fbac13ad0e9fc8a3ac04752058c7", + "sha256:a74fbcdb2a0d46fe00504f571a2a540532f4c188e6ccf26f1f178480117b33c4", + "sha256:a983e441a00a9d57a4d7c91b3116a37ae602907a7618b882c8013b5762e80574", + "sha256:ab8de0d091acbf778f74286f4989cf3d1528336af1b59f3e5d2ebca8b5fe49e1", + "sha256:aeb57c421b34af8f9fe830e1955bf493a86a7996cc1338fe41b30047d16e962c", + "sha256:ce785cf81a7bdade534297ef9e490ddff800d956625020ab2ec2780a556c313e", + "sha256:d0d651aa754ef58d75cec6edfbd21259d93810b73f6ec246436a21b7841908de" + ], + "markers": "python_version >= '3.7'", + "version": "==41.0.3" + }, "distlib": { "hashes": [ "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057", @@ -350,19 +465,19 @@ }, "gunicorn": { "hashes": [ - "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", - "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8" + "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0", + "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033" ], "markers": "sys_platform == 'linux'", - "version": "==20.1.0" + "version": "==21.2.0" }, "identify": { "hashes": [ - "sha256:7243800bce2f58404ed41b7c002e53d4d22bcf3ae1b7900c2d7aefd95394bf7f", - "sha256:c22a8ead0d4ca11f1edd6c9418c3220669b3b7533ada0a0ffa6cc0ef85cf9b54" + "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4", + "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d" ], - "markers": "python_version >= '3.8'", - "version": "==2.5.26" + "markers": "python_version >= '3.7'", + "version": "==2.5.24" }, "idna": { "hashes": [ @@ -382,11 +497,19 @@ }, "importlib-metadata": { "hashes": [ - "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad", - "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d" + "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4", + "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5" ], "markers": "python_version < '3.8'", - "version": "==6.0.0" + "version": "==6.7.0" + }, + "importlib-resources": { + "hashes": [ + "sha256:4be82589bf5c1d7999aedf2a45159d10cb3ca4f19b2271f8792bc8e6da7b22f6", + "sha256:7b1deeebbf351c7578e09bf2f63fa2ce8b5ffec296e0d349139d43cca061a81a" + ], + "markers": "python_version < '3.9'", + "version": "==5.12.0" }, "incremental": { "hashes": [ @@ -412,6 +535,22 @@ "markers": "python_version >= '3.6'", "version": "==2.0.0" }, + "jaraco.classes": { + "hashes": [ + "sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158", + "sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a" + ], + "markers": "python_version >= '3.7'", + "version": "==3.2.3" + }, + "jeepney": { + "hashes": [ + "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806", + "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755" + ], + "markers": "sys_platform == 'linux'", + "version": "==0.8.0" + }, "jinja2": { "hashes": [ "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", @@ -420,6 +559,14 @@ "markers": "python_version >= '3.7'", "version": "==3.1.2" }, + "keyring": { + "hashes": [ + "sha256:3d44a48fa9a254f6c72879d7c88604831ebdaac6ecb0b214308b02953502c510", + "sha256:bc402c5e501053098bcbd149c4ddbf8e36c6809e572c2d098d4961e88d4c270d" + ], + "markers": "python_version >= '3.7'", + "version": "==24.1.1" + }, "linkify-it-py": { "hashes": [ "sha256:11e29f00150cddaa8f434153f103c14716e7e097a8fd372d9eb1ed06ed91524d", @@ -522,6 +669,14 @@ "markers": "python_version >= '3.6'", "version": "==5.1.0" }, + "more-itertools": { + "hashes": [ + "sha256:cabaa341ad0389ea83c17a94566a53ae4c9d07349861ecb14dc6d0345cf9ac5d", + "sha256:d2bc7f02446e86a68911e58ded76d6561eea00cddfb2a91e7019bbb586c799f3" + ], + "markers": "python_version >= '3.7'", + "version": "==9.1.0" + }, "mypy-extensions": { "hashes": [ "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", @@ -597,6 +752,14 @@ ], "path": "." }, + "pkginfo": { + "hashes": [ + "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546", + "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046" + ], + "markers": "python_version >= '3.6'", + "version": "==1.9.6" + }, "platformdirs": { "hashes": [ "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d", @@ -630,6 +793,13 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.7.0" }, + "pycparser": { + "hashes": [ + "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", + "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" + ], + "version": "==2.21" + }, "pyenchant": { "hashes": [ "sha256:0314d162b7af83adc500f5aff850c91466129363ca8c4d79a8b8d99253346204", @@ -650,11 +820,11 @@ }, "pygments": { "hashes": [ - "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c", - "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1" + "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692", + "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29" ], "markers": "python_version >= '3.7'", - "version": "==2.15.1" + "version": "==2.16.1" }, "pypiserver": { "hashes": [ @@ -665,6 +835,14 @@ "markers": "python_version >= '3.6'", "version": "==1.5.2" }, + "pyproject-hooks": { + "hashes": [ + "sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8", + "sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5" + ], + "markers": "python_version >= '3.7'", + "version": "==1.0.0" + }, "pytest": { "hashes": [ "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32", @@ -698,9 +876,19 @@ "markers": "python_version >= '3.7'", "version": "==3.3.1" }, + "pytz": { + "hashes": [ + "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588", + "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb" + ], + "index": "pypi", + "version": "==2023.3" + }, "pyyaml": { "hashes": [ + "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", + "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", @@ -708,7 +896,10 @@ "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", + "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", + "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", + "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", @@ -716,9 +907,12 @@ "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", + "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", + "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", + "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", @@ -733,7 +927,9 @@ "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", + "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", + "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", @@ -745,6 +941,14 @@ "markers": "python_version >= '3.6'", "version": "==6.0.1" }, + "readme-renderer": { + "hashes": [ + "sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273", + "sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343" + ], + "markers": "python_version >= '3.7'", + "version": "==37.3" + }, "requests": { "hashes": [ "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", @@ -753,6 +957,38 @@ "markers": "python_version >= '3.7'", "version": "==2.31.0" }, + "requests-toolbelt": { + "hashes": [ + "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", + "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.0.0" + }, + "rfc3986": { + "hashes": [ + "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd", + "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.0" + }, + "rich": { + "hashes": [ + "sha256:146a90b3b6b47cac4a73c12866a499e9817426423f57c5a66949c086191a8808", + "sha256:fb9d6c0a0f643c99eed3875b5377a184132ba9be4d61516a55273d3554d75a39" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==13.5.2" + }, + "secretstorage": { + "hashes": [ + "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", + "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99" + ], + "markers": "sys_platform == 'linux'", + "version": "==3.3.3" + }, "setuptools": { "hashes": [ "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f", @@ -761,6 +997,14 @@ "markers": "python_version >= '3.7'", "version": "==68.0.0" }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" + }, "snowballstemmer": { "hashes": [ "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", @@ -796,11 +1040,11 @@ }, "sphinxcontrib-applehelp": { "hashes": [ - "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228", - "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e" + "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a", + "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58" ], - "markers": "python_version >= '3.8'", - "version": "==1.0.4" + "markers": "python_version >= '3.5'", + "version": "==1.0.2" }, "sphinxcontrib-devhelp": { "hashes": [ @@ -812,11 +1056,11 @@ }, "sphinxcontrib-htmlhelp": { "hashes": [ - "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff", - "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903" + "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07", + "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2" ], - "markers": "python_version >= '3.8'", - "version": "==2.0.1" + "markers": "python_version >= '3.6'", + "version": "==2.0.0" }, "sphinxcontrib-jsmath": { "hashes": [ @@ -875,6 +1119,62 @@ "markers": "python_version >= '3.7'", "version": "==23.6.0" }, + "twine": { + "hashes": [ + "sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8", + "sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==4.0.2" + }, + "typed-ast": { + "hashes": [ + "sha256:042eb665ff6bf020dd2243307d11ed626306b82812aba21836096d229fdc6a10", + "sha256:045f9930a1550d9352464e5149710d56a2aed23a2ffe78946478f7b5416f1ede", + "sha256:0635900d16ae133cab3b26c607586131269f88266954eb04ec31535c9a12ef1e", + "sha256:118c1ce46ce58fda78503eae14b7664163aa735b620b64b5b725453696f2a35c", + "sha256:16f7313e0a08c7de57f2998c85e2a69a642e97cb32f87eb65fbfe88381a5e44d", + "sha256:1efebbbf4604ad1283e963e8915daa240cb4bf5067053cf2f0baadc4d4fb51b8", + "sha256:2188bc33d85951ea4ddad55d2b35598b2709d122c11c75cffd529fbc9965508e", + "sha256:2b946ef8c04f77230489f75b4b5a4a6f24c078be4aed241cfabe9cbf4156e7e5", + "sha256:335f22ccb244da2b5c296e6f96b06ee9bed46526db0de38d2f0e5a6597b81155", + "sha256:381eed9c95484ceef5ced626355fdc0765ab51d8553fec08661dce654a935db4", + "sha256:429ae404f69dc94b9361bb62291885894b7c6fb4640d561179548c849f8492ba", + "sha256:44f214394fc1af23ca6d4e9e744804d890045d1643dd7e8229951e0ef39429b5", + "sha256:48074261a842acf825af1968cd912f6f21357316080ebaca5f19abbb11690c8a", + "sha256:4bc1efe0ce3ffb74784e06460f01a223ac1f6ab31c6bc0376a21184bf5aabe3b", + "sha256:57bfc3cf35a0f2fdf0a88a3044aafaec1d2f24d8ae8cd87c4f58d615fb5b6311", + "sha256:597fc66b4162f959ee6a96b978c0435bd63791e31e4f410622d19f1686d5e769", + "sha256:5f7a8c46a8b333f71abd61d7ab9255440d4a588f34a21f126bbfc95f6049e686", + "sha256:5fe83a9a44c4ce67c796a1b466c270c1272e176603d5e06f6afbc101a572859d", + "sha256:61443214d9b4c660dcf4b5307f15c12cb30bdfe9588ce6158f4a005baeb167b2", + "sha256:622e4a006472b05cf6ef7f9f2636edc51bda670b7bbffa18d26b255269d3d814", + "sha256:6eb936d107e4d474940469e8ec5b380c9b329b5f08b78282d46baeebd3692dc9", + "sha256:7f58fabdde8dcbe764cef5e1a7fcb440f2463c1bbbec1cf2a86ca7bc1f95184b", + "sha256:83509f9324011c9a39faaef0922c6f720f9623afe3fe220b6d0b15638247206b", + "sha256:8c524eb3024edcc04e288db9541fe1f438f82d281e591c548903d5b77ad1ddd4", + "sha256:94282f7a354f36ef5dbce0ef3467ebf6a258e370ab33d5b40c249fa996e590dd", + "sha256:b445c2abfecab89a932b20bd8261488d574591173d07827c1eda32c457358b18", + "sha256:be4919b808efa61101456e87f2d4c75b228f4e52618621c77f1ddcaae15904fa", + "sha256:bfd39a41c0ef6f31684daff53befddae608f9daf6957140228a08e51f312d7e6", + "sha256:c631da9710271cb67b08bd3f3813b7af7f4c69c319b75475436fcab8c3d21bee", + "sha256:cc95ffaaab2be3b25eb938779e43f513e0e538a84dd14a5d844b8f2932593d88", + "sha256:d09d930c2d1d621f717bb217bf1fe2584616febb5138d9b3e8cdd26506c3f6d4", + "sha256:d40c10326893ecab8a80a53039164a224984339b2c32a6baf55ecbd5b1df6431", + "sha256:d41b7a686ce653e06c2609075d397ebd5b969d821b9797d029fccd71fdec8e04", + "sha256:d5c0c112a74c0e5db2c75882a0adf3133adedcdbfd8cf7c9d6ed77365ab90a1d", + "sha256:e1a976ed4cc2d71bb073e1b2a250892a6e968ff02aa14c1f40eba4f365ffec02", + "sha256:e48bf27022897577d8479eaed64701ecaf0467182448bd95759883300ca818c8", + "sha256:ed4a1a42df8a3dfb6b40c3d2de109e935949f2f66b19703eafade03173f8f437", + "sha256:f0aefdd66f1784c58f65b502b6cf8b121544680456d1cebbd300c2c813899274", + "sha256:fc2b8c4e1bc5cd96c1a823a885e6b158f8451cf6f5530e1829390b4d27d0807f", + "sha256:fd946abf3c31fb50eee07451a6aedbfff912fcd13cf357363f5b4e834cc5e71a", + "sha256:fe58ef6a764de7b4b36edfc8592641f56e69b7163bba9f9c8089838ee596bfb2" + ], + "markers": "python_version < '3.8' and implementation_name == 'cpython'", + "version": "==1.5.5" + }, "typing-extensions": { "hashes": [ "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36", @@ -902,11 +1202,11 @@ }, "virtualenv": { "hashes": [ - "sha256:43a3052be36080548bdee0b42919c88072037d50d56c28bd3f853cbe92b953ff", - "sha256:fd8a78f46f6b99a67b7ec5cf73f92357891a7b3a40fd97637c27f854aae3b9e0" + "sha256:29c70bb9b88510f6414ac3e55c8b413a1f96239b6b789ca123437d5e892190cb", + "sha256:772b05bfda7ed3b8ecd16021ca9716273ad9f4467c801f27e83ac73430246dca" ], "markers": "python_version >= '3.7'", - "version": "==20.24.2" + "version": "==20.24.4" }, "waitress": { "hashes": [ @@ -916,6 +1216,13 @@ "markers": "sys_platform == 'win32'", "version": "==2.1.2" }, + "webencodings": { + "hashes": [ + "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", + "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" + ], + "version": "==0.5.1" + }, "zipp": { "hashes": [ "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832", From 56d1e1cd72a944b56c57f51bd065beeaaf31007d Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Fri, 1 Sep 2023 05:02:12 -0400 Subject: [PATCH 07/12] Handle more variations in private index html to improve hash collection (#5898) * Handle more cases of hash collection * add news fragment --- news/5898.bugfix.rst | 1 + pipenv/project.py | 51 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 news/5898.bugfix.rst diff --git a/news/5898.bugfix.rst b/news/5898.bugfix.rst new file mode 100644 index 00000000..0b9c5c26 --- /dev/null +++ b/news/5898.bugfix.rst @@ -0,0 +1 @@ +Handle more variations in private index html to improve hash collection. diff --git a/pipenv/project.py b/pipenv/project.py index ca173fbc..7a8978f0 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -292,17 +292,16 @@ class Project: return None def get_hashes_from_remote_index_urls(self, ireq, source): - pkg_url = f"{source['url']}/{ireq.name}/" + normalized_name = normalize_name(ireq.name) + url_name = normalized_name.replace(".", "-") + pkg_url = f"{source['url']}/{url_name}/" session = self.get_requests_session_for_source(source) + try: collected_hashes = set() - # Grab the hashes from the new warehouse API. response = session.get(pkg_url, timeout=10) - # Create an instance of the parser parser = PackageIndexHTMLParser() - # Feed the HTML to the parser parser.feed(response.text) - # Extract hrefs hrefs = parser.urls version = "" @@ -310,19 +309,45 @@ class Project: spec = next(iter(s for s in ireq.specifier), None) if spec: version = spec.version + + # We'll check if the href looks like a version-specific page (i.e., ends with '/') for package_url in hrefs: - if version in parse.unquote(package_url): + parsed_url = parse.urlparse(package_url) + if version in parsed_url.path and parsed_url.path.endswith("/"): + # This might be a version-specific page. Fetch and parse it + version_url = urljoin(pkg_url, package_url) + version_response = session.get(version_url, timeout=10) + version_parser = PackageIndexHTMLParser() + version_parser.feed(version_response.text) + version_hrefs = version_parser.urls + + # Process these new hrefs as potential wheels + for v_package_url in version_hrefs: + url_params = parse.urlparse(v_package_url).fragment + params_dict = parse.parse_qs(url_params) + if params_dict.get(FAVORITE_HASH): + collected_hashes.add(params_dict[FAVORITE_HASH][0]) + else: # Fallback to downloading the file to obtain hash + v_package_full_url = urljoin(version_url, v_package_url) + link = Link(v_package_full_url) + file_hash = self.get_file_hash(session, link) + if file_hash: + collected_hashes.add(file_hash) + elif version in parse.unquote(package_url): + # Process the current href as a potential wheel from the main page url_params = parse.urlparse(package_url).fragment params_dict = parse.parse_qs(url_params) if params_dict.get(FAVORITE_HASH): collected_hashes.add(params_dict[FAVORITE_HASH][0]) else: # Fallback to downloading the file to obtain hash - package_url = urljoin(source["url"], package_url) - link = Link(package_url) + package_full_url = urljoin(pkg_url, package_url) + link = Link(package_full_url) file_hash = self.get_file_hash(session, link) if file_hash: collected_hashes.add(file_hash) + return self.prepend_hash_types(collected_hashes, FAVORITE_HASH) + except (ValueError, KeyError, ConnectionError): if self.s.is_verbose(): click.echo( @@ -1198,8 +1223,12 @@ class Project: return newly_added, category, normalized_name def src_name_from_url(self, index_url): - name, _, tld_guess = urllib.parse.urlsplit(index_url).netloc.rpartition(".") - src_name = name.replace(".", "") + location = urllib.parse.urlsplit(index_url).netloc + if "." in location: + name, _, tld_guess = location.rpartition(".") + else: + name = location + src_name = name.replace(".", "").replace(":", "") try: self.get_source(name=src_name) except SourceNotFound: @@ -1221,7 +1250,7 @@ class Project: with contextlib.suppress(SourceNotFound): source = self.get_source(name=index) - if source is not None: + if source is not None and source.get("name"): return source["name"] source = {"url": index, "verify_ssl": verify_ssl} source["name"] = self.src_name_from_url(index) From 7520f6983bc82a5f2a72bbe5bc869f954ef95a9f Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Fri, 1 Sep 2023 05:15:36 -0400 Subject: [PATCH 08/12] Top level Pipfile sys_platform markers should be transitive (#5892) * Top level Pipfile sys_platform markers should be transitive * Add platform_machine top level specifier * Handle case where markers is None * more safety checks * relock on python 3.7 --------- Co-authored-by: Christian Clauss --- Pipfile | 15 ++-- Pipfile.lock | 156 ++++----------------------------------- news/5892.feature.rst | 1 + pipenv/utils/markers.py | 2 + pipenv/utils/resolver.py | 45 +++++++++++ 5 files changed, 73 insertions(+), 146 deletions(-) create mode 100644 news/5892.feature.rst diff --git a/Pipfile b/Pipfile index 515d7ab1..8c1b89f5 100644 --- a/Pipfile +++ b/Pipfile @@ -10,17 +10,20 @@ sphinx-click = "==4.*" sphinxcontrib-spelling = "==7.*" click = "==8.0.3" pypiserver = "==1.*" -stdeb = {version="*", markers="sys_platform == 'linux'"} +stdeb = {version="*", sys_platform = "== 'linux'"} zipp = {version = "==3.6.0", markers = "python_version < '3.10'"} pre-commit = "==2.*" -atomicwrites = {version = "*", markers="sys_platform == 'win32'"} +atomicwrites = {version = "*", sys_platform = "== 'win32'"} pytest-cov = "==3.*" +pluggy = "==1.2.0" # Can be removed from Pipfile when dropping py 3.7 +filelock = "==3.12.2" # Can be removed from Pipfile when dropping py 3.7 +coverage = "==7.2.7" # Can be removed from Pipfile when dropping py 3.7 typing-extensions = "==4.*" -waitress = {version = "*", markers="sys_platform == 'win32'"} -gunicorn = {version = "*", markers="sys_platform == 'linux'"} +waitress = {version = "*", sys_platform = "== 'win32'"} +gunicorn = {version = "*", sys_platform = "== 'linux'"} parse = "*" -importlib-metadata = {version = "*", markers="python_version < '3.8'"} -colorama= {version = "*", markers="sys_platform == 'win32'"} +importlib-metadata = {version = "*"} +colorama= {version = "*", sys_platform = "== 'win32'"} myst-parser = {extras = ["linkify"], version = "*"} invoke = "==2.0.0" exceptiongroup = "==1.1.0" diff --git a/Pipfile.lock b/Pipfile.lock index 4a82ff44..b5b49571 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "262864edb3f18af99a16b3a0d7b9d06fe99a0b86d52486f66a9ac82d0460755f" + "sha256": "8a84150804ee1b1aa65d180190c3795476aea5d3a49b530663ce52a03b5ca8c1" }, "pipfile-spec": 6, "requires": {}, @@ -43,7 +43,6 @@ "hashes": [ "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11" ], - "markers": "sys_platform == 'win32'", "version": "==1.4.1" }, "attrs": { @@ -67,7 +66,6 @@ "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da", "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a" ], - "markers": "python_full_version >= '3.6.0'", "version": "==4.12.2" }, "black": { @@ -98,7 +96,6 @@ "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4", "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3" ], - "markers": "python_version >= '3.7'", "version": "==23.3.0" }, "bleach": { @@ -126,75 +123,6 @@ "markers": "python_version >= '3.6'", "version": "==2023.7.22" }, - "cffi": { - "hashes": [ - "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5", - "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef", - "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104", - "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426", - "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405", - "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375", - "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a", - "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e", - "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc", - "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf", - "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185", - "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497", - "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3", - "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35", - "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c", - "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83", - "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21", - "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca", - "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984", - "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac", - "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd", - "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee", - "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a", - "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2", - "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192", - "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7", - "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585", - "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f", - "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e", - "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27", - "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b", - "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e", - "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e", - "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d", - "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c", - "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415", - "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82", - "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02", - "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314", - "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325", - "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c", - "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3", - "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914", - "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045", - "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d", - "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9", - "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5", - "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2", - "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c", - "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3", - "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2", - "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8", - "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d", - "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d", - "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9", - "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162", - "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76", - "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4", - "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e", - "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9", - "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6", - "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b", - "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01", - "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0" - ], - "version": "==1.15.1" - }, "cfgv": { "hashes": [ "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426", @@ -306,13 +234,10 @@ "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" ], - "markers": "sys_platform == 'win32'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6' and sys_platform == 'win32'", "version": "==0.4.6" }, "coverage": { - "extras": [ - "toml" - ], "hashes": [ "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f", "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2", @@ -375,38 +300,10 @@ "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850", "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3" ], + "index": "pypi", "markers": "python_version >= '3.7'", "version": "==7.2.7" }, - "cryptography": { - "hashes": [ - "sha256:0d09fb5356f975974dbcb595ad2d178305e5050656affb7890a1583f5e02a306", - "sha256:23c2d778cf829f7d0ae180600b17e9fceea3c2ef8b31a99e3c694cbbf3a24b84", - "sha256:3fb248989b6363906827284cd20cca63bb1a757e0a2864d4c1682a985e3dca47", - "sha256:41d7aa7cdfded09b3d73a47f429c298e80796c8e825ddfadc84c8a7f12df212d", - "sha256:42cb413e01a5d36da9929baa9d70ca90d90b969269e5a12d39c1e0d475010116", - "sha256:4c2f0d35703d61002a2bbdcf15548ebb701cfdd83cdc12471d2bae80878a4207", - "sha256:4fd871184321100fb400d759ad0cddddf284c4b696568204d281c902fc7b0d81", - "sha256:5259cb659aa43005eb55a0e4ff2c825ca111a0da1814202c64d28a985d33b087", - "sha256:57a51b89f954f216a81c9d057bf1a24e2f36e764a1ca9a501a6964eb4a6800dd", - "sha256:652627a055cb52a84f8c448185922241dd5217443ca194d5739b44612c5e6507", - "sha256:67e120e9a577c64fe1f611e53b30b3e69744e5910ff3b6e97e935aeb96005858", - "sha256:6af1c6387c531cd364b72c28daa29232162010d952ceb7e5ca8e2827526aceae", - "sha256:6d192741113ef5e30d89dcb5b956ef4e1578f304708701b8b73d38e3e1461f34", - "sha256:7efe8041897fe7a50863e51b77789b657a133c75c3b094e51b5e4b5cec7bf906", - "sha256:84537453d57f55a50a5b6835622ee405816999a7113267739a1b4581f83535bd", - "sha256:8f09daa483aedea50d249ef98ed500569841d6498aa9c9f4b0531b9964658922", - "sha256:95dd7f261bb76948b52a5330ba5202b91a26fbac13ad0e9fc8a3ac04752058c7", - "sha256:a74fbcdb2a0d46fe00504f571a2a540532f4c188e6ccf26f1f178480117b33c4", - "sha256:a983e441a00a9d57a4d7c91b3116a37ae602907a7618b882c8013b5762e80574", - "sha256:ab8de0d091acbf778f74286f4989cf3d1528336af1b59f3e5d2ebca8b5fe49e1", - "sha256:aeb57c421b34af8f9fe830e1955bf493a86a7996cc1338fe41b30047d16e962c", - "sha256:ce785cf81a7bdade534297ef9e490ddff800d956625020ab2ec2780a556c313e", - "sha256:d0d651aa754ef58d75cec6edfbd21259d93810b73f6ec246436a21b7841908de" - ], - "markers": "python_version >= '3.7'", - "version": "==41.0.3" - }, "distlib": { "hashes": [ "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057", @@ -444,6 +341,7 @@ "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81", "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec" ], + "index": "pypi", "markers": "python_version >= '3.7'", "version": "==3.12.2" }, @@ -452,7 +350,6 @@ "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b", "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==3.9.2" }, "flaky": { @@ -460,7 +357,6 @@ "sha256:3ad100780721a1911f57a165809b7ea265a7863305acb66708220820caf8aa0d", "sha256:d6eda73cab5ae7364504b7c44670f70abed9e75f77dd116352f662817592ec9c" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==3.7.0" }, "gunicorn": { @@ -468,7 +364,7 @@ "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0", "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033" ], - "markers": "sys_platform == 'linux'", + "markers": "python_version >= '3.5' and sys_platform == 'linux'", "version": "==21.2.0" }, "identify": { @@ -500,7 +396,7 @@ "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4", "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5" ], - "markers": "python_version < '3.8'", + "markers": "python_version >= '3.7'", "version": "==6.7.0" }, "importlib-resources": { @@ -543,14 +439,6 @@ "markers": "python_version >= '3.7'", "version": "==3.2.3" }, - "jeepney": { - "hashes": [ - "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806", - "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755" - ], - "markers": "sys_platform == 'linux'", - "version": "==0.8.0" - }, "jinja2": { "hashes": [ "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", @@ -666,7 +554,6 @@ "sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744", "sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d" ], - "markers": "python_version >= '3.6'", "version": "==5.1.0" }, "more-itertools": { @@ -725,7 +612,6 @@ "sha256:c66d3347a4858643875ef959d8ba7a269d5964bfb690b0dd998b8f39da930be2", "sha256:d4a3dbb93c53373ee9a0ba055e4858c44169b204b912e49d003ead95db9a9bca" ], - "markers": "python_version >= '3.7'", "version": "==0.4" }, "pathspec": { @@ -773,6 +659,7 @@ "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849", "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3" ], + "index": "pypi", "markers": "python_version >= '3.7'", "version": "==1.2.0" }, @@ -793,13 +680,6 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.7.0" }, - "pycparser": { - "hashes": [ - "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", - "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" - ], - "version": "==2.21" - }, "pyenchant": { "hashes": [ "sha256:0314d162b7af83adc500f5aff850c91466129363ca8c4d79a8b8d99253346204", @@ -865,7 +745,6 @@ "sha256:c07ca07404c612f8abbe22294b23c368e2e5104b521c1790195561f37e1ac3d9", "sha256:f6f50101443ce70ad325ceb4473c4255e9d74e3c7cd0ef827309dfa4c0d975c6" ], - "markers": "python_version >= '3.6'", "version": "==2.1.0" }, "pytest-xdist": { @@ -873,7 +752,6 @@ "sha256:d5ee0520eb1b7bcca50a60a518ab7a7707992812c578198f8b44fdfac78e8c93", "sha256:ff9daa7793569e6a68544850fd3927cd257cc03a7ef76c95e86915355e82b5f2" ], - "markers": "python_version >= '3.7'", "version": "==3.3.1" }, "pytz": { @@ -884,6 +762,14 @@ "index": "pypi", "version": "==2023.3" }, + "pywin32-ctypes": { + "hashes": [ + "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60", + "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7" + ], + "markers": "sys_platform == 'win32'", + "version": "==0.2.2" + }, "pyyaml": { "hashes": [ "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", @@ -981,14 +867,6 @@ "markers": "python_full_version >= '3.7.0'", "version": "==13.5.2" }, - "secretstorage": { - "hashes": [ - "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", - "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99" - ], - "markers": "sys_platform == 'linux'", - "version": "==3.3.3" - }, "setuptools": { "hashes": [ "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f", @@ -1099,7 +977,6 @@ "hashes": [ "sha256:08c22c9c03b28a140fe3ec5064b53a5288279f22e596ca06b0be698d50c93cf2" ], - "markers": "sys_platform == 'linux'", "version": "==0.10.0" }, "tomli": { @@ -1116,7 +993,6 @@ "sha256:da552f29192b3c2b04d630133f194c98e9f14f0558669d427708e203fea4d0a5", "sha256:fc29bd5ab4727c8dacfbe636f7fb5dc53b99805b62da1c96b214836159ff70c1" ], - "markers": "python_version >= '3.7'", "version": "==23.6.0" }, "twine": { @@ -1213,7 +1089,7 @@ "sha256:7500c9625927c8ec60f54377d590f67b30c8e70ef4b8894214ac6e4cad233d2a", "sha256:780a4082c5fbc0fde6a2fcfe5e26e6efc1e8f425730863c04085769781f51eba" ], - "markers": "sys_platform == 'win32'", + "markers": "python_full_version >= '3.7.0' and sys_platform == 'win32'", "version": "==2.1.2" }, "webencodings": { diff --git a/news/5892.feature.rst b/news/5892.feature.rst new file mode 100644 index 00000000..80b0e512 --- /dev/null +++ b/news/5892.feature.rst @@ -0,0 +1 @@ +Top level Pipfile sys_platform markers should be transitive; adds top level platform_machine entries that are also transitive. Marker entries continue to operate the same as before. diff --git a/pipenv/utils/markers.py b/pipenv/utils/markers.py index dcb3384a..21c1c8a5 100644 --- a/pipenv/utils/markers.py +++ b/pipenv/utils/markers.py @@ -54,6 +54,8 @@ class PipenvMarkers(BaseModel): marker_strings.append(pipfile.get("markers")) if pipfile.get("sys_platform"): marker_strings.append(f"sys_platform '{pipfile['sys_platform']}'") + if pipfile.get("platform_machine"): + marker_strings.append(f"platform_machine '{pipfile['platform_machine']}'") markers = set() for marker in marker_strings: markers.add(marker) diff --git a/pipenv/utils/resolver.py b/pipenv/utils/resolver.py index bcdef0cc..83964d7d 100644 --- a/pipenv/utils/resolver.py +++ b/pipenv/utils/resolver.py @@ -447,9 +447,49 @@ class Resolver: self.resolved_tree.update(self.results) return self.resolved_tree + def _get_pipfile_markers(self, pipfile_entry): + sys_platform = pipfile_entry.get("sys_platform") + platform_machine = pipfile_entry.get("platform_machine") + markers = pipfile_entry.get("markers") + + if sys_platform: + sys_platform = f"sys_platform {sys_platform}" + if platform_machine: + platform_machine = f"platform_machine {platform_machine}" + + combined_markers = [ + f"({marker})" + for marker in (sys_platform, markers, platform_machine) + if marker + ] + + return " and ".join(combined_markers).strip() + + def _fold_markers(self, dependency_tree, install_req): + comes_from = dependency_tree[install_req.name] + + if comes_from == "Pipfile": + pipfile_entry = self.pipfile_entries.get(install_req.name) + if pipfile_entry and isinstance(pipfile_entry, dict): + return self._get_pipfile_markers(pipfile_entry) + else: + markers = self._fold_markers(dependency_tree, comes_from) + if markers: + self.markers_lookup[install_req.name] = markers + return markers + def resolve_constraints(self): from .markers import marker_from_specifier + # Build mapping of where package originates from + comes_from = {} + for result in self.resolved_tree: + if isinstance(result.comes_from, InstallRequirement): + comes_from[result.name] = result.comes_from + else: + comes_from[result.name] = "Pipfile" + + # Build up the results tree with markers new_tree = set() for result in self.resolved_tree: if result.markers: @@ -475,6 +515,11 @@ class Resolver: err=True, ) new_tree.add(result) + + # Fold markers + for result in new_tree: + self._fold_markers(comes_from, result) + self.resolved_tree = new_tree def collect_hashes(self, ireq): From 3b62d9119e70d9ba3f66429d865ccffbff5382e3 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Fri, 1 Sep 2023 05:45:37 -0400 Subject: [PATCH 09/12] minor doc build linting --- CHANGELOG.rst | 38 ++++++++++++++++---------------------- pipenv/cli/options.py | 1 + pipenv/environments.py | 2 +- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a64395c5..1f59cb7f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,8 +1,5 @@ 2023.8.28 (2023-08-28) ====================== -Pipenv 2023.8.28 (2023-08-28) -============================= - Bug Fixes --------- @@ -14,9 +11,6 @@ Bug Fixes 2023.8.26 (2023-08-26) ====================== -Pipenv 2023.8.26 (2023-08-26) -============================= - Bug Fixes --------- @@ -29,9 +23,6 @@ Bug Fixes 2023.8.25 (2023-08-25) ====================== -Pipenv 2023.8.25 (2023-08-25) -============================= - Bug Fixes --------- @@ -434,8 +425,8 @@ Vendored Libraries - Vendor in ``pip==22.3.1`` which is currently the latest version of ``pip``. `#5520 `_ - * Bump version of requirementslib to 2.2.1 - * Bump version of vistir to 0.7.5 - * Bump version of colorama to 0.4.6 `#5522 `_ + * Bump version of vistir to 0.7.5 + * Bump version of colorama to 0.4.6 `#5522 `_ - Bump plette version to 0.4.4 `#5539 `_ @@ -482,9 +473,9 @@ Vendored Libraries ------------------ - * Drop unused code from cerberus - * Drop unused module wheel `#5467 `_ + * Drop unused module wheel `#5467 `_ - * Replace yaspin spinner with rich spinner. - * Bump vistir version to 0.7.4 `#5468 `_ + * Bump vistir version to 0.7.4 `#5468 `_ - Bump version of requirementslib to 2.2.0 Drop yaspin which is no longer used. Bump vistir to version 0.7.4 @@ -886,11 +877,10 @@ Vendored Libraries ------------------ - * Rename patched ``notpip`` to ``pip`` in order to be clear that its a patched version of pip. - * Remove the part of _post_pip_import.patch that overrode the standalone pip to be the user installed pip, - now we fully rely on our vendored and patched ``pip``, even for all types of installs. + * Remove the part of _post_pip_import.patch that overrode the standalone pip to be the user installed pip, now we fully rely on our vendored and patched ``pip``, even for all types of installs. * Vendor in the next newest version of ``pip==22.2`` * Modify patch for ``pipdeptree`` to not use ``pip-shims`` `#5188 `_ -- * Remove vendored ``urllib3`` in favor of using it from vendored version in ``pip._vendor`` `#5215 `_ + * Remove vendored ``urllib3`` in favor of using it from vendored version in ``pip._vendor`` `#5215 `_ Removals and Deprecations ------------------------- @@ -1605,11 +1595,11 @@ Vendored Libraries - Update vendored dependencies and invocations - Update vendored and patched dependencies - - Update patches on ``piptools``, ``pip``, ``pip-shims``, ``tomlkit` + - Update patches on ``piptools``, ``pip``, ``pip-shims``, ``tomlkit`` - Fix invocations of dependencies - - Fix custom ``InstallCommand` instantiation - - Update ``PackageFinder` usage - - Fix ``Bool` stringify attempts from ``tomlkit` + - Fix custom ``InstallCommand`` instantiation + - Update ``PackageFinder`` usage + - Fix ``Bool`` stringify attempts from ``tomlkit`` Updated vendored dependencies: - **attrs**: ```18.2.0`` => ```19.1.0`` @@ -1992,7 +1982,9 @@ Bug Fixes - ``requirementslib 1.1.16 => 1.1.17`` - ``shellingham 1.2.4 => 1.2.6`` - ``tomlkit 0.4.2 => 0.4.4`` - - ``vistir 0.1.4 => 0.1.6`` `#2802 `_, + - ``vistir 0.1.4 => 0.1.6`` + + `#2802 `_, `#2867 `_, `#2880 `_ @@ -2046,7 +2038,9 @@ Vendored Libraries - ``requirementslib 1.1.16 => 1.1.17`` - ``shellingham 1.2.4 => 1.2.6`` - ``tomlkit 0.4.2 => 0.4.4`` - - ``vistir 0.1.4 => 0.1.6`` `#2902 `_, + - ``vistir 0.1.4 => 0.1.6`` + + `#2902 `_, `#2935 `_ diff --git a/pipenv/cli/options.py b/pipenv/cli/options.py index 78c30d2d..701cf9ed 100644 --- a/pipenv/cli/options.py +++ b/pipenv/cli/options.py @@ -502,6 +502,7 @@ def skip_lock_option(f): default=False, expose_value=True, envvar="PIPENV_SKIP_LOCK", + help="Install from Pipfile bypassing lock mechanisms.", callback=callback, type=click_types.BOOL, show_envvar=True, diff --git a/pipenv/environments.py b/pipenv/environments.py index 03af5314..325b63ac 100644 --- a/pipenv/environments.py +++ b/pipenv/environments.py @@ -293,7 +293,7 @@ class Setting: """ When set True, will create or use the ``.venv`` in your project directory. When Set False, will ignore the .venv in your project directory even if it exists. If unset (default), will use the .venv of project directory should it exist, otherwise - will create new virtual environments in a global location. + will create new virtual environments in a global location. """ self.PIPENV_VERBOSE = bool(get_from_env("VERBOSE", check_for_negation=False)) From 246f795a119b45ac06d2fff2ed6f32a92acb0937 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 1 Sep 2023 10:04:53 +0000 Subject: [PATCH 10/12] Bumped version. Signed-off-by: github-actions[bot] --- pipenv/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pipenv/__version__.py b/pipenv/__version__.py index 529af700..c8bdf0fb 100644 --- a/pipenv/__version__.py +++ b/pipenv/__version__.py @@ -2,4 +2,4 @@ # // ) ) / / // ) ) //___) ) // ) ) || / / # //___/ / / / //___/ / // // / / || / / # // / / // ((____ // / / ||/ / -__version__ = "2023.8.29.dev0" +__version__ = "2023.9.1.dev1" From fd76fd84cd417d2dc35e59f0da69810012c7a6c8 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Fri, 1 Sep 2023 10:32:59 -0400 Subject: [PATCH 11/12] merge with main --- CHANGELOG.rst | 20 ++++++++++++++++++++ news/5892.feature.rst | 1 - news/5895.bugfix.rst | 1 - news/5896.bugfix.rst | 1 - news/5897.bugfix.rst | 1 - news/5898.bugfix.rst | 1 - pipenv/__version__.py | 2 +- 7 files changed, 21 insertions(+), 6 deletions(-) delete mode 100644 news/5892.feature.rst delete mode 100644 news/5895.bugfix.rst delete mode 100644 news/5896.bugfix.rst delete mode 100644 news/5897.bugfix.rst delete mode 100644 news/5898.bugfix.rst diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1f59cb7f..613dd4f9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,23 @@ +2023.9.1 (2023-09-01) +===================== +Pipenv 2023.9.1 (2023-09-01) +============================ + + +Features & Improvements +----------------------- + +- Top level Pipfile sys_platform markers should be transitive; adds top level platform_machine entries that are also transitive. Marker entries continue to operate the same as before. `#5892 `_ + +Bug Fixes +--------- + +- Apply patch for install_search_all_sources = True functionality. `#5895 `_ +- Relative paths improvements for editable installs. `#5896 `_ +- Set log level in resolver to WARN when verbose is not passed. `#5897 `_ +- Handle more variations in private index html to improve hash collection. `#5898 `_ + + 2023.8.28 (2023-08-28) ====================== diff --git a/news/5892.feature.rst b/news/5892.feature.rst deleted file mode 100644 index 80b0e512..00000000 --- a/news/5892.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Top level Pipfile sys_platform markers should be transitive; adds top level platform_machine entries that are also transitive. Marker entries continue to operate the same as before. diff --git a/news/5895.bugfix.rst b/news/5895.bugfix.rst deleted file mode 100644 index 9eeed1f8..00000000 --- a/news/5895.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Apply patch for install_search_all_sources = True functionality. diff --git a/news/5896.bugfix.rst b/news/5896.bugfix.rst deleted file mode 100644 index 8fb6083a..00000000 --- a/news/5896.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Relative paths improvements for editable installs. diff --git a/news/5897.bugfix.rst b/news/5897.bugfix.rst deleted file mode 100644 index 85844566..00000000 --- a/news/5897.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Set log level in resolver to WARN when verbose is not passed. diff --git a/news/5898.bugfix.rst b/news/5898.bugfix.rst deleted file mode 100644 index 0b9c5c26..00000000 --- a/news/5898.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Handle more variations in private index html to improve hash collection. diff --git a/pipenv/__version__.py b/pipenv/__version__.py index c8bdf0fb..3ad7a6ea 100644 --- a/pipenv/__version__.py +++ b/pipenv/__version__.py @@ -2,4 +2,4 @@ # // ) ) / / // ) ) //___) ) // ) ) || / / # //___/ / / / //___/ / // // / / || / / # // / / // ((____ // / / ||/ / -__version__ = "2023.9.1.dev1" +__version__ = "2023.9.1" From 440880a34206396ab68e463409811c41797a12fa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 1 Sep 2023 14:36:17 +0000 Subject: [PATCH 12/12] Bumped version. Signed-off-by: github-actions[bot] --- pipenv/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pipenv/__version__.py b/pipenv/__version__.py index 3ad7a6ea..c8960a6e 100644 --- a/pipenv/__version__.py +++ b/pipenv/__version__.py @@ -2,4 +2,4 @@ # // ) ) / / // ) ) //___) ) // ) ) || / / # //___/ / / / //___/ / // // / / || / / # // / / // ((____ // / / ||/ / -__version__ = "2023.9.1" +__version__ = "2023.9.2.dev0"