From ab826d5e49e35d1169e77478f7d863fa21ff9833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Mart=C3=AD=20Gamboa?= Date: Tue, 21 May 2024 15:57:27 +0200 Subject: [PATCH 1/8] Add 3.12 to setup.py classifiers --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index e0b4c70..6cc8a4b 100644 --- a/setup.py +++ b/setup.py @@ -51,6 +51,7 @@ def read(*parts): 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', ], packages=find_packages(exclude=("tests",)), ) From c0f3e38f019c0eee64c29cd9fe250c3fc14e53b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Mart=C3=AD=20Gamboa?= Date: Tue, 21 May 2024 16:00:03 +0200 Subject: [PATCH 2/8] Update contributing.md some grammar nits --- contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributing.md b/contributing.md index d2b2641..a15ae38 100644 --- a/contributing.md +++ b/contributing.md @@ -32,7 +32,7 @@ I use [pytest](https://docs.pytest.org/en/7.4.x/contents.html), [Coverage](https ## Creating new tests -Normal Unit tests that do not connect to the QBO API should be located under `test/unit` Test that connect to QBO API should go under `tests/integration`. Inheriting from `QuickbooksTestCase` will automatically setup `self.qb_client` to use when connecting to QBO. +Normal Unit tests that do not connect to the QBO API should be located under `test/unit`. Tests that connect to QBO API should go under `tests/integration`. Inheriting from `QuickbooksTestCase` will automatically setup `self.qb_client` to use when connecting to QBO. Example: ``` From da86e27806609a24579032bed154024c4ec0d012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Mart=C3=AD=20Gamboa?= Date: Tue, 21 May 2024 16:02:05 +0200 Subject: [PATCH 3/8] Fix path in pytest example --- contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributing.md b/contributing.md index d2b2641..0367e5f 100644 --- a/contributing.md +++ b/contributing.md @@ -27,7 +27,7 @@ I use [pytest](https://docs.pytest.org/en/7.4.x/contents.html), [Coverage](https 6. Run all tests: ```pytest --cov``` Run only unit tests: ```pytest tests/unit --cov``` - Run only integration tests: ```pytest tests/intergration --cov``` + Run only integration tests: ```pytest tests/integration --cov``` From 5afd3f5179aa52162bfcdfb08a71310eb38bbc90 Mon Sep 17 00:00:00 2001 From: "William N. Green" Date: Wed, 22 May 2024 18:10:33 -0700 Subject: [PATCH 4/8] Use simplejson Decimal support Modified imports and removed unused json imports Modified calls to set use_decimal for serialization/deserialization --- quickbooks/client.py | 4 ++-- quickbooks/mixins.py | 10 ++++------ quickbooks/objects/payment.py | 1 - 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/quickbooks/client.py b/quickbooks/client.py index 967bba3..7a07578 100644 --- a/quickbooks/client.py +++ b/quickbooks/client.py @@ -1,6 +1,6 @@ import http.client as httplib import textwrap -import json +import simplejson as json import base64 import hashlib import hmac @@ -206,7 +206,7 @@ def make_request(self, request_type, url, request_body=None, content_type='appli "Application authentication failed", error_code=req.status_code, detail=req.text) try: - result = req.json() + result = json.loads(req.text, use_decimal=True) except: raise exceptions.QuickbooksException("Error reading json response: {0}".format(req.text), 10000) diff --git a/quickbooks/mixins.py b/quickbooks/mixins.py index 2083139..6b0a1be 100644 --- a/quickbooks/mixins.py +++ b/quickbooks/mixins.py @@ -1,16 +1,14 @@ from urllib.parse import quote -try: import simplejson as json -except ImportError: import json +import simplejson as json from .utils import build_where_clause, build_choose_clause from .client import QuickBooks from .exceptions import QuickbooksException - class ToJsonMixin(object): def to_json(self): - return json.dumps(self, default=self.json_filter(), sort_keys=True, indent=4) + return json.dumps(self, default=self.json_filter(), sort_keys=True, indent=4, use_decimal=True) def json_filter(self): """ @@ -178,7 +176,7 @@ def void(self, qb=None): data = self.get_void_data() params = self.get_void_params() - results = qb.post(url, json.dumps(data), params=params) + results = qb.post(url, json.dumps(data, use_decimal=True), params=params) return results @@ -232,7 +230,7 @@ def delete(self, qb=None, request_id=None): 'Id': self.Id, 'SyncToken': self.SyncToken, } - return qb.delete_object(self.qbo_object_name, json.dumps(data), request_id=request_id) + return qb.delete_object(self.qbo_object_name, json.dumps(data, use_decimal=True), request_id=request_id) class DeleteNoIdMixin(object): diff --git a/quickbooks/objects/payment.py b/quickbooks/objects/payment.py index 75cbf57..5783d16 100644 --- a/quickbooks/objects/payment.py +++ b/quickbooks/objects/payment.py @@ -4,7 +4,6 @@ from ..client import QuickBooks from .creditcardpayment import CreditCardPayment from ..mixins import DeleteMixin, VoidMixin -import json class PaymentLine(QuickbooksBaseObject): From 9de4c9ebab2f2b4aee52bb49470eeecaacd2d6ff Mon Sep 17 00:00:00 2001 From: "William N. Green" Date: Wed, 22 May 2024 20:40:06 -0700 Subject: [PATCH 5/8] Fixed mock object for simplejson case --- tests/unit/test_client.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index aafbf33..c0b0ab0 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -1,3 +1,4 @@ +import simplejson as json from tests.integration.test_base import QuickbooksUnitTestCase try: @@ -141,7 +142,7 @@ def test_get_single_object(self, make_req): @patch('quickbooks.client.QuickBooks.process_request') def test_make_request(self, process_request): - process_request.return_value = MockResponse() + process_request.return_value = MockResponseSimpleJson() qb_client = client.QuickBooks() qb_client.company_id = "1234" @@ -220,7 +221,7 @@ def test_download_pdf_not_authorized(self, process_request): @patch('quickbooks.client.QuickBooks.process_request') def test_make_request_file_closed(self, process_request): file_path = '/path/to/file.txt' - process_request.return_value = MockResponse() + process_request.return_value = MockResponseSimpleJson() with patch('builtins.open', mock_open(read_data=b'file content')) as mock_file: qb_client = client.QuickBooks(auth_client=self.auth_client) qb_client.make_request('POST', @@ -253,6 +254,18 @@ def json(self): def content(self): return '' +class MockResponseSimpleJson: + def __init__(self, json_data=None, status_code=200): + self.json_data = json_data or {} + self.status_code = status_code + + @property + def text(self): + return json.dumps(self.json_data) # Ensure this uses simplejson if necessary + + def json(self): + return self.json_data + class MockUnauthorizedResponse(object): @property From 3dcc61446bee45533410148e1b96ba28aa4b6a3c Mon Sep 17 00:00:00 2001 From: "William N. Green" Date: Sat, 1 Jun 2024 12:09:38 -0700 Subject: [PATCH 6/8] Removed simplejson dependency See https://github.com/ej2/python-quickbooks/pull/358 --- Pipfile | 1 - Pipfile.lock | 457 +++++++++++++++++-------------------------- quickbooks/client.py | 8 +- quickbooks/mixins.py | 18 +- requirements.txt | 3 +- setup.py | 1 - 6 files changed, 199 insertions(+), 289 deletions(-) diff --git a/Pipfile b/Pipfile index 4d3612c..ab07e83 100644 --- a/Pipfile +++ b/Pipfile @@ -13,5 +13,4 @@ pytest-cov = "*" urllib3 = ">=2.1.0" intuit-oauth = "==1.2.5" requests = ">=2.31.0" -simplejson = ">=3.19.1" requests_oauthlib = ">=1.3.1" diff --git a/Pipfile.lock b/Pipfile.lock index d1ab4bd..b95a512 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "09dfd0a28da4402be6db03781432fb082e5fe5d6010dae3f98443aa5d336f526" + "sha256": "e25e6a93ea424fe54edd3dbdbd0eed5c76b49764b8e64cdb4c70d271932331f0" }, "pipfile-spec": 6, "requires": {}, @@ -16,11 +16,11 @@ "default": { "certifi": { "hashes": [ - "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1", - "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474" + "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", + "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" ], "markers": "python_version >= '3.6'", - "version": "==2023.11.17" + "version": "==2024.2.2" }, "charset-normalizer": { "hashes": [ @@ -120,11 +120,11 @@ }, "ecdsa": { "hashes": [ - "sha256:190348041559e21b22a1d65cee485282ca11a6f81d503fddb84d5017e9ed1e49", - "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd" + "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a", + "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.18.0" + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.19.0" }, "enum-compat": { "hashes": [ @@ -133,28 +133,21 @@ ], "version": "==0.0.3" }, - "future": { - "hashes": [ - "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.18.3" - }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", + "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" ], "markers": "python_version >= '3.5'", - "version": "==3.6" + "version": "==3.7" }, "intuit-oauth": { "hashes": [ - "sha256:14a1a8ed73f24369ba209f0e581eb30698571fd7bcbe05ca5bed65d2ff9df8b1", - "sha256:dd09ef833a26e12e0fbe96d0e7694cdae2c9179776f763ea00e328f8cbd4464e" + "sha256:1c3d53468c00590485dc3b040d5d18389060573c616a26e33a03c1b164c92823", + "sha256:74af897366c0fb984a6179ef3200bb10c0ed194760e7daf92c8b0927e856a022" ], "index": "pypi", - "version": "==1.2.4" + "version": "==1.2.5" }, "oauthlib": { "hashes": [ @@ -166,11 +159,11 @@ }, "pyasn1": { "hashes": [ - "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58", - "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c" + "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c", + "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==0.5.1" + "markers": "python_version >= '3.8'", + "version": "==0.6.0" }, "python-jose": { "hashes": [ @@ -181,20 +174,21 @@ }, "requests": { "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.31.0" + "markers": "python_version >= '3.8'", + "version": "==2.32.3" }, "requests-oauthlib": { "hashes": [ - "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5", - "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a" + "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", + "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.3.1" + "index": "pypi", + "markers": "python_version >= '3.4'", + "version": "==2.0.0" }, "rsa": { "hashes": [ @@ -204,111 +198,6 @@ "markers": "python_version >= '3.6' and python_version < '4'", "version": "==4.9" }, - "simplejson": { - "hashes": [ - "sha256:0405984f3ec1d3f8777c4adc33eac7ab7a3e629f3b1c05fdded63acc7cf01137", - "sha256:0436a70d8eb42bea4fe1a1c32d371d9bb3b62c637969cb33970ad624d5a3336a", - "sha256:061e81ea2d62671fa9dea2c2bfbc1eec2617ae7651e366c7b4a2baf0a8c72cae", - "sha256:064300a4ea17d1cd9ea1706aa0590dcb3be81112aac30233823ee494f02cb78a", - "sha256:08889f2f597ae965284d7b52a5c3928653a9406d88c93e3161180f0abc2433ba", - "sha256:0a48679310e1dd5c9f03481799311a65d343748fe86850b7fb41df4e2c00c087", - "sha256:0b0a3eb6dd39cce23801a50c01a0976971498da49bc8a0590ce311492b82c44b", - "sha256:0d2d5119b1d7a1ed286b8af37357116072fc96700bce3bec5bb81b2e7057ab41", - "sha256:0d551dc931638e2102b8549836a1632e6e7cf620af3d093a7456aa642bff601d", - "sha256:1018bd0d70ce85f165185d2227c71e3b1e446186f9fa9f971b69eee223e1e3cd", - "sha256:11c39fbc4280d7420684494373b7c5904fa72a2b48ef543a56c2d412999c9e5d", - "sha256:11cc3afd8160d44582543838b7e4f9aa5e97865322844b75d51bf4e0e413bb3e", - "sha256:1537b3dd62d8aae644f3518c407aa8469e3fd0f179cdf86c5992792713ed717a", - "sha256:16ca9c90da4b1f50f089e14485db8c20cbfff2d55424062791a7392b5a9b3ff9", - "sha256:176a1b524a3bd3314ed47029a86d02d5a95cc0bee15bd3063a1e1ec62b947de6", - "sha256:18955c1da6fc39d957adfa346f75226246b6569e096ac9e40f67d102278c3bcb", - "sha256:1bb5b50dc6dd671eb46a605a3e2eb98deb4a9af787a08fcdddabe5d824bb9664", - "sha256:1c768e7584c45094dca4b334af361e43b0aaa4844c04945ac7d43379eeda9bc2", - "sha256:1dd4f692304854352c3e396e9b5f0a9c9e666868dd0bdc784e2ac4c93092d87b", - "sha256:25785d038281cd106c0d91a68b9930049b6464288cea59ba95b35ee37c2d23a5", - "sha256:287e39ba24e141b046812c880f4619d0ca9e617235d74abc27267194fc0c7835", - "sha256:2c1467d939932901a97ba4f979e8f2642415fcf02ea12f53a4e3206c9c03bc17", - "sha256:2c433a412e96afb9a3ce36fa96c8e61a757af53e9c9192c97392f72871e18e69", - "sha256:2d022b14d7758bfb98405672953fe5c202ea8a9ccf9f6713c5bd0718eba286fd", - "sha256:2f98d918f7f3aaf4b91f2b08c0c92b1774aea113334f7cde4fe40e777114dbe6", - "sha256:2fc697be37585eded0c8581c4788fcfac0e3f84ca635b73a5bf360e28c8ea1a2", - "sha256:3194cd0d2c959062b94094c0a9f8780ffd38417a5322450a0db0ca1a23e7fbd2", - "sha256:332c848f02d71a649272b3f1feccacb7e4f7e6de4a2e6dc70a32645326f3d428", - "sha256:346820ae96aa90c7d52653539a57766f10f33dd4be609206c001432b59ddf89f", - "sha256:3471e95110dcaf901db16063b2e40fb394f8a9e99b3fe9ee3acc6f6ef72183a2", - "sha256:3848427b65e31bea2c11f521b6fc7a3145d6e501a1038529da2391aff5970f2f", - "sha256:39b6d79f5cbfa3eb63a869639cfacf7c41d753c64f7801efc72692c1b2637ac7", - "sha256:3e74355cb47e0cd399ead3477e29e2f50e1540952c22fb3504dda0184fc9819f", - "sha256:3f39bb1f6e620f3e158c8b2eaf1b3e3e54408baca96a02fe891794705e788637", - "sha256:40847f617287a38623507d08cbcb75d51cf9d4f9551dd6321df40215128325a3", - "sha256:4280e460e51f86ad76dc456acdbfa9513bdf329556ffc8c49e0200878ca57816", - "sha256:445a96543948c011a3a47c8e0f9d61e9785df2544ea5be5ab3bc2be4bd8a2565", - "sha256:4969d974d9db826a2c07671273e6b27bc48e940738d768fa8f33b577f0978378", - "sha256:49aaf4546f6023c44d7e7136be84a03a4237f0b2b5fb2b17c3e3770a758fc1a0", - "sha256:49e0e3faf3070abdf71a5c80a97c1afc059b4f45a5aa62de0c2ca0444b51669b", - "sha256:49f9da0d6cd17b600a178439d7d2d57c5ef01f816b1e0e875e8e8b3b42db2693", - "sha256:4a8c3cc4f9dfc33220246760358c8265dad6e1104f25f0077bbca692d616d358", - "sha256:4d36081c0b1c12ea0ed62c202046dca11438bee48dd5240b7c8de8da62c620e9", - "sha256:4edcd0bf70087b244ba77038db23cd98a1ace2f91b4a3ecef22036314d77ac23", - "sha256:554313db34d63eac3b3f42986aa9efddd1a481169c12b7be1e7512edebff8eaf", - "sha256:5675e9d8eeef0aa06093c1ff898413ade042d73dc920a03e8cea2fb68f62445a", - "sha256:60848ab779195b72382841fc3fa4f71698a98d9589b0a081a9399904487b5832", - "sha256:66e5dc13bfb17cd6ee764fc96ccafd6e405daa846a42baab81f4c60e15650414", - "sha256:6779105d2fcb7fcf794a6a2a233787f6bbd4731227333a072d8513b252ed374f", - "sha256:6ad331349b0b9ca6da86064a3599c425c7a21cd41616e175ddba0866da32df48", - "sha256:6f0a0b41dd05eefab547576bed0cf066595f3b20b083956b1405a6f17d1be6ad", - "sha256:73a8a4653f2e809049999d63530180d7b5a344b23a793502413ad1ecea9a0290", - "sha256:778331444917108fa8441f59af45886270d33ce8a23bfc4f9b192c0b2ecef1b3", - "sha256:7cb98be113911cb0ad09e5523d0e2a926c09a465c9abb0784c9269efe4f95917", - "sha256:7d74beca677623481810c7052926365d5f07393c72cbf62d6cce29991b676402", - "sha256:7f2398361508c560d0bf1773af19e9fe644e218f2a814a02210ac2c97ad70db0", - "sha256:8434dcdd347459f9fd9c526117c01fe7ca7b016b6008dddc3c13471098f4f0dc", - "sha256:8a390e56a7963e3946ff2049ee1eb218380e87c8a0e7608f7f8790ba19390867", - "sha256:92c4a4a2b1f4846cd4364855cbac83efc48ff5a7d7c06ba014c792dd96483f6f", - "sha256:9300aee2a8b5992d0f4293d88deb59c218989833e3396c824b69ba330d04a589", - "sha256:9453419ea2ab9b21d925d0fd7e3a132a178a191881fab4169b6f96e118cc25bb", - "sha256:9652e59c022e62a5b58a6f9948b104e5bb96d3b06940c6482588176f40f4914b", - "sha256:972a7833d4a1fcf7a711c939e315721a88b988553fc770a5b6a5a64bd6ebeba3", - "sha256:9c1a4393242e321e344213a90a1e3bf35d2f624aa8b8f6174d43e3c6b0e8f6eb", - "sha256:9e038c615b3906df4c3be8db16b3e24821d26c55177638ea47b3f8f73615111c", - "sha256:9e4c166f743bb42c5fcc60760fb1c3623e8fda94f6619534217b083e08644b46", - "sha256:9eb117db8d7ed733a7317c4215c35993b815bf6aeab67523f1f11e108c040672", - "sha256:9eb442a2442ce417801c912df68e1f6ccfcd41577ae7274953ab3ad24ef7d82c", - "sha256:a3cd18e03b0ee54ea4319cdcce48357719ea487b53f92a469ba8ca8e39df285e", - "sha256:a8617625369d2d03766413bff9e64310feafc9fc4f0ad2b902136f1a5cd8c6b0", - "sha256:a970a2e6d5281d56cacf3dc82081c95c1f4da5a559e52469287457811db6a79b", - "sha256:aad7405c033d32c751d98d3a65801e2797ae77fac284a539f6c3a3e13005edc4", - "sha256:adcb3332979cbc941b8fff07181f06d2b608625edc0a4d8bc3ffc0be414ad0c4", - "sha256:af9c7e6669c4d0ad7362f79cb2ab6784d71147503e62b57e3d95c4a0f222c01c", - "sha256:b01fda3e95d07a6148702a641e5e293b6da7863f8bc9b967f62db9461330562c", - "sha256:b8d940fd28eb34a7084877747a60873956893e377f15a32ad445fe66c972c3b8", - "sha256:bccb3e88ec26ffa90f72229f983d3a5d1155e41a1171190fa723d4135523585b", - "sha256:bcedf4cae0d47839fee7de344f96b5694ca53c786f28b5f773d4f0b265a159eb", - "sha256:be893258d5b68dd3a8cba8deb35dc6411db844a9d35268a8d3793b9d9a256f80", - "sha256:c0521e0f07cb56415fdb3aae0bbd8701eb31a9dfef47bb57206075a0584ab2a2", - "sha256:c594642d6b13d225e10df5c16ee15b3398e21a35ecd6aee824f107a625690374", - "sha256:c87c22bd6a987aca976e3d3e23806d17f65426191db36d40da4ae16a6a494cbc", - "sha256:c9ac1c2678abf9270e7228133e5b77c6c3c930ad33a3c1dfbdd76ff2c33b7b50", - "sha256:d0e5ffc763678d48ecc8da836f2ae2dd1b6eb2d27a48671066f91694e575173c", - "sha256:d0f402e787e6e7ee7876c8b05e2fe6464820d9f35ba3f172e95b5f8b699f6c7f", - "sha256:d222a9ed082cd9f38b58923775152003765016342a12f08f8c123bf893461f28", - "sha256:d94245caa3c61f760c4ce4953cfa76e7739b6f2cbfc94cc46fff6c050c2390c5", - "sha256:de9a2792612ec6def556d1dc621fd6b2073aff015d64fba9f3e53349ad292734", - "sha256:e2f5a398b5e77bb01b23d92872255e1bcb3c0c719a3be40b8df146570fe7781a", - "sha256:e8dd53a8706b15bc0e34f00e6150fbefb35d2fd9235d095b4f83b3c5ed4fa11d", - "sha256:e9eb3cff1b7d71aa50c89a0536f469cb8d6dcdd585d8f14fb8500d822f3bdee4", - "sha256:ed628c1431100b0b65387419551e822987396bee3c088a15d68446d92f554e0c", - "sha256:ef7938a78447174e2616be223f496ddccdbf7854f7bf2ce716dbccd958cc7d13", - "sha256:f1c70249b15e4ce1a7d5340c97670a95f305ca79f376887759b43bb33288c973", - "sha256:f3c7363a8cb8c5238878ec96c5eb0fc5ca2cb11fc0c7d2379863d342c6ee367a", - "sha256:fbbcc6b0639aa09b9649f36f1bcb347b19403fe44109948392fbb5ea69e48c3e", - "sha256:febffa5b1eda6622d44b245b0685aff6fb555ce0ed734e2d7b1c3acd018a2cff", - "sha256:ff836cd4041e16003549449cc0a5e372f6b6f871eb89007ab0ee18fb2800fded" - ], - "index": "pypi", - "markers": "python_version >= '2.5' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==3.19.2" - }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", @@ -319,22 +208,22 @@ }, "urllib3": { "hashes": [ - "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3", - "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54" + "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", + "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==2.1.0" + "version": "==2.2.1" } }, "develop": { "certifi": { "hashes": [ - "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1", - "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474" + "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", + "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" ], "markers": "python_version >= '3.6'", - "version": "==2023.11.17" + "version": "==2024.2.2" }, "charset-normalizer": { "hashes": [ @@ -437,86 +326,86 @@ "toml" ], "hashes": [ - "sha256:04387a4a6ecb330c1878907ce0dc04078ea72a869263e53c72a1ba5bbdf380ca", - "sha256:0676cd0ba581e514b7f726495ea75aba3eb20899d824636c6f59b0ed2f88c471", - "sha256:0e8d06778e8fbffccfe96331a3946237f87b1e1d359d7fbe8b06b96c95a5407a", - "sha256:0eb3c2f32dabe3a4aaf6441dde94f35687224dfd7eb2a7f47f3fd9428e421058", - "sha256:109f5985182b6b81fe33323ab4707011875198c41964f014579cf82cebf2bb85", - "sha256:13eaf476ec3e883fe3e5fe3707caeb88268a06284484a3daf8250259ef1ba143", - "sha256:164fdcc3246c69a6526a59b744b62e303039a81e42cfbbdc171c91a8cc2f9446", - "sha256:26776ff6c711d9d835557ee453082025d871e30b3fd6c27fcef14733f67f0590", - "sha256:26f66da8695719ccf90e794ed567a1549bb2644a706b41e9f6eae6816b398c4a", - "sha256:29f3abe810930311c0b5d1a7140f6395369c3db1be68345638c33eec07535105", - "sha256:316543f71025a6565677d84bc4df2114e9b6a615aa39fb165d697dba06a54af9", - "sha256:36b0ea8ab20d6a7564e89cb6135920bc9188fb5f1f7152e94e8300b7b189441a", - "sha256:3cc9d4bc55de8003663ec94c2f215d12d42ceea128da8f0f4036235a119c88ac", - "sha256:485e9f897cf4856a65a57c7f6ea3dc0d4e6c076c87311d4bc003f82cfe199d25", - "sha256:5040148f4ec43644702e7b16ca864c5314ccb8ee0751ef617d49aa0e2d6bf4f2", - "sha256:51456e6fa099a8d9d91497202d9563a320513fcf59f33991b0661a4a6f2ad450", - "sha256:53d7d9158ee03956e0eadac38dfa1ec8068431ef8058fe6447043db1fb40d932", - "sha256:5a10a4920def78bbfff4eff8a05c51be03e42f1c3735be42d851f199144897ba", - "sha256:5b14b4f8760006bfdb6e08667af7bc2d8d9bfdb648351915315ea17645347137", - "sha256:5b2ccb7548a0b65974860a78c9ffe1173cfb5877460e5a229238d985565574ae", - "sha256:697d1317e5290a313ef0d369650cfee1a114abb6021fa239ca12b4849ebbd614", - "sha256:6ae8c9d301207e6856865867d762a4b6fd379c714fcc0607a84b92ee63feff70", - "sha256:707c0f58cb1712b8809ece32b68996ee1e609f71bd14615bd8f87a1293cb610e", - "sha256:74775198b702868ec2d058cb92720a3c5a9177296f75bd97317c787daf711505", - "sha256:756ded44f47f330666843b5781be126ab57bb57c22adbb07d83f6b519783b870", - "sha256:76f03940f9973bfaee8cfba70ac991825611b9aac047e5c80d499a44079ec0bc", - "sha256:79287fd95585ed36e83182794a57a46aeae0b64ca53929d1176db56aacc83451", - "sha256:799c8f873794a08cdf216aa5d0531c6a3747793b70c53f70e98259720a6fe2d7", - "sha256:7d360587e64d006402b7116623cebf9d48893329ef035278969fa3bbf75b697e", - "sha256:80b5ee39b7f0131ebec7968baa9b2309eddb35b8403d1869e08f024efd883566", - "sha256:815ac2d0f3398a14286dc2cea223a6f338109f9ecf39a71160cd1628786bc6f5", - "sha256:83c2dda2666fe32332f8e87481eed056c8b4d163fe18ecc690b02802d36a4d26", - "sha256:846f52f46e212affb5bcf131c952fb4075b55aae6b61adc9856222df89cbe3e2", - "sha256:936d38794044b26c99d3dd004d8af0035ac535b92090f7f2bb5aa9c8e2f5cd42", - "sha256:9864463c1c2f9cb3b5db2cf1ff475eed2f0b4285c2aaf4d357b69959941aa555", - "sha256:995ea5c48c4ebfd898eacb098164b3cc826ba273b3049e4a889658548e321b43", - "sha256:a1526d265743fb49363974b7aa8d5899ff64ee07df47dd8d3e37dcc0818f09ed", - "sha256:a56de34db7b7ff77056a37aedded01b2b98b508227d2d0979d373a9b5d353daa", - "sha256:a7c97726520f784239f6c62506bc70e48d01ae71e9da128259d61ca5e9788516", - "sha256:b8e99f06160602bc64da35158bb76c73522a4010f0649be44a4e167ff8555952", - "sha256:bb1de682da0b824411e00a0d4da5a784ec6496b6850fdf8c865c1d68c0e318dd", - "sha256:bf477c355274a72435ceb140dc42de0dc1e1e0bf6e97195be30487d8eaaf1a09", - "sha256:bf635a52fc1ea401baf88843ae8708591aa4adff875e5c23220de43b1ccf575c", - "sha256:bfd5db349d15c08311702611f3dccbef4b4e2ec148fcc636cf8739519b4a5c0f", - "sha256:c530833afc4707fe48524a44844493f36d8727f04dcce91fb978c414a8556cc6", - "sha256:cc6d65b21c219ec2072c1293c505cf36e4e913a3f936d80028993dd73c7906b1", - "sha256:cd3c1e4cb2ff0083758f09be0f77402e1bdf704adb7f89108007300a6da587d0", - "sha256:cfd2a8b6b0d8e66e944d47cdec2f47c48fef2ba2f2dff5a9a75757f64172857e", - "sha256:d0ca5c71a5a1765a0f8f88022c52b6b8be740e512980362f7fdbb03725a0d6b9", - "sha256:e7defbb9737274023e2d7af02cac77043c86ce88a907c58f42b580a97d5bcca9", - "sha256:e9d1bf53c4c8de58d22e0e956a79a5b37f754ed1ffdbf1a260d9dcfa2d8a325e", - "sha256:ea81d8f9691bb53f4fb4db603203029643caffc82bf998ab5b59ca05560f4c06" + "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523", + "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f", + "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d", + "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb", + "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0", + "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c", + "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98", + "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83", + "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8", + "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7", + "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac", + "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84", + "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb", + "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3", + "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884", + "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614", + "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd", + "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807", + "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd", + "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8", + "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc", + "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db", + "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0", + "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08", + "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232", + "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d", + "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a", + "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1", + "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286", + "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303", + "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341", + "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84", + "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45", + "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc", + "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec", + "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd", + "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155", + "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52", + "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d", + "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485", + "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31", + "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d", + "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d", + "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d", + "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85", + "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce", + "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb", + "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974", + "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24", + "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56", + "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9", + "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==7.4.0" + "version": "==7.5.3" }, "docutils": { "hashes": [ - "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", - "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b" + "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", + "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2" ], - "markers": "python_version >= '3.7'", - "version": "==0.20.1" + "markers": "python_version >= '3.9'", + "version": "==0.21.2" }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", + "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" ], "markers": "python_version >= '3.5'", - "version": "==3.6" + "version": "==3.7" }, "importlib-metadata": { "hashes": [ - "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e", - "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc" + "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570", + "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2" ], "markers": "python_version >= '3.8'", - "version": "==7.0.1" + "version": "==7.1.0" }, "iniconfig": { "hashes": [ @@ -528,19 +417,35 @@ }, "jaraco.classes": { "hashes": [ - "sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb", - "sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621" + "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", + "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790" ], "markers": "python_version >= '3.8'", - "version": "==3.3.0" + "version": "==3.4.0" + }, + "jaraco.context": { + "hashes": [ + "sha256:3e16388f7da43d384a1a7cd3452e72e14732ac9fe459678773a3608a812bf266", + "sha256:c2f67165ce1f9be20f32f650f25d8edfc1646a8aeee48ae06fb35f90763576d2" + ], + "markers": "python_version >= '3.8'", + "version": "==5.3.0" + }, + "jaraco.functools": { + "hashes": [ + "sha256:3b24ccb921d6b593bdceb56ce14799204f473976e2a9d4b15b04d0f2c2326664", + "sha256:d33fa765374c0611b52f8b3a795f8900869aa88c84769d4d1746cd68fb28c3e8" + ], + "markers": "python_version >= '3.8'", + "version": "==4.0.1" }, "keyring": { "hashes": [ - "sha256:4446d35d636e6a10b8bce7caa66913dd9eca5fd222ca03a3d42c38608ac30836", - "sha256:e730ecffd309658a08ee82535a3b5ec4b4c8669a9be11efb66249d8e0aeb9a25" + "sha256:2458681cdefc0dbc0b7eb6cf75d0b98e59f9ad9b2d4edd319d18f68bdca95e50", + "sha256:daaffd42dbda25ddafb1ad5fec4024e5bbcfe424597ca1ca452b299861e49f1b" ], "markers": "python_version >= '3.8'", - "version": "==24.3.0" + "version": "==25.2.1" }, "markdown-it-py": { "hashes": [ @@ -560,99 +465,99 @@ }, "more-itertools": { "hashes": [ - "sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a", - "sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6" + "sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684", + "sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1" ], "markers": "python_version >= '3.8'", - "version": "==10.1.0" + "version": "==10.2.0" }, "nh3": { "hashes": [ - "sha256:0d02d0ff79dfd8208ed25a39c12cbda092388fff7f1662466e27d97ad011b770", - "sha256:3277481293b868b2715907310c7be0f1b9d10491d5adf9fce11756a97e97eddf", - "sha256:3b803a5875e7234907f7d64777dfde2b93db992376f3d6d7af7f3bc347deb305", - "sha256:427fecbb1031db085eaac9931362adf4a796428ef0163070c484b5a768e71601", - "sha256:5f0d77272ce6d34db6c87b4f894f037d55183d9518f948bba236fe81e2bb4e28", - "sha256:60684857cfa8fdbb74daa867e5cad3f0c9789415aba660614fe16cd66cbb9ec7", - "sha256:6f42f99f0cf6312e470b6c09e04da31f9abaadcd3eb591d7d1a88ea931dca7f3", - "sha256:86e447a63ca0b16318deb62498db4f76fc60699ce0a1231262880b38b6cff911", - "sha256:8d595df02413aa38586c24811237e95937ef18304e108b7e92c890a06793e3bf", - "sha256:9c0d415f6b7f2338f93035bba5c0d8c1b464e538bfbb1d598acd47d7969284f0", - "sha256:a5167a6403d19c515217b6bcaaa9be420974a6ac30e0da9e84d4fc67a5d474c5", - "sha256:ac19c0d68cd42ecd7ead91a3a032fdfff23d29302dbb1311e641a130dfefba97", - "sha256:b1e97221cedaf15a54f5243f2c5894bb12ca951ae4ddfd02a9d4ea9df9e1a29d", - "sha256:bc2d086fb540d0fa52ce35afaded4ea526b8fc4d3339f783db55c95de40ef02e", - "sha256:d1e30ff2d8d58fb2a14961f7aac1bbb1c51f9bdd7da727be35c63826060b0bf3", - "sha256:f3b53ba93bb7725acab1e030bc2ecd012a817040fd7851b332f86e2f9bb98dc6" - ], - "version": "==0.2.15" + "sha256:0316c25b76289cf23be6b66c77d3608a4fdf537b35426280032f432f14291b9a", + "sha256:1a814dd7bba1cb0aba5bcb9bebcc88fd801b63e21e2450ae6c52d3b3336bc911", + "sha256:1aa52a7def528297f256de0844e8dd680ee279e79583c76d6fa73a978186ddfb", + "sha256:22c26e20acbb253a5bdd33d432a326d18508a910e4dcf9a3316179860d53345a", + "sha256:40015514022af31975c0b3bca4014634fa13cb5dc4dbcbc00570acc781316dcc", + "sha256:40d0741a19c3d645e54efba71cb0d8c475b59135c1e3c580f879ad5514cbf028", + "sha256:551672fd71d06cd828e282abdb810d1be24e1abb7ae2543a8fa36a71c1006fe9", + "sha256:66f17d78826096291bd264f260213d2b3905e3c7fae6dfc5337d49429f1dc9f3", + "sha256:85cdbcca8ef10733bd31f931956f7fbb85145a4d11ab9e6742bbf44d88b7e351", + "sha256:a3f55fabe29164ba6026b5ad5c3151c314d136fd67415a17660b4aaddacf1b10", + "sha256:b4427ef0d2dfdec10b641ed0bdaf17957eb625b2ec0ea9329b3d28806c153d71", + "sha256:ba73a2f8d3a1b966e9cdba7b211779ad8a2561d2dba9674b8a19ed817923f65f", + "sha256:c21bac1a7245cbd88c0b0e4a420221b7bfa838a2814ee5bb924e9c2f10a1120b", + "sha256:c551eb2a3876e8ff2ac63dff1585236ed5dfec5ffd82216a7a174f7c5082a78a", + "sha256:c790769152308421283679a142dbdb3d1c46c79c823008ecea8e8141db1a2062", + "sha256:d7a25fd8c86657f5d9d576268e3b3767c5cd4f42867c9383618be8517f0f022a" + ], + "version": "==0.2.17" }, "packaging": { "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", + "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" ], "markers": "python_version >= '3.7'", - "version": "==23.2" + "version": "==24.0" }, "pkginfo": { "hashes": [ - "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546", - "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046" + "sha256:6d4998d1cd42c297af72cc0eab5f5bab1d356fb8a55b828fa914173f8bc1ba05", + "sha256:dba885aa82e31e80d615119874384923f4e011c2a39b0c4b7104359e36cb7087" ], - "markers": "python_version >= '3.6'", - "version": "==1.9.6" + "markers": "python_version >= '3.8'", + "version": "==1.11.0" }, "pluggy": { "hashes": [ - "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12", - "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7" + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" ], "markers": "python_version >= '3.8'", - "version": "==1.3.0" + "version": "==1.5.0" }, "pygments": { "hashes": [ - "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c", - "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367" + "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", + "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" ], - "markers": "python_version >= '3.7'", - "version": "==2.17.2" + "markers": "python_version >= '3.8'", + "version": "==2.18.0" }, "pytest": { "hashes": [ - "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280", - "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8" + "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd", + "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==7.4.4" + "markers": "python_version >= '3.8'", + "version": "==8.2.1" }, "pytest-cov": { "hashes": [ - "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6", - "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a" + "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652", + "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==4.1.0" + "markers": "python_version >= '3.8'", + "version": "==5.0.0" }, "readme-renderer": { "hashes": [ - "sha256:13d039515c1f24de668e2c93f2e877b9dbe6c6c32328b90a40a49d8b2b85f36d", - "sha256:2d55489f83be4992fe4454939d1a051c33edbab778e82761d060c9fc6b308cd1" + "sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311", + "sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9" ], "markers": "python_version >= '3.8'", - "version": "==42.0" + "version": "==43.0" }, "requests": { "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.31.0" + "markers": "python_version >= '3.8'", + "version": "==2.32.3" }, "requests-toolbelt": { "hashes": [ @@ -672,37 +577,37 @@ }, "rich": { "hashes": [ - "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa", - "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235" + "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", + "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432" ], "markers": "python_full_version >= '3.7.0'", - "version": "==13.7.0" + "version": "==13.7.1" }, "twine": { "hashes": [ - "sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8", - "sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8" + "sha256:4d74770c88c4fcaf8134d2a6a9d863e40f08255ff7d8e2acb3cbbd57d25f6e9d", + "sha256:fe1d814395bfe50cfbe27783cb74efe93abeac3f66deaeb6c8390e4e92bacb43" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==4.0.2" + "markers": "python_version >= '3.8'", + "version": "==5.1.0" }, "urllib3": { "hashes": [ - "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3", - "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54" + "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", + "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==2.1.0" + "version": "==2.2.1" }, "zipp": { "hashes": [ - "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31", - "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0" + "sha256:2828e64edb5386ea6a52e7ba7cdb17bb30a73a858f5eb6eb93d8d36f5ea26091", + "sha256:35427f6d5594f4acf82d25541438348c26736fa9b3afa2754bcd63cdb99d8e8f" ], "markers": "python_version >= '3.8'", - "version": "==3.17.0" + "version": "==3.19.1" } } } diff --git a/quickbooks/client.py b/quickbooks/client.py index 7a07578..23b057a 100644 --- a/quickbooks/client.py +++ b/quickbooks/client.py @@ -1,14 +1,16 @@ import http.client as httplib import textwrap -import simplejson as json +import json import base64 import hashlib import hmac +import decimal from . import exceptions from requests_oauthlib import OAuth2Session -to_bytes = lambda value, *args, **kwargs: bytes(value, "utf-8", *args, **kwargs) +def to_bytes(value, *args, **kwargs): + return bytes(value, "utf-8", *args, **kwargs) class Environments(object): @@ -206,7 +208,7 @@ def make_request(self, request_type, url, request_body=None, content_type='appli "Application authentication failed", error_code=req.status_code, detail=req.text) try: - result = json.loads(req.text, use_decimal=True) + result = json.loads(req.text, parse_float=decimal.Decimal) except: raise exceptions.QuickbooksException("Error reading json response: {0}".format(req.text), 10000) diff --git a/quickbooks/mixins.py b/quickbooks/mixins.py index 6b0a1be..e5a860f 100644 --- a/quickbooks/mixins.py +++ b/quickbooks/mixins.py @@ -1,14 +1,20 @@ +import decimal +import json from urllib.parse import quote -import simplejson as json - -from .utils import build_where_clause, build_choose_clause from .client import QuickBooks from .exceptions import QuickbooksException +from .utils import build_choose_clause, build_where_clause + +class DecimalEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, decimal.Decimal): + return str(obj) + return super(DecimalEncoder, self).default(obj) class ToJsonMixin(object): def to_json(self): - return json.dumps(self, default=self.json_filter(), sort_keys=True, indent=4, use_decimal=True) + return json.dumps(self, cls=DecimalEncoder, default=self.json_filter(), sort_keys=True, indent=4) def json_filter(self): """ @@ -176,7 +182,7 @@ def void(self, qb=None): data = self.get_void_data() params = self.get_void_params() - results = qb.post(url, json.dumps(data, use_decimal=True), params=params) + results = qb.post(url, json.dumps(data, cls=DecimalEncoder), params=params) return results @@ -230,7 +236,7 @@ def delete(self, qb=None, request_id=None): 'Id': self.Id, 'SyncToken': self.SyncToken, } - return qb.delete_object(self.qbo_object_name, json.dumps(data, use_decimal=True), request_id=request_id) + return qb.delete_object(self.qbo_object_name, json.dumps(data, cls=DecimalEncoder), request_id=request_id) class DeleteNoIdMixin(object): diff --git a/requirements.txt b/requirements.txt index 2f1d93f..d67d7f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ intuit-oauth==1.2.4 requests_oauthlib>=1.3.1 -requests>=2.31.0 -simplejson>=3.19.1 \ No newline at end of file +requests>=2.31.0 \ No newline at end of file diff --git a/setup.py b/setup.py index e0b4c70..046aa75 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,6 @@ def read(*parts): 'intuit-oauth==1.2.5', 'requests_oauthlib>=1.3.1', 'requests>=2.31.0', - 'simplejson>=3.19.1', 'python-dateutil', ], From 4158e8b08e63eda2cea025d83c8682d08b0a93aa Mon Sep 17 00:00:00 2001 From: "William N. Green" Date: Sat, 1 Jun 2024 12:10:18 -0700 Subject: [PATCH 7/8] Updated test Put the decode on the test, removed the name for clarity --- tests/unit/test_client.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index c0b0ab0..a606d0e 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -1,4 +1,4 @@ -import simplejson as json +import json from tests.integration.test_base import QuickbooksUnitTestCase try: @@ -7,7 +7,7 @@ from unittest.mock import patch, mock_open from quickbooks.exceptions import QuickbooksException, SevereException, AuthorizationException -from quickbooks import client +from quickbooks import client, mixins from quickbooks.objects.salesreceipt import SalesReceipt @@ -142,7 +142,7 @@ def test_get_single_object(self, make_req): @patch('quickbooks.client.QuickBooks.process_request') def test_make_request(self, process_request): - process_request.return_value = MockResponseSimpleJson() + process_request.return_value = MockResponseJson() qb_client = client.QuickBooks() qb_client.company_id = "1234" @@ -221,7 +221,7 @@ def test_download_pdf_not_authorized(self, process_request): @patch('quickbooks.client.QuickBooks.process_request') def test_make_request_file_closed(self, process_request): file_path = '/path/to/file.txt' - process_request.return_value = MockResponseSimpleJson() + process_request.return_value = MockResponseJson() with patch('builtins.open', mock_open(read_data=b'file content')) as mock_file: qb_client = client.QuickBooks(auth_client=self.auth_client) qb_client.make_request('POST', @@ -254,14 +254,14 @@ def json(self): def content(self): return '' -class MockResponseSimpleJson: +class MockResponseJson: def __init__(self, json_data=None, status_code=200): self.json_data = json_data or {} self.status_code = status_code @property def text(self): - return json.dumps(self.json_data) # Ensure this uses simplejson if necessary + return json.dumps(self.json_data, cls=mixins.DecimalEncoder) def json(self): return self.json_data From 031831ea5700f9c90ac359c138c03d0f4aca5b3e Mon Sep 17 00:00:00 2001 From: "William N. Green" Date: Sat, 1 Jun 2024 12:25:11 -0700 Subject: [PATCH 8/8] Created use_decimal flag on client creation https://github.com/ej2/python-quickbooks/pull/358#issuecomment-2143554544 --- quickbooks/client.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/quickbooks/client.py b/quickbooks/client.py index 23b057a..0566ddb 100644 --- a/quickbooks/client.py +++ b/quickbooks/client.py @@ -26,6 +26,7 @@ class QuickBooks(object): minorversion = None verifier_token = None invoice_link = False + use_decimal = False sandbox_api_url_v3 = "https://sandbox-quickbooks.api.intuit.com/v3" api_url_v3 = "https://quickbooks.api.intuit.com/v3" @@ -81,6 +82,9 @@ def __new__(cls, **kwargs): if 'verifier_token' in kwargs: instance.verifier_token = kwargs.get('verifier_token') + if 'use_decimal' in kwargs: + instance.use_decimal = kwargs.get('use_decimal') + return instance def _start_session(self): @@ -208,7 +212,10 @@ def make_request(self, request_type, url, request_body=None, content_type='appli "Application authentication failed", error_code=req.status_code, detail=req.text) try: - result = json.loads(req.text, parse_float=decimal.Decimal) + if (self.use_decimal): + result = json.loads(req.text, parse_float=decimal.Decimal) + else: + result = json.loads(req.text) except: raise exceptions.QuickbooksException("Error reading json response: {0}".format(req.text), 10000)