pypi-simple
Advanced tools
+15
-0
@@ -0,1 +1,16 @@ | ||
| v1.5.0 (2024-02-24) | ||
| ------------------- | ||
| - **Bugfix**: Fix parsing of "true" `data-core-metadata` attributes and | ||
| handling of the attribute's absence (contributed by | ||
| [@thatch](https://github.com/thatch)) | ||
| - `DistributionPackage.has_metadata` will now be `None` if this attribute | ||
| was absent in the HTML returned by PyPI. Previously, it would be `False` | ||
| under this circumstance. | ||
| - Added `PyPISimple.get_package_metadata_bytes()` (contributed by | ||
| [@thatch](https://github.com/thatch)) | ||
| - `PyPISimple.get_package_metadata()` now always decodes responses as UTF-8 | ||
| (contributed by [@thatch](https://github.com/thatch)) | ||
| - Request methods now take optional `headers` arguments (contributed by | ||
| [@thatch](https://github.com/thatch)) | ||
| v1.4.1 (2024-01-30) | ||
@@ -2,0 +17,0 @@ ------------------- |
+20
-0
@@ -6,2 +6,22 @@ .. currentmodule:: pypi_simple | ||
| v1.5.0 (2024-02-24) | ||
| ------------------- | ||
| - **Bugfix**: Fix parsing of "true" ``data-core-metadata`` attributes and | ||
| handling of the attribute's absence (contributed by `@thatch | ||
| <https://github.com/thatch>`_) | ||
| - `DistributionPackage.has_metadata` will now be `None` if this attribute was | ||
| absent in the HTML returned by PyPI. Previously, it would be `False` under | ||
| this circumstance. | ||
| - Added `PyPISimple.get_package_metadata_bytes()` (contributed by `@thatch | ||
| <https://github.com/thatch>`_) | ||
| - `PyPISimple.get_package_metadata()` now always decodes responses as UTF-8 | ||
| (contributed by `@thatch <https://github.com/thatch>`_) | ||
| - Request methods now take optional ``headers`` arguments (contributed by | ||
| `@thatch <https://github.com/thatch>`_) | ||
| v1.4.1 (2024-01-30) | ||
@@ -8,0 +28,0 @@ ------------------- |
+1
-1
| Metadata-Version: 2.1 | ||
| Name: pypi-simple | ||
| Version: 1.4.1 | ||
| Version: 1.5.0 | ||
| Summary: PyPI Simple Repository API client library | ||
@@ -5,0 +5,0 @@ Project-URL: Source Code, https://github.com/jwodder/pypi-simple |
@@ -17,3 +17,3 @@ """ | ||
| __version__ = "1.4.1" | ||
| __version__ = "1.5.0" | ||
| __author__ = "John Thorvald Wodder II" | ||
@@ -20,0 +20,0 @@ __author_email__ = "pypi-simple@varonathe.org" |
@@ -146,2 +146,3 @@ from __future__ import annotations | ||
| metadata_digests: Optional[dict[str, str]] | ||
| has_metadata = None | ||
| if mddigest is not None: | ||
@@ -152,2 +153,3 @@ metadata_digests = {} | ||
| metadata_digests[m[1]] = m[2] | ||
| has_metadata = bool(m) or mddigest.lower() == "true" | ||
| else: | ||
@@ -168,3 +170,3 @@ metadata_digests = None | ||
| metadata_digests=metadata_digests, | ||
| has_metadata=metadata_digests is not None, | ||
| has_metadata=has_metadata, | ||
| ) | ||
@@ -171,0 +173,0 @@ |
+115
-17
@@ -102,2 +102,3 @@ from __future__ import annotations | ||
| accept: Optional[str] = None, | ||
| headers: Optional[dict[str, str]] = None, | ||
| ) -> IndexPage: | ||
@@ -117,2 +118,6 @@ """ | ||
| .. versionchanged:: 1.5.0 | ||
| ``headers`` parameter added | ||
| :param timeout: optional timeout to pass to the ``requests`` call | ||
@@ -124,2 +129,4 @@ :type timeout: float | tuple[float,float] | None | ||
| defaults to the value supplied on client instantiation | ||
| :param Optional[dict[str, str]] headers: | ||
| Custom headers to provide for the request. | ||
| :rtype: IndexPage | ||
@@ -133,4 +140,9 @@ :raises requests.HTTPError: if the repository responds with an HTTP | ||
| """ | ||
| request_headers = {"Accept": accept or self.accept} | ||
| if headers: | ||
| request_headers.update(headers) | ||
| r = self.s.get( | ||
| self.endpoint, timeout=timeout, headers={"Accept": accept or self.accept} | ||
| self.endpoint, | ||
| timeout=timeout, | ||
| headers=request_headers, | ||
| ) | ||
@@ -145,2 +157,3 @@ r.raise_for_status() | ||
| accept: Optional[str] = None, | ||
| headers: Optional[dict[str, str]] = None, | ||
| ) -> Iterator[str]: | ||
@@ -172,2 +185,6 @@ """ | ||
| .. versionchanged:: 1.5.0 | ||
| ``headers`` parameter added | ||
| :param int chunk_size: how many bytes to read from the response at a | ||
@@ -181,2 +198,4 @@ time | ||
| defaults to the value supplied on client instantiation | ||
| :param Optional[dict[str, str]] headers: | ||
| Custom headers to provide for the request. | ||
| :rtype: Iterator[str] | ||
@@ -190,2 +209,5 @@ :raises requests.HTTPError: if the repository responds with an HTTP | ||
| """ | ||
| request_headers = {"Accept": accept or self.accept} | ||
| if headers: | ||
| request_headers.update(headers) | ||
| with self.s.get( | ||
@@ -195,3 +217,3 @@ self.endpoint, | ||
| timeout=timeout, | ||
| headers={"Accept": accept or self.accept}, | ||
| headers=request_headers, | ||
| ) as r: | ||
@@ -217,2 +239,3 @@ r.raise_for_status() | ||
| accept: Optional[str] = None, | ||
| headers: Optional[dict[str, str]] = None, | ||
| ) -> ProjectPage: | ||
@@ -232,2 +255,6 @@ """ | ||
| .. versionchanged:: 1.5.0 | ||
| ``headers`` parameter added | ||
| :param str project: The name of the project to fetch information on. | ||
@@ -241,2 +268,4 @@ The name does not need to be normalized. | ||
| defaults to the value supplied on client instantiation | ||
| :param Optional[dict[str, str]] headers: | ||
| Custom headers to provide for the request. | ||
| :rtype: ProjectPage | ||
@@ -252,4 +281,7 @@ :raises NoSuchProjectError: if the repository responds with a 404 error | ||
| """ | ||
| request_headers = {"Accept": accept or self.accept} | ||
| if headers: | ||
| request_headers.update(headers) | ||
| url = self.get_project_url(project) | ||
| r = self.s.get(url, timeout=timeout, headers={"Accept": accept or self.accept}) | ||
| r = self.s.get(url, timeout=timeout, headers=request_headers) | ||
| if r.status_code == 404: | ||
@@ -278,2 +310,3 @@ raise NoSuchProjectError(project, url) | ||
| timeout: float | tuple[float, float] | None = None, | ||
| headers: Optional[dict[str, str]] = None, | ||
| ) -> None: | ||
@@ -293,2 +326,6 @@ """ | ||
| .. versionchanged:: 1.5.0 | ||
| ``headers`` parameter added | ||
| :param DistributionPackage pkg: the distribution package to download | ||
@@ -306,2 +343,4 @@ :param path: | ||
| :type timeout: float | tuple[float,float] | None | ||
| :param Optional[dict[str, str]] headers: | ||
| Custom headers to provide for the request. | ||
| :raises requests.HTTPError: if the repository responds with an HTTP | ||
@@ -323,3 +362,3 @@ error code | ||
| digester = NullDigestChecker() | ||
| with self.s.get(pkg.url, stream=True, timeout=timeout) as r: | ||
| with self.s.get(pkg.url, stream=True, timeout=timeout, headers=headers) as r: | ||
| r.raise_for_status() | ||
@@ -348,3 +387,3 @@ try: | ||
| def get_package_metadata( | ||
| def get_package_metadata_bytes( | ||
| self, | ||
@@ -354,9 +393,12 @@ pkg: DistributionPackage, | ||
| timeout: float | tuple[float, float] | None = None, | ||
| ) -> str: | ||
| headers: Optional[dict[str, str]] = None, | ||
| ) -> bytes: | ||
| """ | ||
| .. versionadded:: 1.3.0 | ||
| .. versionadded:: 1.5.0 | ||
| Retrieve the `distribution metadata`_ for the given | ||
| `DistributionPackage`. The metadata can then be parsed with, for | ||
| example, |the packaging package|_. | ||
| `DistributionPackage` as raw bytes. This method is lower-level than | ||
| `PyPISimple.get_package_metadata()` and is most appropriate if you want | ||
| to defer interpretation of the data (e.g., if you're just writing to a | ||
| file) or want to customize the handling of non-UTF-8 data. | ||
@@ -370,8 +412,2 @@ Not all packages have distribution metadata available for download; the | ||
| .. _distribution metadata: | ||
| https://packaging.python.org/en/latest/specifications/core-metadata/ | ||
| .. |the packaging package| replace:: the ``packaging`` package | ||
| .. _the packaging package: | ||
| https://packaging.pypa.io/en/stable/metadata.html | ||
| :param DistributionPackage pkg: | ||
@@ -383,2 +419,5 @@ the distribution package to retrieve the metadata of | ||
| :type timeout: float | tuple[float,float] | None | ||
| :param Optional[dict[str, str]] headers: | ||
| Custom headers to provide for the request. | ||
| :rtype: bytes | ||
@@ -401,3 +440,3 @@ :raises NoMetadataError: | ||
| digester = NullDigestChecker() | ||
| r = self.s.get(pkg.metadata_url, timeout=timeout) | ||
| r = self.s.get(pkg.metadata_url, timeout=timeout, headers=headers) | ||
| if r.status_code == 404: | ||
@@ -408,5 +447,64 @@ raise NoMetadataError(pkg.filename) | ||
| digester.finalize() | ||
| return r.text | ||
| return r.content | ||
| def get_package_metadata( | ||
| self, | ||
| pkg: DistributionPackage, | ||
| verify: bool = True, | ||
| timeout: float | tuple[float, float] | None = None, | ||
| headers: Optional[dict[str, str]] = None, | ||
| ) -> str: | ||
| """ | ||
| .. versionadded:: 1.3.0 | ||
| Retrieve the `distribution metadata`_ for the given | ||
| `DistributionPackage` and decode it as UTF-8. The metadata can then be | ||
| parsed with, for example, |the packaging package|_. | ||
| Not all packages have distribution metadata available for download; the | ||
| `DistributionPackage.has_metadata` attribute can be used to check | ||
| whether the repository reported the availability of the metadata. This | ||
| method will always attempt to download metadata regardless of the value | ||
| of `~DistributionPackage.has_metadata`; if the server replies with a | ||
| 404, a `NoMetadataError` is raised. | ||
| .. _distribution metadata: | ||
| https://packaging.python.org/en/latest/specifications/core-metadata/ | ||
| .. |the packaging package| replace:: the ``packaging`` package | ||
| .. _the packaging package: | ||
| https://packaging.pypa.io/en/stable/metadata.html | ||
| .. versionchanged:: 1.5.0 | ||
| ``headers`` parameter added | ||
| :param DistributionPackage pkg: | ||
| the distribution package to retrieve the metadata of | ||
| :param bool verify: | ||
| whether to verify the metadata's digests against the retrieved data | ||
| :param timeout: optional timeout to pass to the ``requests`` call | ||
| :type timeout: float | tuple[float,float] | None | ||
| :param Optional[dict[str, str]] headers: | ||
| Custom headers to provide for the request. | ||
| :rtype: str | ||
| :raises NoMetadataError: | ||
| if the repository responds with a 404 error code | ||
| :raises requests.HTTPError: if the repository responds with an HTTP | ||
| error code other than 404 | ||
| :raises NoDigestsError: | ||
| if ``verify`` is true and the given package's metadata does not | ||
| have any digests with known algorithms | ||
| :raises DigestMismatchError: | ||
| if ``verify`` is true and the digest of the downloaded data does | ||
| not match the expected value | ||
| """ | ||
| return self.get_package_metadata_bytes( | ||
| pkg, | ||
| verify, | ||
| timeout, | ||
| headers, | ||
| ).decode("utf-8", "surrogateescape") | ||
| class NoSuchProjectError(Exception): | ||
@@ -413,0 +511,0 @@ """ |
+105
-17
@@ -94,3 +94,3 @@ from __future__ import annotations | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -111,3 +111,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -128,3 +128,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -145,3 +145,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -162,3 +162,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -179,3 +179,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -229,3 +229,3 @@ ], | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -246,3 +246,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -307,3 +307,3 @@ ], | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -352,3 +352,3 @@ ], | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -400,3 +400,3 @@ ], | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -644,3 +644,3 @@ ], | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ) | ||
@@ -675,3 +675,3 @@ dest = tmp_path / str(pkg.project) / pkg.filename | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ) | ||
@@ -708,3 +708,3 @@ dest = tmp_path / str(pkg.project) / pkg.filename | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ) | ||
@@ -746,3 +746,3 @@ dest = tmp_path / str(pkg.project) / pkg.filename | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ) | ||
@@ -792,3 +792,3 @@ dest = tmp_path / str(pkg.project) / pkg.filename | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ) | ||
@@ -849,3 +849,3 @@ dest = tmp_path / str(pkg.project) / pkg.filename | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ) | ||
@@ -864,1 +864,89 @@ dest = tmp_path / str(pkg.project) / pkg.filename | ||
| assert spy.updates == [65535] * (size // 65535) + [size % 65535] | ||
| @responses.activate | ||
| def test_metadata_encoding() -> None: | ||
| responses.add( | ||
| method=responses.GET, | ||
| url="https://test.nil/simple/packages/example-0.0.1-py3-none-any.whl.metadata", | ||
| body=b"\xe2\x98\x83", # unicode snowman | ||
| ) | ||
| responses.add( | ||
| method=responses.GET, | ||
| url="https://test.nil/simple/packages/example-0.0.2-py3-none-any.whl.metadata", | ||
| body=b"\xff\xfe\x03\x26", # unicode snowman in utf-16 | ||
| ) | ||
| with PyPISimple("https://test.nil/simple/") as simple: | ||
| pkg = DistributionPackage( | ||
| filename="example-0.0.1-py3-none-any.whl", | ||
| project="example", | ||
| version="0.0.1", | ||
| package_type="wheel", | ||
| url="https://test.nil/simple/packages/example-0.0.1-py3-none-any.whl", | ||
| digests={}, | ||
| requires_python=None, | ||
| has_sig=None, | ||
| has_metadata=True, | ||
| metadata_digests={"sha1": "2686137311c038a99622242fdb662b88c221c08d"}, | ||
| ) | ||
| assert simple.get_package_metadata_bytes(pkg) == b"\xe2\x98\x83" | ||
| assert simple.get_package_metadata(pkg) == "\u2603" | ||
| pkg = DistributionPackage( | ||
| filename="example-0.0.2-py3-none-any.whl", | ||
| project="example", | ||
| version="0.0.2", | ||
| package_type="wheel", | ||
| url="https://test.nil/simple/packages/example-0.0.2-py3-none-any.whl", | ||
| digests={}, | ||
| requires_python=None, | ||
| has_sig=None, | ||
| has_metadata=True, | ||
| metadata_digests={"sha1": "7381ac0d9ddb35e4074acfd9cf72ea47314da70b"}, | ||
| ) | ||
| assert simple.get_package_metadata_bytes(pkg) == b"\xff\xfe\x03\x26" | ||
| assert simple.get_package_metadata(pkg) == "\udcff\udcfe\u0003\u0026" | ||
| @responses.activate | ||
| def test_custom_headers_get_index_page() -> None: | ||
| with (DATA_DIR / "simple01.html").open() as fp: | ||
| responses.add( | ||
| method=responses.GET, | ||
| url="https://test.nil/simple/", | ||
| body=fp.read(), | ||
| content_type="text/html", | ||
| match=[responses.matchers.header_matcher({"X-Custom": "foo"})], | ||
| ) | ||
| with PyPISimple("https://test.nil/simple/") as simple: | ||
| # Just check that the method returns successfully | ||
| simple.get_index_page(headers={"X-Custom": "foo"}) | ||
| @responses.activate | ||
| def test_custom_headers_stream_project_names() -> None: | ||
| with (DATA_DIR / "simple01.html").open() as fp: | ||
| responses.add( | ||
| method=responses.GET, | ||
| url="https://test.nil/simple/", | ||
| body=fp.read(), | ||
| content_type="text/html", | ||
| match=[responses.matchers.header_matcher({"X-Custom": "foo"})], | ||
| ) | ||
| with PyPISimple("https://test.nil/simple/") as simple: | ||
| # Just check that the method returns successfully | ||
| list(simple.stream_project_names(headers={"X-Custom": "foo"})) | ||
| @responses.activate | ||
| def test_custom_headers_get_project_page() -> None: | ||
| with (DATA_DIR / "aws-adfs-ebsco.html").open() as fp: | ||
| responses.add( | ||
| method=responses.GET, | ||
| url="https://test.nil/simple/aws-adfs-ebsco/", | ||
| body=fp.read(), | ||
| content_type="text/html", | ||
| match=[responses.matchers.header_matcher({"X-Custom": "foo"})], | ||
| ) | ||
| with PyPISimple("https://test.nil/simple/") as simple: | ||
| simple.get_project_page("aws-adfs-ebsco", headers={"X-Custom": "foo"}) |
@@ -87,3 +87,3 @@ from __future__ import annotations | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -127,3 +127,3 @@ ), | ||
| "data-gpg-sig": "false", | ||
| "data-core-metadata": "sha256=true", | ||
| "data-core-metadata": "true", | ||
| }, | ||
@@ -130,0 +130,0 @@ ), |
@@ -50,3 +50,3 @@ from datetime import datetime, timezone | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -67,3 +67,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -84,3 +84,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -101,3 +101,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -118,3 +118,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -135,3 +135,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -152,3 +152,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -169,3 +169,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -186,3 +186,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -203,3 +203,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -220,3 +220,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -237,3 +237,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -267,3 +267,3 @@ ], | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -284,3 +284,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -301,3 +301,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -318,3 +318,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -348,3 +348,3 @@ ], | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -365,3 +365,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -382,3 +382,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -399,3 +399,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -416,3 +416,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -446,3 +446,3 @@ ], | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -463,3 +463,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -493,3 +493,3 @@ ], | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -510,3 +510,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -548,3 +548,3 @@ ], | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -565,3 +565,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -582,3 +582,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -599,3 +599,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -616,3 +616,3 @@ DistributionPackage( | ||
| metadata_digests=None, | ||
| has_metadata=False, | ||
| has_metadata=None, | ||
| ), | ||
@@ -619,0 +619,0 @@ ], |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
284856
3.18%5771
2.92%