summaryrefslogtreecommitdiff
diff options
authorAndrius Merkys <merkys@debian.org>2025-09-02 02:16:03 -0400
committergit-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com>2025-09-02 10:41:02 +0000
commitd0d6ef6c5cdc775f8a918abf5fbe2022ed1cfe8d (patch)
treec6ad25dd6bd7b78d8e81b552deb9171c3a0b3d60
parentfab4ffdb489a09133ae2ab6d796ec173dbcbdcc0 (diff)
Imported using git-ubuntu import.
Notes
Notes: * New upstream version 1.7.0 * Bump copyright years.
-rw-r--r--CHANGES.md12
-rw-r--r--crossref/restful.py181
-rw-r--r--debian/changelog7
-rw-r--r--debian/control1
-rw-r--r--debian/copyright2
-rw-r--r--debian/patches/disable-network-tests.patch21
-rw-r--r--debian/patches/series1
-rwxr-xr-xdebian/rules1
-rw-r--r--poetry.lock477
-rw-r--r--pyproject.toml2
-rw-r--r--tests/test_integration.py87
-rw-r--r--tests/test_restful.py166
-rw-r--r--tests/test_validators.py119
13 files changed, 643 insertions, 434 deletions
diff --git a/CHANGES.md b/CHANGES.md
index a330bc2..244a894 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,6 +1,16 @@
+# 1.7.0
+
+* Remove support for Python 2.X
+* Allow skipping SSL verification using a requests library
+* Replicate configurations to the Works endpoint when using works from Journals, Prefixes, Members,
+ Funders and Types, classes
+* Using pytests as a test framework
+* Including integration tests
+* Upgrading dependencies
+
# 1.6.1
-* Fix Depositor including timeout attribute to it
+* Fix Depositor including a timeout attribute to it
# 1.6.0
diff --git a/crossref/restful.py b/crossref/restful.py
index 67fdc9a..338e434 100644
--- a/crossref/restful.py
+++ b/crossref/restful.py
@@ -1,5 +1,3 @@
-from __future__ import annotations
-
import contextlib
import typing
from time import sleep
@@ -29,9 +27,10 @@ class UrlSyntaxError(CrossrefAPIError, ValueError):
class HTTPRequest:
- def __init__(self, throttle=True):
+ def __init__(self, throttle=True, verify=True):
self.throttle = throttle
self.rate_limits = {"x-rate-limit-limit": 50, "x-rate-limit-interval": 1}
+ self.verify = verify # Disable SSL verification by default
def _update_rate_limits(self, headers):
@@ -65,7 +64,6 @@ class HTTPRequest:
only_headers=False,
custom_header=None,
):
-
if only_headers is True:
return requests.head(endpoint, timeout=2)
@@ -73,11 +71,17 @@ class HTTPRequest:
headers = custom_header if custom_header else {"user-agent": str(Etiquette())}
if method == "post":
- result = action(endpoint, data=data, files=files, timeout=timeout, headers=headers)
+ result = action(
+ endpoint,
+ data=data, files=files, timeout=timeout, headers=headers, verify=self.verify
+ )
else:
- result = action(endpoint, params=data, timeout=timeout, headers=headers)
+ result = action(
+ endpoint,
+ params=data, timeout=timeout, headers=headers, verify=self.verify
+ )
- if self.throttle is True:
+ if self.throttle:
self._update_rate_limits(result.headers)
sleep(self.throttling_time)
@@ -125,8 +129,12 @@ class Endpoint:
throttle=True,
crossref_plus_token=None,
timeout=30,
+ verify=True,
):
- self.do_http_request = HTTPRequest(throttle=throttle).do_http_request
+ self.throttle = throttle
+ self.verify = verify
+ self.http_request = HTTPRequest(throttle=throttle, verify=verify)
+ self.do_http_request = self.http_request.do_http_request
self.etiquette = etiquette or Etiquette()
self.custom_header = {"user-agent": str(self.etiquette)}
self.crossref_plus_token = crossref_plus_token
@@ -147,7 +155,6 @@ class Endpoint:
only_headers=True,
custom_header=self.custom_header,
timeout=self.timeout,
- throttle=False,
)
return {
@@ -233,7 +240,7 @@ class Endpoint:
@property
def url(self):
"""
- This attribute retrieve the url that will be used as a HTTP request to
+ This attribute retrieves the url that will be used as a HTTP request to
the Crossref API.
This attribute can be used compounded with query, filter,
@@ -274,8 +281,10 @@ class Endpoint:
request_params=request_params,
context=context,
etiquette=self.etiquette,
+ throttle=self.throttle,
crossref_plus_token=self.crossref_plus_token,
timeout=self.timeout,
+ verify=self.verify,
),
)
@@ -302,7 +311,7 @@ class Endpoint:
return
- if self.CURSOR_AS_ITER_METHOD is True:
+ if self.CURSOR_AS_ITER_METHOD:
request_params = dict(self.request_params)
request_params["cursor"] = "*"
request_params["rows"] = LIMIT
@@ -620,12 +629,15 @@ class Works(Endpoint):
request_params=request_params,
context=context,
etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
timeout=self.timeout,
+ verify=self.verify,
)
def select(self, *args):
"""
- This method retrieve an iterable object that implements the method
+ This method retrieves an iterable object that implements the method
__iter__. The arguments given will compose the parameters in the
request url.
@@ -724,12 +736,15 @@ class Works(Endpoint):
request_params=request_params,
context=context,
etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
timeout=self.timeout,
+ verify=self.verify,
)
def sort(self, sort="score"):
"""
- This method retrieve an iterable object that implements the method
+ This method retrieves an iterable object that implements the method
__iter__. The arguments given will compose the parameters in the
request url.
@@ -785,12 +800,15 @@ class Works(Endpoint):
request_params=request_params,
context=context,
etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
timeout=self.timeout,
+ verify=self.verify,
)
def filter(self, **kwargs): # noqa: A003
"""
- This method retrieve an iterable object that implements the method
+ This method retrieves an iterable object that implements the method
__iter__. The arguments given will compose the parameters in the
request url.
@@ -842,7 +860,10 @@ class Works(Endpoint):
request_params=request_params,
context=context,
etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
timeout=self.timeout,
+ verify=self.verify,
)
def facet(self, facet_name, facet_count=100):
@@ -854,10 +875,10 @@ class Works(Endpoint):
if facet_name not in self.FACET_VALUES.keys():
msg = (
f"Facet {facet_name} specified but there is no such facet for this route."
- f" Valid facets for this route are: *, affiliation, funder-name, funder-doi,"
- f" publisher-name, orcid, container-title, assertion, archive, update-type,"
- f" issn, published, source, type-name, license, category-name, relation-type,"
- f" assertion-group"
+ " Valid facets for this route are: *, affiliation, funder-name, funder-doi,"
+ " publisher-name, orcid, container-title, assertion, archive, update-type,"
+ " issn, published, source, type-name, license, category-name, relation-type,"
+ " assertion-group"
)
raise UrlSyntaxError((
msg
@@ -935,15 +956,20 @@ class Works(Endpoint):
)
request_params["query.%s" % field.replace("_", "-")] = value
- return self.__class__(request_url=request_url,
- request_params=request_params,
- context=context,
- etiquette=self.etiquette,
- timeout=self.timeout)
+ return self.__class__(
+ request_url=request_url,
+ request_params=request_params,
+ context=context,
+ etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
+ timeout=self.timeout,
+ verify=self.verify,
+ )
def sample(self, sample_size=20):
"""
- This method retrieve an iterable object that implements the method
+ This method retrieves an iterable object that implements the method
__iter__. The arguments given will compose the parameters in the
request url.
@@ -963,7 +989,11 @@ class Works(Endpoint):
context = str(self.context)
request_url = build_url_endpoint(self.ENDPOINT, context)
request_params = dict(self.request_params)
-
+ etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
+ timeout=self.timeout,
+ verify=self.verify,
try:
if sample_size > 100:
msg = (
@@ -986,6 +1016,9 @@ class Works(Endpoint):
context=context,
etiquette=self.etiquette,
timeout=self.timeout,
+ throttle=self.throttle,
+ verify=self.verify,
+ crossref_plus_token=self.crossref_plus_token,
)
def doi(self, doi, only_message=True):
@@ -1131,7 +1164,7 @@ class Funders(Endpoint):
def query(self, *args):
"""
- This method retrieve an iterable object that implements the method
+ This method retrieves an iterable object that implements the method
__iter__. The arguments given will compose the parameters in the
request url.
@@ -1160,7 +1193,10 @@ class Funders(Endpoint):
request_url=request_url,
request_params=request_params,
etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
timeout=self.timeout,
+ verify=self.verify,
)
def filter(self, **kwargs): # noqa: A003
@@ -1216,7 +1252,10 @@ class Funders(Endpoint):
request_params=request_params,
context=context,
etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
timeout=self.timeout,
+ verify=self.verify,
)
def funder(self, funder_id, only_message=True):
@@ -1295,14 +1334,21 @@ class Funders(Endpoint):
def works(self, funder_id):
"""
- This method retrieve a iterable of Works of the given funder.
+ This method retrieves an iterable of Works of the given funder.
args: Crossref allowed document Types (String)
return: Works()
"""
context = f"{self.ENDPOINT}/{funder_id!s}"
- return Works(context=context)
+ return Works(
+ context=context,
+ etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
+ timeout=self.timeout,
+ verify=self.verify,
+ )
class Members(Endpoint):
@@ -1319,7 +1365,7 @@ class Members(Endpoint):
def query(self, *args):
"""
- This method retrieve an iterable object that implements the method
+ This method retrieves an iterable object that implements the method
__iter__. The arguments given will compose the parameters in the
request url.
@@ -1374,7 +1420,10 @@ class Members(Endpoint):
request_params=request_params,
context=context,
etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
timeout=self.timeout,
+ verify=self.verify,
)
def filter(self, **kwargs): # noqa: A003
@@ -1434,7 +1483,10 @@ class Members(Endpoint):
request_params=request_params,
context=context,
etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
timeout=self.timeout,
+ verify=self.verify,
)
def member(self, member_id, only_message=True):
@@ -1507,8 +1559,8 @@ class Members(Endpoint):
def member_exists(self, member_id):
"""
- This method retrieve a boolean according to the existence of a crossref
- member. It returns False if the API results a 404 status code.
+ This method retrieves a boolean according to the existence of a crossref
+ member. It returns False if the API results in a 404 status code.
args: Crossref allowed document Type (String)
@@ -1545,14 +1597,21 @@ class Members(Endpoint):
def works(self, member_id):
"""
- This method retrieve a iterable of Works of the given member.
+ This method retrieves an iterable of Works of the given member.
args: Member ID (Integer)
return: Works()
"""
context = f"{self.ENDPOINT}/{member_id!s}"
- return Works(context=context)
+ return Works(
+ context=context,
+ etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
+ timeout=self.timeout,
+ verify=self.verify,
+ )
class Types(Endpoint):
@@ -1562,7 +1621,7 @@ class Types(Endpoint):
def type(self, type_id, only_message=True): # noqa: A003
"""
- This method retrive a crossref document type metadata related to the
+ This method retrives a crossref document type metadata related to the
given type_id.
args: Crossref allowed document Types (String)
@@ -1591,7 +1650,7 @@ class Types(Endpoint):
def all(self): # noqa: A003
"""
- This method retrieve an iterator with all the available types.
+ This method retrieves an iterator with all the available types.
return: iterator of crossref document types
@@ -1628,7 +1687,7 @@ class Types(Endpoint):
def type_exists(self, type_id):
"""
- This method retrieve a boolean according to the existence of a crossref
+ This method retrieves a boolean according to the existence of a crossref
document type. It returns False if the API results a 404 status code.
args: Crossref allowed document Type (String)
@@ -1666,14 +1725,21 @@ class Types(Endpoint):
def works(self, type_id):
"""
- This method retrieve a iterable of Works of the given type.
+ This method retrieves an iterable of Works of the given type.
args: Crossref allowed document Types (String)
return: Works()
"""
context = f"{self.ENDPOINT}/{type_id!s}"
- return Works(context=context)
+ return Works(
+ context=context,
+ etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
+ timeout=self.timeout,
+ verify=self.verify,
+ )
class Prefixes(Endpoint):
@@ -1683,7 +1749,7 @@ class Prefixes(Endpoint):
def prefix(self, prefix_id, only_message=True):
"""
- This method retrieve a json with the given Prefix metadata
+ This method retrieves a JSON with the given Prefix metadata
args: Crossref Prefix (String)
@@ -1716,14 +1782,21 @@ class Prefixes(Endpoint):
def works(self, prefix_id):
"""
- This method retrieve a iterable of Works of the given prefix.
+ This method retrieves an iterable of Works of the given prefix.
args: Crossref Prefix (String)
return: Works()
"""
context = f"{self.ENDPOINT}/{prefix_id!s}"
- return Works(context=context)
+ return Works(
+ context=context,
+ etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
+ timeout=self.timeout,
+ verify=self.verify,
+ )
class Journals(Endpoint):
@@ -1733,7 +1806,7 @@ class Journals(Endpoint):
def query(self, *args):
"""
- This method retrieve an iterable object that implements the method
+ This method retrieves an iterable object that implements the method
__iter__. The arguments given will compose the parameters in the
request url.
@@ -1764,12 +1837,15 @@ class Journals(Endpoint):
request_params=request_params,
context=context,
etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
timeout=self.timeout,
+ verify=self.verify,
)
def journal(self, issn, only_message=True):
"""
- This method retrieve a json with the given ISSN metadata
+ This method retrieves a JSON with the given ISSN metadata
args: Journal ISSN (String)
@@ -1804,8 +1880,8 @@ class Journals(Endpoint):
def journal_exists(self, issn):
"""
- This method retrieve a boolean according to the existence of a journal
- in the Crossref database. It returns False if the API results a 404
+ This method retrieves a boolean according to the existence of a journal
+ in the Crossref database. It returns False if the API results in a 404
status code.
args: Journal ISSN (String)
@@ -1843,7 +1919,7 @@ class Journals(Endpoint):
def works(self, issn):
"""
- This method retrieve a iterable of Works of the given journal.
+ This method retrieves an iterable of Works of the given journal.
args: Journal ISSN (String)
@@ -1851,7 +1927,14 @@ class Journals(Endpoint):
"""
context = f"{self.ENDPOINT}/{issn!s}"
- return Works(context=context)
+ return Works(
+ context=context,
+ etiquette=self.etiquette,
+ throttle=self.throttle,
+ crossref_plus_token=self.crossref_plus_token,
+ timeout=self.timeout,
+ verify=self.verify,
+ )
class Depositor:
@@ -1904,7 +1987,7 @@ class Depositor:
def request_doi_status_by_filename(self, file_name, data_type="result"):
"""
- This method retrieve the DOI requests status.
+ This method retrieves the DOI requests status.
file_name: Used as unique ID to identify a deposit.
@@ -1928,7 +2011,7 @@ class Depositor:
def request_doi_status_by_batch_id(self, doi_batch_id, data_type="result"):
"""
- This method retrieve the DOI requests status.
+ This method retrieves the DOI requests status.
file_name: Used as unique ID to identify a deposit.
diff --git a/debian/changelog b/debian/changelog
index 48f6fd3..da9aff2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+python-crossrefapi (1.7.0-1) unstable; urgency=medium
+
+ * New upstream version 1.7.0
+ * Bump copyright years.
+
+ -- Andrius Merkys <merkys@debian.org> Tue, 02 Sep 2025 02:16:03 -0400
+
python-crossrefapi (1.6.1-1) unstable; urgency=medium
* New upstream version 1.6.1
diff --git a/debian/control b/debian/control
index bae07f2..c346b4f 100644
--- a/debian/control
+++ b/debian/control
@@ -10,6 +10,7 @@ Build-Depends:
pybuild-plugin-pyproject,
python3-all:any,
python3-poetry-core,
+ python3-pytest,
python3-requests <!nocheck>,
python3-setuptools,
Standards-Version: 4.6.2
diff --git a/debian/copyright b/debian/copyright
index 2fd5370..c964ea6 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -8,7 +8,7 @@ Copyright: 2017, Fabio Batalha
License: BSD-2-Clause
Files: debian/*
-Copyright: 2021-2024, Andrius Merkys <merkys@debian.org>
+Copyright: 2021-2025, Andrius Merkys <merkys@debian.org>
License: BSD-2-Clause
License: BSD-2-Clause
diff --git a/debian/patches/disable-network-tests.patch b/debian/patches/disable-network-tests.patch
deleted file mode 100644
index ca88689..0000000
--- a/debian/patches/disable-network-tests.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-Description: Disable network tests.
-Author: Andrius Merkys <merkys@debian.org>
-Forwarded: not-needed
---- a/tests/test_restful.py
-+++ b/tests/test_restful.py
-@@ -21,6 +21,7 @@
- contact_email="undefined",
- )
-
-+ @unittest.skip("not running network tests")
- def test_work_agency_message(self):
- """
- Testing the base structure for the /works/{DOI}/agency endpoint.
-@@ -33,6 +34,7 @@
-
- assert result["agency"]["id"] == "crossref"
-
-+ @unittest.skip("not running network tests")
- def test_work_agency_header(self):
- """
- Testing the base structure for the /works/{DOI}/agency endpoint.
diff --git a/debian/patches/series b/debian/patches/series
deleted file mode 100644
index ac5717b..0000000
--- a/debian/patches/series
+++ /dev/null
@@ -1 +0,0 @@
-disable-network-tests.patch
diff --git a/debian/rules b/debian/rules
index b3f45d0..7df209d 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,6 +1,7 @@
#!/usr/bin/make -f
export PYBUILD_NAME = crossrefapi
+export PYBUILD_TEST_ARGS = -k 'not test_integration and not test_work_agency_message and not test_work_agency_header'
# These values will intentionally fail with
# 'requests.exceptions.InvalidURL: Proxy URL had no scheme'
diff --git a/poetry.lock b/poetry.lock
index 226edf2..8295e77 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,32 +1,31 @@
-# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
+# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand.
[[package]]
name = "asttokens"
-version = "2.4.1"
+version = "3.0.0"
description = "Annotate AST trees with source code positions"
optional = false
-python-versions = "*"
+python-versions = ">=3.8"
+groups = ["main", "dev"]
files = [
- {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"},
- {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"},
+ {file = "asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"},
+ {file = "asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7"},
]
-[package.dependencies]
-six = ">=1.12.0"
-
[package.extras]
-astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"]
-test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"]
+astroid = ["astroid (>=2,<4)"]
+test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"]
[[package]]
name = "certifi"
-version = "2024.8.30"
+version = "2025.6.15"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
+groups = ["main"]
files = [
- {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"},
- {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"},
+ {file = "certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057"},
+ {file = "certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b"},
]
[[package]]
@@ -35,6 +34,7 @@ version = "3.4.0"
description = "Validate configuration and produce human readable error messages."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"},
{file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
@@ -42,101 +42,104 @@ files = [
[[package]]
name = "charset-normalizer"
-version = "3.3.2"
+version = "3.4.2"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
-python-versions = ">=3.7.0"
-files = [
- {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"},
- {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"},
+ {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"},
+ {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"},
]
[[package]]
@@ -145,6 +148,8 @@ version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+groups = ["main", "dev"]
+markers = "sys_platform == \"win32\""
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
@@ -152,79 +157,89 @@ files = [
[[package]]
name = "decorator"
-version = "5.1.1"
+version = "5.2.1"
description = "Decorators for Humans"
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.8"
+groups = ["main", "dev"]
files = [
- {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
- {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
+ {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"},
+ {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"},
]
[[package]]
name = "distlib"
-version = "0.3.8"
+version = "0.3.9"
description = "Distribution utilities"
optional = false
python-versions = "*"
+groups = ["dev"]
files = [
- {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
- {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
+ {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"},
+ {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"},
]
[[package]]
name = "exceptiongroup"
-version = "1.2.2"
+version = "1.3.0"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
+groups = ["main", "dev"]
+markers = "python_version == \"3.10\""
files = [
- {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
- {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
+ {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"},
+ {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"},
]
+[package.dependencies]
+typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""}
+
[package.extras]
test = ["pytest (>=6)"]
[[package]]
name = "executing"
-version = "2.1.0"
+version = "2.2.0"
description = "Get the currently executing AST node of a frame, and other information"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
files = [
- {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"},
- {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"},
+ {file = "executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa"},
+ {file = "executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755"},
]
[package.extras]
-tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"]
+tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""]
[[package]]
name = "filelock"
-version = "3.16.1"
+version = "3.18.0"
description = "A platform independent file lock."
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
+groups = ["dev"]
files = [
- {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"},
- {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"},
+ {file = "filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"},
+ {file = "filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2"},
]
[package.extras]
-docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"]
-testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"]
-typing = ["typing-extensions (>=4.12.2)"]
+docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"]
+typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""]
[[package]]
name = "identify"
-version = "2.6.1"
+version = "2.6.12"
description = "File identification library for Python"
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
+groups = ["dev"]
files = [
- {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"},
- {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"},
+ {file = "identify-2.6.12-py2.py3-none-any.whl", hash = "sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2"},
+ {file = "identify-2.6.12.tar.gz", hash = "sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6"},
]
[package.extras]
@@ -236,6 +251,7 @@ version = "3.10"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.6"
+groups = ["main"]
files = [
{file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
{file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
@@ -246,24 +262,26 @@ all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2
[[package]]
name = "iniconfig"
-version = "2.0.0"
+version = "2.1.0"
description = "brain-dead simple config-ini parsing"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
+groups = ["dev"]
files = [
- {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
- {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
+ {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"},
+ {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"},
]
[[package]]
name = "ipython"
-version = "8.28.0"
+version = "8.37.0"
description = "IPython: Productive Interactive Computing"
optional = false
python-versions = ">=3.10"
+groups = ["main", "dev"]
files = [
- {file = "ipython-8.28.0-py3-none-any.whl", hash = "sha256:530ef1e7bb693724d3cdc37287c80b07ad9b25986c007a53aa1857272dac3f35"},
- {file = "ipython-8.28.0.tar.gz", hash = "sha256:0d0d15ca1e01faeb868ef56bc7ee5a0de5bd66885735682e8a322ae289a13d1a"},
+ {file = "ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2"},
+ {file = "ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216"},
]
[package.dependencies]
@@ -273,16 +291,16 @@ exceptiongroup = {version = "*", markers = "python_version < \"3.11\""}
jedi = ">=0.16"
matplotlib-inline = "*"
pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""}
-prompt-toolkit = ">=3.0.41,<3.1.0"
+prompt_toolkit = ">=3.0.41,<3.1.0"
pygments = ">=2.4.0"
-stack-data = "*"
+stack_data = "*"
traitlets = ">=5.13.0"
-typing-extensions = {version = ">=4.6", markers = "python_version < \"3.12\""}
+typing_extensions = {version = ">=4.6", markers = "python_version < \"3.12\""}
[package.extras]
all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"]
black = ["black"]
-doc = ["docrepr", "exceptiongroup", "intersphinx-registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli", "typing-extensions"]
+doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli ; python_version < \"3.11\"", "typing_extensions"]
kernel = ["ipykernel"]
matplotlib = ["matplotlib"]
nbconvert = ["nbconvert"]
@@ -291,26 +309,27 @@ notebook = ["ipywidgets", "notebook"]
parallel = ["ipyparallel"]
qtconsole = ["qtconsole"]
test = ["packaging", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"]
-test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"]
+test-extra = ["curio", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"]
[[package]]
name = "jedi"
-version = "0.19.1"
+version = "0.19.2"
description = "An autocompletion tool for Python that can be used for text editors."
optional = false
python-versions = ">=3.6"
+groups = ["main", "dev"]
files = [
- {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"},
- {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"},
+ {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"},
+ {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"},
]
[package.dependencies]
-parso = ">=0.8.3,<0.9.0"
+parso = ">=0.8.4,<0.9.0"
[package.extras]
docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"]
qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"]
-testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"]
+testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"]
[[package]]
name = "matplotlib-inline"
@@ -318,6 +337,7 @@ version = "0.1.7"
description = "Inline Matplotlib backend for Jupyter"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
files = [
{file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"},
{file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"},
@@ -332,6 +352,7 @@ version = "1.9.1"
description = "Node.js virtual environment builder"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+groups = ["dev"]
files = [
{file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"},
{file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
@@ -339,13 +360,14 @@ files = [
[[package]]
name = "packaging"
-version = "24.1"
+version = "25.0"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
- {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
- {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
+ {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"},
+ {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"},
]
[[package]]
@@ -354,6 +376,7 @@ version = "0.8.4"
description = "A Python Parser"
optional = false
python-versions = ">=3.6"
+groups = ["main", "dev"]
files = [
{file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"},
{file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"},
@@ -369,6 +392,8 @@ version = "4.9.0"
description = "Pexpect allows easy control of interactive console applications."
optional = false
python-versions = "*"
+groups = ["main", "dev"]
+markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""
files = [
{file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"},
{file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"},
@@ -379,34 +404,36 @@ ptyprocess = ">=0.5"
[[package]]
name = "platformdirs"
-version = "4.3.6"
+version = "4.3.8"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
+groups = ["dev"]
files = [
- {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"},
- {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"},
+ {file = "platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4"},
+ {file = "platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc"},
]
[package.extras]
-docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"]
-test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"]
-type = ["mypy (>=1.11.2)"]
+docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"]
+test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"]
+type = ["mypy (>=1.14.1)"]
[[package]]
name = "pluggy"
-version = "1.5.0"
+version = "1.6.0"
description = "plugin and hook calling mechanisms for python"
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
+groups = ["dev"]
files = [
- {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
- {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
+ {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"},
+ {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"},
]
[package.extras]
dev = ["pre-commit", "tox"]
-testing = ["pytest", "pytest-benchmark"]
+testing = ["coverage", "pytest", "pytest-benchmark"]
[[package]]
name = "pre-commit"
@@ -414,6 +441,7 @@ version = "3.8.0"
description = "A framework for managing and maintaining multi-language pre-commit hooks."
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
files = [
{file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"},
{file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"},
@@ -428,13 +456,14 @@ virtualenv = ">=20.10.0"
[[package]]
name = "prompt-toolkit"
-version = "3.0.48"
+version = "3.0.51"
description = "Library for building powerful interactive command lines in Python"
optional = false
-python-versions = ">=3.7.0"
+python-versions = ">=3.8"
+groups = ["main", "dev"]
files = [
- {file = "prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e"},
- {file = "prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90"},
+ {file = "prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"},
+ {file = "prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed"},
]
[package.dependencies]
@@ -446,6 +475,8 @@ version = "0.7.0"
description = "Run a subprocess in a pseudo terminal"
optional = false
python-versions = "*"
+groups = ["main", "dev"]
+markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""
files = [
{file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
{file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
@@ -457,6 +488,7 @@ version = "0.2.3"
description = "Safely evaluate AST nodes without side effects"
optional = false
python-versions = "*"
+groups = ["main", "dev"]
files = [
{file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"},
{file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"},
@@ -467,13 +499,14 @@ tests = ["pytest"]
[[package]]
name = "pygments"
-version = "2.18.0"
+version = "2.19.2"
description = "Pygments is a syntax highlighting package written in Python."
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
files = [
- {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"},
- {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
+ {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"},
+ {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"},
]
[package.extras]
@@ -485,6 +518,7 @@ version = "7.4.4"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"},
{file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"},
@@ -507,6 +541,7 @@ version = "6.0.2"
description = "YAML parser and emitter for Python"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
files = [
{file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
{file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
@@ -565,18 +600,19 @@ files = [
[[package]]
name = "requests"
-version = "2.32.3"
+version = "2.32.4"
description = "Python HTTP for Humans."
optional = false
python-versions = ">=3.8"
+groups = ["main"]
files = [
- {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
- {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
+ {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"},
+ {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"},
]
[package.dependencies]
certifi = ">=2017.4.17"
-charset-normalizer = ">=2,<4"
+charset_normalizer = ">=2,<4"
idna = ">=2.5,<4"
urllib3 = ">=1.21.1,<3"
@@ -590,6 +626,7 @@ version = "0.0.277"
description = "An extremely fast Python linter, written in Rust."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
files = [
{file = "ruff-0.0.277-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:3250b24333ef419b7a232080d9724ccc4d2da1dbbe4ce85c4caa2290d83200f8"},
{file = "ruff-0.0.277-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:3e60605e07482183ba1c1b7237eca827bd6cbd3535fe8a4ede28cbe2a323cb97"},
@@ -611,22 +648,12 @@ files = [
]
[[package]]
-name = "six"
-version = "1.16.0"
-description = "Python 2 and 3 compatibility utilities"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
-files = [
- {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
- {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
-]
-
-[[package]]
name = "stack-data"
version = "0.6.3"
description = "Extract data from python stack frames and tracebacks for informative displays"
optional = false
python-versions = "*"
+groups = ["main", "dev"]
files = [
{file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"},
{file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"},
@@ -642,13 +669,45 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
[[package]]
name = "tomli"
-version = "2.0.2"
+version = "2.2.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.8"
-files = [
- {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"},
- {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"},
+groups = ["dev"]
+markers = "python_version == \"3.10\""
+files = [
+ {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
+ {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
+ {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
+ {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
+ {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
+ {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
+ {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
+ {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
+ {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
+ {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
+ {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
+ {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
+ {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
+ {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
+ {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
+ {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
+ {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
+ {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
+ {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
+ {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
+ {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
+ {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
+ {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
+ {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
+ {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
+ {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
+ {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
+ {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
+ {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
+ {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
+ {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
+ {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
]
[[package]]
@@ -657,6 +716,7 @@ version = "5.14.3"
description = "Traitlets Python configuration system"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
files = [
{file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"},
{file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"},
@@ -668,41 +728,45 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,
[[package]]
name = "typing-extensions"
-version = "4.12.2"
-description = "Backported and Experimental Type Hints for Python 3.8+"
+version = "4.14.0"
+description = "Backported and Experimental Type Hints for Python 3.9+"
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
+groups = ["main", "dev"]
+markers = "python_version < \"3.12\""
files = [
- {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
- {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
+ {file = "typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af"},
+ {file = "typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4"},
]
[[package]]
name = "urllib3"
-version = "2.2.3"
+version = "2.5.0"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
+groups = ["main"]
files = [
- {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"},
- {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"},
+ {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"},
+ {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"},
]
[package.extras]
-brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
+brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""]
h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
[[package]]
name = "virtualenv"
-version = "20.26.6"
+version = "20.31.2"
description = "Virtual Python Environment builder"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
+groups = ["dev"]
files = [
- {file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"},
- {file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"},
+ {file = "virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11"},
+ {file = "virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af"},
]
[package.dependencies]
@@ -712,7 +776,7 @@ platformdirs = ">=3.9.1,<5"
[package.extras]
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
-test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
+test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""]
[[package]]
name = "wcwidth"
@@ -720,12 +784,13 @@ version = "0.2.13"
description = "Measures the displayed width of unicode strings in a terminal"
optional = false
python-versions = "*"
+groups = ["main", "dev"]
files = [
{file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"},
{file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"},
]
[metadata]
-lock-version = "2.0"
+lock-version = "2.1"
python-versions = "^3.10"
content-hash = "0da5aa4acc06d8b5853e375f1313784cb22519528806b62b296086efae886b48"
diff --git a/pyproject.toml b/pyproject.toml
index 5aeb969..eb94aff 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "crossrefapi"
-version = "1.6.1"
+version = "1.7.0"
description = "Library that implements the endpoints of the Crossref API"
authors = ["Fabio Batalha <fabio.batalha@erudit.org>"]
packages = [
diff --git a/tests/test_integration.py b/tests/test_integration.py
new file mode 100644
index 0000000..4c3ab6c
--- /dev/null
+++ b/tests/test_integration.py
@@ -0,0 +1,87 @@
+"""
+These tests perform live requests to the Crossref API aiming to test real use cases.
+"""
+from crossref.restful import Funders, Members, Works, Journals
+
+
+def test_works_get_work():
+ """
+ Test the retrieval of a specific DOI.
+ """
+ doi = "10.1590/S0102-09352010000200002"
+ works = Works(verify=False)
+ sample = works.doi(doi)
+ assert sample.get("DOI").upper() == doi
+
+def test_works_sample():
+ """
+ Test the sample endpoint using a limit of 5 records.
+ """
+ works = Works(verify=False)
+ sample = works.sample(5)
+ itens = list(sample)
+ assert len(itens) == 5
+
+def test_funders_endpoint():
+ funders = Funders(verify=False)
+ assert funders.query("ABBEY AWARDS").url == "https://api.crossref.org/funders?query=ABBEY+AWARDS"
+ result = list(funders.query("ABBEY AWARDS"))
+ assert len(result) == 1
+ assert result[0].get("id") == "501100000314"
+ assert result[0].get("name") == "ABBEY AWARDS"
+
+def test_funders_endpoint_funder():
+ funders = Funders(verify=False)
+ funder = funders.funder(funder_id="501100000314")
+ assert funder.get("id") == "501100000314"
+
+def test_funders_endpoint_works():
+ funders = Funders(verify=False)
+ record = list(funders.works(funder_id="501100000314").filter(doi="10.3897/folmed.62.e51230"))[0]
+ assert record.get("funder")[0]["name"] == "ABBEY AWARDS"
+
+def test_member_endpoint_query():
+ members = Members(verify=False)
+ assert (
+ members.query("Érudit Consortium").url ==
+ "https://api.crossref.org/members?query=%C3%89rudit+Consortium"
+ )
+ result = list(members.query("Consortium Erudit"))
+ assert len(result) == 1
+ assert result[0].get("prefix")[0]["value"] == "10.7202"
+
+def test_member_endpoint_filter():
+ members = Members(verify=False)
+ result = list(members.filter(prefix="10.7202"))
+ assert len(result) == 1
+ assert result[0].get("primary-name") == "Consortium Erudit"
+
+def test_member_endpoint_member():
+ members = Members(verify=False)
+ member = members.member(member_id="4194")
+ assert member.get("prefix")[0]["value"] == "10.7202"
+
+def test_member_endpoint_works():
+ members = Members(verify=False)
+ record = list(members.works(member_id="4194").filter(doi="10.7202/050998ar"))[0]
+ assert record.get("DOI") == "10.7202/050998ar"
+
+def test_journal_endpoint_query():
+ journals = Journals(verify=False)
+ assert (
+ journals.query("Cuizine The Journal of Canadian Food Cultures").url ==
+ "https://api.crossref.org/journals?query=Cuizine+The+Journal+of+Canadian+Food+Cultures"
+ )
+ result = list(journals.query("Cuizine The Journal of Canadian Food Cultures"))
+ assert len(result) == 1
+ assert result[0].get("title") == "Cuizine The Journal of Canadian Food Cultures"
+
+def test_journals_endpoint_journal():
+ journals = Journals(verify=False)
+ journal = journals.journal(issn="1918-5480")
+ assert journal.get("ISSN")[0] == "1918-5480"
+
+def test_journals_endpoint_works():
+ journals = Journals(verify=False)
+ record = list(journals.works(issn="1918-5480").filter(doi="10.7202/1038479ar"))[0]
+ assert record.get("DOI") == "10.7202/1038479ar" \ No newline at end of file
diff --git a/tests/test_restful.py b/tests/test_restful.py
index 9be4150..57895ee 100644
--- a/tests/test_restful.py
+++ b/tests/test_restful.py
@@ -1,123 +1,103 @@
+import pytest
+from crossref import VERSION, restful
-import unittest
-from crossref import VERSION, restful
+@pytest.fixture(autouse=True)
+def etiquette():
+ return restful.Etiquette(
+ application_name="UnitTest CrossrefAPI",
+ application_version=VERSION,
+ application_url="https://github.com/fabiobatalha/crossrefapi",
+ contact_email="undefined",
+ )
-class RestfulTest(unittest.TestCase):
+def test_work_agency_message(etiquette):
"""
- These tests are testing the API live integration, the main purpouse of these
- testes is to validate the JSON structure of the API results.
- These tests may lead to connectivity erros if the Crossref API is temporary
- out of service.
+ Testing the base structure for the /works/{DOI}/agency endpoint.
+ If all the base structure is present, this test may not lead to dict
+ keyerror exceptions.
"""
+ works = restful.Works(etiquette=etiquette, verify=False)
+ result = works.agency("10.1590/S0102-09352010000200002")
+ assert result["agency"]["id"] == "crossref"
- def setUp(self):
-
- self.etiquette = restful.Etiquette(
- application_name="UnitTest CrossrefAPI",
- application_version=VERSION,
- application_url="https://github.com/fabiobatalha/crossrefapi",
- contact_email="undefined",
- )
-
- def test_work_agency_message(self):
- """
- Testing the base structure for the /works/{DOI}/agency endpoint.
- If all the base structure is present, this test may not lead to dict
- keyerror exceptions.
- """
- works = restful.Works(etiquette=self.etiquette)
-
- result = works.agency("10.1590/S0102-09352010000200002")
-
- assert result["agency"]["id"] == "crossref"
-
- def test_work_agency_header(self):
- """
- Testing the base structure for the /works/{DOI}/agency endpoint.
- If all the base structure is present, this test may not lead to dict
- keyerror exceptions.
- """
- works = restful.Works(etiquette=self.etiquette)
-
- result = works.agency("10.1590/S0102-09352010000200002", only_message=False)
-
- assert result["message-type"] == "work-agency"
-
- def test_work_select_fields(self):
- result = restful.Works(etiquette=self.etiquette).select("DOI").url
-
- assert result == "https://api.crossref.org/works?select=DOI"
- def test_work_select_fields_multiple_parameter_and_array(self):
- result = restful.Works(etiquette=self.etiquette) \
- .select("DOI", "title").select("subject").select(["relation", "editor"]) \
- .select("relation, editor").url
-
- assert result == "https://api.crossref.org/works?select=DOI%2Ceditor%2Crelation%2Csubject%2Ctitle"
-
- def test_work_with_sample(self):
- result = restful.Works(etiquette=self.etiquette).sample(5).url
-
- assert result == "https://api.crossref.org/works?sample=5"
-
- def test_work_with_sample_and_filters(self):
- result = restful.Works(
- etiquette=self.etiquette).filter(type="journal-article").sample(5).url
-
- assert result == "https://api.crossref.org/works?filter=type%3Ajournal-article&sample=5"
-
- def test_members_filters(self):
- result = restful.Members(
- etiquette=self.etiquette).filter(has_public_references="true").url
-
- assert result == "https://api.crossref.org/members?filter=has-public-references%3Atrue"
-
- def test_funders_filters(self):
- result = restful.Funders(etiquette=self.etiquette).filter(location="Japan").url
-
- assert result == "https://api.crossref.org/funders?filter=location%3AJapan"
+def test_work_agency_header(etiquette):
+ """
+ Testing the base structure for the /works/{DOI}/agency endpoint.
+ If all the base structure is present, this test may not lead to dict
+ keyerror exceptions.
+ """
+ works = restful.Works(etiquette=etiquette, verify=False)
+ result = works.agency("10.1590/S0102-09352010000200002", only_message=False)
+ assert result["message-type"] == "work-agency"
-class HTTPRequestTest(unittest.TestCase):
+def test_work_select_fields(etiquette):
+ result = restful.Works(etiquette=etiquette, verify=False).select("DOI").url
+ assert result == "https://api.crossref.org/works?select=DOI"
- def setUp(self):
- self.httprequest = restful.HTTPRequest()
+def test_work_select_fields_multiple_parameter_and_array(etiquette):
+ result = restful.Works(etiquette=etiquette, verify=False) \
+ .select("DOI", "title").select("subject").select(["relation", "editor"]) \
+ .select("relation, editor").url
+ assert result == "https://api.crossref.org/works?select=DOI%2Ceditor%2Crelation%2Csubject%2Ctitle"
- def test_default_rate_limits(self):
- expected = {"x-rate-limit-interval": 1, "x-rate-limit-limit": 50}
+def test_work_with_sample(etiquette):
+ result = restful.Works(etiquette=etiquette, verify=False).sample(5).url
+ assert result == "https://api.crossref.org/works?sample=5"
- assert self.httprequest.rate_limits == expected
- def test_update_rate_limits_seconds(self):
+def test_work_with_sample_and_filters(etiquette):
+ result = restful.Works(
+ etiquette=etiquette, verify=False
+ ).filter(type="journal-article").sample(5).url
+ assert result == "https://api.crossref.org/works?filter=type%3Ajournal-article&sample=5"
- headers = {"x-rate-limit-interval": "2s", "x-rate-limit-limit": 50}
- self.httprequest._update_rate_limits(headers)
+def test_members_filters(etiquette):
+ result = restful.Members(
+ etiquette=etiquette, verify=False
+ ).filter(has_public_references="true").url
+ assert result == "https://api.crossref.org/members?filter=has-public-references%3Atrue"
- expected = {"x-rate-limit-interval": 2, "x-rate-limit-limit": 50}
- assert self.httprequest.rate_limits == expected
+def test_funders_filters(etiquette):
+ result = restful.Funders(
+ etiquette=etiquette, verify=False
+ ).filter(location="Japan").url
+ assert result == "https://api.crossref.org/funders?filter=location%3AJapan"
- def test_update_rate_limits_minutes(self):
- headers = {"x-rate-limit-interval": "2m", "x-rate-limit-limit": 50}
+@pytest.fixture(autouse=True)
+def httprequest():
+ return restful.HTTPRequest()
- self.httprequest._update_rate_limits(headers)
- expected = {"x-rate-limit-interval": 120, "x-rate-limit-limit": 50}
+def test_default_rate_limits(httprequest):
+ expected = {"x-rate-limit-interval": 1, "x-rate-limit-limit": 50}
+ assert httprequest.rate_limits == expected
- assert self.httprequest.rate_limits == expected
- def test_update_rate_limits_hours(self):
+def test_update_rate_limits_seconds(httprequest):
+ headers = {"x-rate-limit-interval": "2s", "x-rate-limit-limit": 50}
+ httprequest._update_rate_limits(headers)
+ expected = {"x-rate-limit-interval": 2, "x-rate-limit-limit": 50}
+ assert httprequest.rate_limits == expected
- headers = {"x-rate-limit-interval": "2h", "x-rate-limit-limit": 50}
- self.httprequest._update_rate_limits(headers)
+def test_update_rate_limits_minutes(httprequest):
+ headers = {"x-rate-limit-interval": "2m", "x-rate-limit-limit": 50}
+ httprequest._update_rate_limits(headers)
+ expected = {"x-rate-limit-interval": 120, "x-rate-limit-limit": 50}
+ assert httprequest.rate_limits == expected
- expected = {"x-rate-limit-interval": 7200, "x-rate-limit-limit": 50}
- assert self.httprequest.rate_limits == expected
+def test_update_rate_limits_hours(httprequest):
+ headers = {"x-rate-limit-interval": "2h", "x-rate-limit-limit": 50}
+ httprequest._update_rate_limits(headers)
+ expected = {"x-rate-limit-interval": 7200, "x-rate-limit-limit": 50}
+ assert httprequest.rate_limits == expected
diff --git a/tests/test_validators.py b/tests/test_validators.py
index f1b86cc..d778da8 100644
--- a/tests/test_validators.py
+++ b/tests/test_validators.py
@@ -1,112 +1,109 @@
-
-import unittest
+import pytest
from crossref import validators
-class ValidatorsTest(unittest.TestCase):
-
- def test_directory_1(self):
+def test_directory_1():
- result = validators.directory("DOAJ")
+ result = validators.directory("DOAJ")
- assert result
+ assert result
- def test_directory_2(self):
+def test_directory_2():
- with self.assertRaises(ValueError):
- validators.directory("any invalid archive")
+ with pytest.raises(ValueError):
+ validators.directory("any invalid archive")
- def test_archive_1(self):
+def test_archive_1():
- result = validators.archive("CLOCKSS")
+ result = validators.archive("CLOCKSS")
- assert result
+ assert result
- def test_archive_2(self):
+def test_archive_2():
- with self.assertRaises(ValueError):
- validators.archive("any invalid archive")
+ with pytest.raises(ValueError):
+ validators.archive("any invalid archive")
- def test_document_type_1(self):
+def test_document_type_1():
- result = validators.document_type("book-chapter")
+ result = validators.document_type("book-chapter")
- assert result
+ assert result
- def test_document_type_2(self):
+def test_document_type_2():
- with self.assertRaises(ValueError):
- validators.document_type("any invalid type")
+ with pytest.raises(ValueError):
+ validators.document_type("any invalid type")
- def test_is_bool_3(self):
+def test_is_bool_3():
- result = validators.is_bool("true")
+ result = validators.is_bool("true")
- assert result
+ assert result
- def test_is_bool_4(self):
+def test_is_bool_4():
- result = validators.is_bool("false")
+ result = validators.is_bool("false")
- assert result
+ assert result
- def test_is_bool_5(self):
+def test_is_bool_5():
- result = validators.is_bool("1")
+ result = validators.is_bool("1")
- assert result
+ assert result
- def test_is_bool_5(self):
+def test_is_bool_6():
- with self.assertRaises(ValueError):
- validators.is_bool("jljlj")
+ with pytest.raises(ValueError):
+ validators.is_bool("jljlj")
- def test_is_date_1(self):
+def test_is_date_1():
- result = validators.is_date("2017")
+ result = validators.is_date("2017")
- assert result
+ assert result
- def test_is_date_2(self):
+def test_is_date_2():
- result = validators.is_date("2017-12")
+ result = validators.is_date("2017-12")
- assert result
+ assert result
- def test_is_date_3(self):
+def test_is_date_3():
- result = validators.is_date("2017-12-31")
+ result = validators.is_date("2017-12-31")
- assert result
+ assert result
- def test_is_date_4(self):
+def test_is_date_4():
- with self.assertRaises(ValueError):
- validators.is_date("asas")
+ with pytest.raises(ValueError):
+ validators.is_date("asas")
- def test_is_date_5(self):
+def test_is_date_5():
- with self.assertRaises(ValueError):
- validators.is_date("2017-30")
+ with pytest.raises(ValueError):
+ validators.is_date("2017-30")
- def test_is_date_6(self):
+def test_is_date_6():
- with self.assertRaises(ValueError):
- validators.is_date("2017-12-00")
+ with pytest.raises(ValueError):
+ validators.is_date("2017-12-00")
- def test_is_integer_1(self):
+def test_is_integer_1():
- result = validators.is_integer("10")
+ result = validators.is_integer("10")
- assert result
+ assert result
- def test_is_integer_1(self):
+def test_is_integer_2():
- with self.assertRaises(ValueError):
- validators.is_integer("-1")
+ with pytest.raises(ValueError):
+ validators.is_integer("-1")
- def test_is_integer_3(self):
+def test_is_integer_3():
- with self.assertRaises(ValueError):
- validators.is_integer("dd")
+ with pytest.raises(ValueError):
+ validators.is_integer("dd")