From 3c5354d85534edfc457dcc0175ba4446c2918ac7 Mon Sep 17 00:00:00 2001 From: Bill Klenotiz Date: Wed, 21 Sep 2022 13:55:21 -0400 Subject: [PATCH 01/54] add workflows --- .../close-waiting-for-response-issues.yml | 20 ++++++++++++ .../workflows/remove-labels-on-activity.yml | 16 ++++++++++ .github/workflows/stale.yml | 31 +++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 .github/workflows/close-waiting-for-response-issues.yml create mode 100644 .github/workflows/remove-labels-on-activity.yml create mode 100644 .github/workflows/stale.yml diff --git a/.github/workflows/close-waiting-for-response-issues.yml b/.github/workflows/close-waiting-for-response-issues.yml new file mode 100644 index 00000000..ffd7a382 --- /dev/null +++ b/.github/workflows/close-waiting-for-response-issues.yml @@ -0,0 +1,20 @@ +name: Close Waiting for Response Issues +on: + schedule: + - cron: "30 1 * * *" + workflow_dispatch: +jobs: + check-need-info: + runs-on: ubuntu-latest + steps: + - name: close-issues + uses: actions-cool/issues-helper@v3 + with: + actions: 'close-issues' + token: ${{ secrets.GITHUB_TOKEN }} + labels: 'Waiting for Response' + inactive-day: 7 + body: | + We are closing this issue because we did not hear back regarding additional details we needed to resolve this issue. If the issue persists and you are able to provide the missing clarification we need, feel free to respond and reopen this issue. + + We appreciate your understanding as we try to manage our number of open issues. diff --git a/.github/workflows/remove-labels-on-activity.yml b/.github/workflows/remove-labels-on-activity.yml new file mode 100644 index 00000000..48872e95 --- /dev/null +++ b/.github/workflows/remove-labels-on-activity.yml @@ -0,0 +1,16 @@ +name: Remove Stale or Waiting Labels +on: + issue_comment: + types: [created] + workflow_dispatch: +jobs: + remove-labels-on-activity: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-ecosystem/action-remove-labels@v1 + if: contains(github.event.issue.labels.*.name, 'Waiting for Response') + with: + labels: | + Waiting for Response + diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 00000000..eeab0d6e --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,31 @@ +name: Close inactive issues +on: + schedule: + - cron: "30 1 * * *" + +jobs: + close-issues: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v5 + with: + days-before-issue-stale: 90 + days-before-issue-close: 14 + stale-issue-label: "Stale" + stale-issue-message: > + This issue is stale because it has been open for 90 days with no activity. It will be closed if no further action occurs in 14 days. + close-issue-message: | + We are closing this issue because it has been inactive for a few months. + This probably means that it is not reproducible or it has been fixed in a newer version. + If it’s an enhancement and hasn’t been taken on since it was submitted, then it seems other issues have taken priority. + + If you still encounter this issue with the latest stable version, please reopen using the issue template. You can also contribute directly by submitting a pull request– see the [CONTRIBUTING.md](https://github.com/Shopify/shopify_python_api/blob/master/CONTRIBUTING.md) file for guidelines + + Thank you! + days-before-pr-stale: -1 + days-before-pr-close: -1 + repo-token: ${{ secrets.GITHUB_TOKEN }} + exempt-issue-labels: "feature request" From b280c629b68765b90bd0b78c788a8dfaee00cc74 Mon Sep 17 00:00:00 2001 From: Bill Klenotiz Date: Tue, 27 Sep 2022 12:43:39 -0400 Subject: [PATCH 02/54] changed to 60 days --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index eeab0d6e..eae8f16f 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/stale@v5 with: - days-before-issue-stale: 90 + days-before-issue-stale: 60 days-before-issue-close: 14 stale-issue-label: "Stale" stale-issue-message: > From 19ab56da1cd5687a595a123166094ed89d6a5b48 Mon Sep 17 00:00:00 2001 From: xiao Date: Mon, 3 Oct 2022 09:25:30 +0900 Subject: [PATCH 03/54] Fix #600: Accept 5 seconds clock skew to avoid `ImmatureSignatureError` --- CHANGELOG | 1 + shopify/session_token.py | 4 ++++ test/session_token_test.py | 7 ++++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 4a283388..bc0fa94b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,5 @@ == Unreleased +- Fix: Accept 10 seconds clock skew to avoid `ImmatureSignatureError` == Version 12.0.0 - Update API version with 2022-04 release, remove API version 2021-07 ([#591](https://github.com/Shopify/shopify_python_api/pull/591)) diff --git a/shopify/session_token.py b/shopify/session_token.py index 19f3105b..91a4970b 100644 --- a/shopify/session_token.py +++ b/shopify/session_token.py @@ -14,6 +14,7 @@ ALGORITHM = "HS256" PREFIX = "Bearer " REQUIRED_FIELDS = ["iss", "dest", "sub", "jti", "sid"] +LEEWAY_SECONDS = 10 class SessionTokenError(Exception): @@ -54,6 +55,9 @@ def _decode_session_token(session_token, api_key, secret): secret, audience=api_key, algorithms=[ALGORITHM], + # AppBridge frequently sends future `nbf`, and it causes `ImmatureSignatureError`. + # Accept few seconds clock skew to avoid this error. + leeway=LEEWAY_SECONDS, options={"require": REQUIRED_FIELDS}, ) except jwt.exceptions.PyJWTError as exception: diff --git a/test/session_token_test.py b/test/session_token_test.py index 38e43808..f94fe0b2 100644 --- a/test/session_token_test.py +++ b/test/session_token_test.py @@ -48,7 +48,7 @@ def test_raises_if_token_authentication_header_is_not_bearer(self): self.assertEqual("The HTTP_AUTHORIZATION_HEADER provided does not contain a Bearer token", str(cm.exception)) def test_raises_jwt_error_if_session_token_is_expired(self): - self.payload["exp"] = timestamp((datetime.now() + timedelta(0, -10))) + self.payload["exp"] = timestamp((datetime.now() + timedelta(0, -11))) with self.assertRaises(session_token.SessionTokenError) as cm: session_token.decode_from_header(self.build_auth_header(), api_key=self.api_key, secret=self.secret) @@ -103,3 +103,8 @@ def test_returns_decoded_payload(self): ) self.assertEqual(self.payload, decoded_payload) + + def test_allow_10_seconds_clock_skew_in_nbf(self): + self.payload["nbf"] = timestamp((datetime.now() + timedelta(seconds=10))) + + session_token.decode_from_header(self.build_auth_header(), api_key=self.api_key, secret=self.secret) From 67b50d0bfea4e7388b938b1abaca41d7428c297a Mon Sep 17 00:00:00 2001 From: Andy Waite Date: Mon, 17 Oct 2022 10:13:53 -0400 Subject: [PATCH 04/54] Format changelog --- CHANGELOG | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index bc0fa94b..7fa7a41d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ == Unreleased -- Fix: Accept 10 seconds clock skew to avoid `ImmatureSignatureError` +- Allow up to 10 seconds clock skew to avoid `ImmatureSignatureError` +([#609](https://github.com/Shopify/shopify_python_api/pull/609)) == Version 12.0.0 - Update API version with 2022-04 release, remove API version 2021-07 ([#591](https://github.com/Shopify/shopify_python_api/pull/591)) From c43e6dd324d4cc538a016718d4df05f45595c605 Mon Sep 17 00:00:00 2001 From: Andy Waite Date: Mon, 17 Oct 2022 10:15:20 -0400 Subject: [PATCH 05/54] Release v12.0.1 --- CHANGELOG | 2 ++ shopify/version.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 7fa7a41d..e4f2619f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,6 @@ == Unreleased + +== Version 12.0.1 - Allow up to 10 seconds clock skew to avoid `ImmatureSignatureError` ([#609](https://github.com/Shopify/shopify_python_api/pull/609)) diff --git a/shopify/version.py b/shopify/version.py index 2a8345bc..08d8f853 100644 --- a/shopify/version.py +++ b/shopify/version.py @@ -1 +1 @@ -VERSION = "12.0.0" +VERSION = "12.0.1" From e7bef94e1acc129d9b6611a95e42195d5f30cff1 Mon Sep 17 00:00:00 2001 From: Andy Waite Date: Mon, 17 Oct 2022 10:18:13 -0400 Subject: [PATCH 06/54] Bump python version for build --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b45a1dfc..4c9bc93e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,7 +6,7 @@ jobs: name: Python ${{ matrix.version }} strategy: matrix: - version: [3.6, 3.10.0] + version: [3.7, 3.10.0] steps: - name: Checkout From 298ddc9838305625d6abcf71593dc967a191f5a7 Mon Sep 17 00:00:00 2001 From: Bill Klenotiz Date: Tue, 18 Oct 2022 15:38:16 -0400 Subject: [PATCH 07/54] lint --- .github/workflows/remove-labels-on-activity.yml | 1 - .github/workflows/stale.yml | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/remove-labels-on-activity.yml b/.github/workflows/remove-labels-on-activity.yml index 48872e95..948801e7 100644 --- a/.github/workflows/remove-labels-on-activity.yml +++ b/.github/workflows/remove-labels-on-activity.yml @@ -13,4 +13,3 @@ jobs: with: labels: | Waiting for Response - diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index eae8f16f..41e94f6d 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -16,10 +16,10 @@ jobs: days-before-issue-close: 14 stale-issue-label: "Stale" stale-issue-message: > - This issue is stale because it has been open for 90 days with no activity. It will be closed if no further action occurs in 14 days. + This issue is stale because it has been open for 90 days with no activity. It will be closed if no further action occurs in 14 days. close-issue-message: | - We are closing this issue because it has been inactive for a few months. - This probably means that it is not reproducible or it has been fixed in a newer version. + We are closing this issue because it has been inactive for a few months. + This probably means that it is not reproducible or it has been fixed in a newer version. If it’s an enhancement and hasn’t been taken on since it was submitted, then it seems other issues have taken priority. If you still encounter this issue with the latest stable version, please reopen using the issue template. You can also contribute directly by submitting a pull request– see the [CONTRIBUTING.md](https://github.com/Shopify/shopify_python_api/blob/master/CONTRIBUTING.md) file for guidelines From 4c6910373e24f2ad123d5e4d216ea5bfa16fd39c Mon Sep 17 00:00:00 2001 From: Bill Klenotiz Date: Tue, 18 Oct 2022 15:44:51 -0400 Subject: [PATCH 08/54] change msg --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 41e94f6d..c194ded1 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -16,7 +16,7 @@ jobs: days-before-issue-close: 14 stale-issue-label: "Stale" stale-issue-message: > - This issue is stale because it has been open for 90 days with no activity. It will be closed if no further action occurs in 14 days. + This issue is stale because it has been open for 60 days with no activity. It will be closed if no further action occurs in 14 days. close-issue-message: | We are closing this issue because it has been inactive for a few months. This probably means that it is not reproducible or it has been fixed in a newer version. From f7f7e92758cf495213ea663273f304c6e26ebe27 Mon Sep 17 00:00:00 2001 From: Bill Klenotiz Date: Wed, 7 Dec 2022 09:16:44 -0500 Subject: [PATCH 09/54] add reason --- .github/workflows/stale.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index c194ded1..6b670540 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -29,3 +29,4 @@ jobs: days-before-pr-close: -1 repo-token: ${{ secrets.GITHUB_TOKEN }} exempt-issue-labels: "feature request" + close-issue-reason: "not_planned" \ No newline at end of file From 20bca2195530206719557461126ed7452a2e758a Mon Sep 17 00:00:00 2001 From: Dylan Thacker-Smith Date: Mon, 12 Dec 2022 09:58:05 -0500 Subject: [PATCH 10/54] Trigger CI on PR events --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4c9bc93e..8127de2c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,5 @@ name: CI -on: [push] +on: [push, pull_request] jobs: build: runs-on: ubuntu-latest From 2a2b0cd77023433d52e1763e5a3c58cdf40ba3b1 Mon Sep 17 00:00:00 2001 From: Kevin O'Sullivan Date: Mon, 12 Dec 2022 14:25:26 -0500 Subject: [PATCH 11/54] Update 3.10.0 to 3.10 to trigger CI --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8127de2c..75aad488 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,7 +6,7 @@ jobs: name: Python ${{ matrix.version }} strategy: matrix: - version: [3.7, 3.10.0] + version: ["3.7", "3.10"] steps: - name: Checkout From 13ae8ed7bdf7908c9f21896a396325f59411ed90 Mon Sep 17 00:00:00 2001 From: Bill Klenotiz Date: Mon, 12 Dec 2022 16:09:27 -0500 Subject: [PATCH 12/54] add new line --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 6b670540..cd1f94c0 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -29,4 +29,4 @@ jobs: days-before-pr-close: -1 repo-token: ${{ secrets.GITHUB_TOKEN }} exempt-issue-labels: "feature request" - close-issue-reason: "not_planned" \ No newline at end of file + close-issue-reason: "not_planned" From a4670ebae6fb36af4bdfa684c250c91cff315a53 Mon Sep 17 00:00:00 2001 From: Bill Klenotiz Date: Mon, 12 Dec 2022 16:44:41 -0500 Subject: [PATCH 13/54] upgrade pylint --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f8b66bfe..5adbcb8a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,6 +11,6 @@ repos: hooks: - id: black - repo: https://github.com/PyCQA/pylint - rev: pylint-2.7.2 + rev: pylint-2.15.8 hooks: - id: pylint From ebb55d6cb53742b622d0da8dc5b6d6538bc9ff95 Mon Sep 17 00:00:00 2001 From: Paulo Margarido <64600052+paulomarg@users.noreply.github.com> Date: Tue, 13 Dec 2022 09:17:58 -0500 Subject: [PATCH 14/54] Update pylint version in CI --- .pre-commit-config.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f8b66bfe..43267923 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,16 +1,16 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: -- repo: https://github.com/pre-commit/pre-commit-hooks + - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.4.0 hooks: - - id: end-of-file-fixer - - id: trailing-whitespace -- repo: https://github.com/psf/black + - id: end-of-file-fixer + - id: trailing-whitespace + - repo: https://github.com/psf/black rev: 22.3.0 hooks: - - id: black -- repo: https://github.com/PyCQA/pylint - rev: pylint-2.7.2 + - id: black + - repo: https://github.com/PyCQA/pylint + rev: v2.15.8 hooks: - - id: pylint + - id: pylint From 8d248d653052ef07f88211c42ef179ea4bfa242b Mon Sep 17 00:00:00 2001 From: Paulo Margarido <64600052+paulomarg@users.noreply.github.com> Date: Tue, 13 Dec 2022 09:28:39 -0500 Subject: [PATCH 15/54] Fix linting errors --- shopify/base.py | 3 --- test/base_test.py | 3 --- test/marketing_event_test.py | 3 --- 3 files changed, 9 deletions(-) diff --git a/shopify/base.py b/shopify/base.py index 47f40cb3..449e288b 100644 --- a/shopify/base.py +++ b/shopify/base.py @@ -17,9 +17,6 @@ class ShopifyConnection(pyactiveresource.connection.Connection): response = None - def __init__(self, site, user=None, password=None, timeout=None, format=formats.JSONFormat): - super(ShopifyConnection, self).__init__(site, user, password, timeout, format) - def _open(self, *args, **kwargs): self.response = None try: diff --git a/test/base_test.py b/test/base_test.py index 5817872e..5cc19a60 100644 --- a/test/base_test.py +++ b/test/base_test.py @@ -17,9 +17,6 @@ def setUpClass(self): def tearDownClass(self): shopify.ApiVersion.clear_defined_versions() - def setUp(self): - super(BaseTest, self).setUp() - def tearDown(self): shopify.ShopifyResource.clear_session() diff --git a/test/marketing_event_test.py b/test/marketing_event_test.py index a3753d63..2f73029d 100644 --- a/test/marketing_event_test.py +++ b/test/marketing_event_test.py @@ -4,9 +4,6 @@ class MarketingEventTest(TestCase): - def setUp(self): - super(MarketingEventTest, self).setUp() - def test_get_marketing_event(self): self.fake("marketing_events/1", method="GET", body=self.load_fixture("marketing_event")) marketing_event = shopify.MarketingEvent.find(1) From 805892e3929bd11c7be27b08f00d1f62f49792e6 Mon Sep 17 00:00:00 2001 From: Rohan Bansal Date: Fri, 28 Oct 2022 16:36:14 +0530 Subject: [PATCH 16/54] feat: update API version to 2022-10 --- CHANGELOG | 1 + shopify/api_version.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index e4f2619f..088dd17f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,5 @@ == Unreleased +- Update API version with 2022-10 release, remove API version 2021-10 == Version 12.0.1 - Allow up to 10 seconds clock skew to avoid `ImmatureSignatureError` diff --git a/shopify/api_version.py b/shopify/api_version.py index 72740b73..5c506c31 100644 --- a/shopify/api_version.py +++ b/shopify/api_version.py @@ -27,10 +27,10 @@ def define_version(cls, version): @classmethod def define_known_versions(cls): cls.define_version(Unstable()) - cls.define_version(Release("2021-10")) cls.define_version(Release("2022-01")) cls.define_version(Release("2022-04")) cls.define_version(Release("2022-07")) + cls.define_version(Release("2022-10")) @classmethod def clear_defined_versions(cls): From 37a639c8735d9b213c4b38249a7e5ad04f57ff0b Mon Sep 17 00:00:00 2001 From: Kevin O'Sullivan Date: Tue, 13 Dec 2022 13:54:34 -0500 Subject: [PATCH 17/54] Add 2022-10 back into api_version.py --- CHANGELOG | 2 +- shopify/api_version.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 088dd17f..c7abf352 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,5 @@ == Unreleased -- Update API version with 2022-10 release, remove API version 2021-10 +- Add API version with 2022-10 release == Version 12.0.1 - Allow up to 10 seconds clock skew to avoid `ImmatureSignatureError` diff --git a/shopify/api_version.py b/shopify/api_version.py index 5c506c31..8beee194 100644 --- a/shopify/api_version.py +++ b/shopify/api_version.py @@ -27,6 +27,7 @@ def define_version(cls, version): @classmethod def define_known_versions(cls): cls.define_version(Unstable()) + cls.define_version(Release("2021-10")) cls.define_version(Release("2022-01")) cls.define_version(Release("2022-04")) cls.define_version(Release("2022-07")) From 72c9ecc4d3b62db709a267d57cece7376e5b8918 Mon Sep 17 00:00:00 2001 From: Kevin O'Sullivan Date: Tue, 13 Dec 2022 14:01:02 -0500 Subject: [PATCH 18/54] Release v12.1.0 --- CHANGELOG | 2 ++ shopify/version.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index c7abf352..76b2277f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,6 @@ == Unreleased + +== Version 12.1.0 - Add API version with 2022-10 release == Version 12.0.1 diff --git a/shopify/version.py b/shopify/version.py index 08d8f853..910a54d5 100644 --- a/shopify/version.py +++ b/shopify/version.py @@ -1 +1 @@ -VERSION = "12.0.1" +VERSION = "12.1.0" From c8906a380afd0480ac72dc1c62b70eca78121143 Mon Sep 17 00:00:00 2001 From: Paulo Margarido <64600052+paulomarg@users.noreply.github.com> Date: Thu, 5 Jan 2023 09:42:06 -0500 Subject: [PATCH 19/54] Add support for version 2023-01 --- CHANGELOG | 282 +++++++++++++++++++++++------------------ shopify/api_version.py | 1 + 2 files changed, 162 insertions(+), 121 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 76b2277f..ab2b1e6b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,20 +1,27 @@ == Unreleased +- Update API version with 2023-01 release ([#](https://github.com/Shopify/shopify_python_api/pull/)) + == Version 12.1.0 + - Add API version with 2022-10 release == Version 12.0.1 + - Allow up to 10 seconds clock skew to avoid `ImmatureSignatureError` -([#609](https://github.com/Shopify/shopify_python_api/pull/609)) + ([#609](https://github.com/Shopify/shopify_python_api/pull/609)) == Version 12.0.0 + - Update API version with 2022-04 release, remove API version 2021-07 ([#591](https://github.com/Shopify/shopify_python_api/pull/591)) == Version 11.0.0 + - Update API version with 2022-04 release - remove API version 2020-10, 2021-01, 2021-04 as they are all unsupported as of 2022-04 == Version 10.0.0 + - Update API version with 2022-01 release, remove API version 2020-07 == Version 9.0.0 @@ -23,18 +30,23 @@ - Update API version with 2021-10 release, remove API version 2020-04 ([#548](https://github.com/Shopify/shopify_python_api/pull/548)) == Version 8.4.2 + - Update API version with 2021-07 release, remove API version 2020-01 ([#521](https://github.com/Shopify/shopify_python_api/pull/521)) == Version 8.4.1 + - Bug fix: `sanitize_shop_domain` now returns `None` rather than `'none.myshopify.com'` if no `shop_domain` arg is passed in ([#499](https://github.com/Shopify/shopify_python_api/pull/499)) == Version 8.4.0 + - Revert Feature #441 Dynamic API Versioning ([#495](https://github.com/Shopify/shopify_python_api/pull/495)) == Version 8.3.1 + - Fix bug: Add the `shopify/utils` sub-package when building the source distribution ([#493](https://github.com/Shopify/shopify_python_api/pull/493)) == Version 8.3.0 + - Add support for [session tokens](https://shopify.dev/concepts/apps/building-embedded-apps-using-session-tokens) ([#479](https://github.com/Shopify/shopify_python_api/pull/479)) - Use `session_token.decode_from_header` to obtain a decoded session token from an HTTP Authorization header - Create a `utils` sub-package with a `shop_url` utility file ([#483](https://github.com/Shopify/shopify_python_api/pull/483)) @@ -48,297 +60,325 @@ - Add support for retrieving all orders using customer_id ([#466](https://github.com/Shopify/shopify_python_api/pull/466)) == Version 8.2.0 + - [Feature] Add support for Dynamic API Versioning. When the library is initialized, it will now make a request to -Shopify to fetch a list of the available API versions. ([#441](https://github.com/Shopify/shopify_python_api/pull/441)) + Shopify to fetch a list of the available API versions. ([#441](https://github.com/Shopify/shopify_python_api/pull/441)) == Version 8.1.0 + - [Feature] Add support for Shopify Payments resources (#428) == Version 8.0.4 + - Release API version 2020-10 - Deprecate API version 2019-10 == Version 8.0.3 -- Patch for replacing call to _build_list() with _build_collection() in gift_card.py + +- Patch for replacing call to \_build_list() with \_build_collection() in gift_card.py == Version 8.0.2 + - Patch for product updating with variants == Version 8.0.1 + - release api version 2020-07 - deprecate api version 2019-07 - Add support for FulfillmentOrder resource (#390) == Version 8.0.0 + - release api version 2020-04 - deprecate api version 2019-04 == Version 7.0.3 + - bug fix for temporary sessions - deprecation fix for regexs == Version 7.0.2 + - bug fix for variant updates after the 2019-10 api version == Version 7.0.1 + - bug fix for string interpolation == Version 7.0.0 -* Made no_iter_next default to True on collection so that by default it only -fetches a single page -* Passes kwargs to paginated collections so that attributes can be set with -find() -* Allow case insensitive check for the link header for cursor pagination. + +- Made no_iter_next default to True on collection so that by default it only + fetches a single page +- Passes kwargs to paginated collections so that attributes can be set with + find() +- Allow case insensitive check for the link header for cursor pagination. == Version 6.0.1 -* Made the collection access more consistent so that there is no confusion -between a collection and a paginated collection + +- Made the collection access more consistent so that there is no confusion + between a collection and a paginated collection == Version 6.0.0 -* Add Cursor pagination support + +- Add Cursor pagination support == Version 5.1.2 -* Add version 2020-01 to known ApiVersions. This version will not be usable until October 2019. + +- Add version 2020-01 to known ApiVersions. This version will not be usable until October 2019. == Version 5.1.1 -* Fix initializing API with basic auth URL. + +- Fix initializing API with basic auth URL. == Version 5.1.0 -* Added support for GraphQL queries with a GraphQL resource + +- Added support for GraphQL queries with a GraphQL resource == Version 5.0.1 -* Fixing missing class variable causing exception when creating a session without a token + +- Fixing missing class variable causing exception when creating a session without a token == Version 5.0.0 -* Added support for Shopify API Versioning + +- Added support for Shopify API Versioning == Version 4.0.0 -* Added AccessScope resource -* Added ApiPermission resource -* Added User resource -* Added Publication, CollectionPublication and ProductPublication resources -* Added Currency resource -* Added TenderTransaction resource -* Added shopify.Limits class, for retrieving the current status of Shopify rate limiting. -* Added support for Refund.calculate -* Added support for Location.inventory_levels -* Added support for PriceRule batch operations -* Removed `cancel()` method for RecurringApplicationCharge resource (use `destroy()` going forward) -* Fix for handling array query parameters (e.g. `foo[]=1&foo[]=2`) during HMAC calculation -* Fixed Python 3 compatibility with the API console + +- Added AccessScope resource +- Added ApiPermission resource +- Added User resource +- Added Publication, CollectionPublication and ProductPublication resources +- Added Currency resource +- Added TenderTransaction resource +- Added shopify.Limits class, for retrieving the current status of Shopify rate limiting. +- Added support for Refund.calculate +- Added support for Location.inventory_levels +- Added support for PriceRule batch operations +- Removed `cancel()` method for RecurringApplicationCharge resource (use `destroy()` going forward) +- Fix for handling array query parameters (e.g. `foo[]=1&foo[]=2`) during HMAC calculation +- Fixed Python 3 compatibility with the API console == Version 3.1.0 -* Adds InventoryItem resource -* Adds InventoryLevel resource -* Adds GiftCardAdjustment resource -* Fix to properly handle byte data for Asset.attach() + +- Adds InventoryItem resource +- Adds InventoryLevel resource +- Adds GiftCardAdjustment resource +- Fix to properly handle byte data for Asset.attach() == Version 3.0.0 -* Added CollectListing resource -* Added ResourceFeedback resource -* Added StorefrontAccessToken resource -* Added ProductListing resource -* Removed deprecated ProductSearchEngine resource -* Removed deprecated Discount resource -* Fixed Python3 compatibility issue with `Image.attach_image()` + +- Added CollectListing resource +- Added ResourceFeedback resource +- Added StorefrontAccessToken resource +- Added ProductListing resource +- Removed deprecated ProductSearchEngine resource +- Removed deprecated Discount resource +- Fixed Python3 compatibility issue with `Image.attach_image()` == Version 2.6.0 -* Added support for Marketing Event API through Marketing Event resource + +- Added support for Marketing Event API through Marketing Event resource == Version 2.5.1 -* Fixed an issue preventing creation of Order Risk resources + +- Fixed an issue preventing creation of Order Risk resources == Version 2.5.0 -* Added Price Rule and Discount Code resources + +- Added Price Rule and Discount Code resources == Version 2.4.0 -* Add support for report publishing + +- Add support for report publishing == Version 2.3.0 -* Add support for customer#send_invite + +- Add support for customer#send_invite == Version 2.2.0 -* Add support for draft orders + +- Add support for draft orders == Version 2.1.8 -* Added support for `open` method on fulfillments + +- Added support for `open` method on fulfillments == Version 2.1.7 -* Removed all references to the deprecated MD5 `signature` parameter which is no longer provided by Shopify. +- Removed all references to the deprecated MD5 `signature` parameter which is no longer provided by Shopify. == Version 2.1.6 -* Added Refund resource +- Added Refund resource == Version 2.1.5 -* bump pyactiveresource for camelcase bugfix +- bump pyactiveresource for camelcase bugfix == Version 2.1.4 == Version 2.1.3 -* Fixed hmac signature validation for params with delimiters (`&`, `=` or `%`) +- Fixed hmac signature validation for params with delimiters (`&`, `=` or `%`) == Version 2.1.2 -* Fixed an issue with unicode strings in params passed to validate_hmac -* Added shop domain verification when creating a session +- Fixed an issue with unicode strings in params passed to validate_hmac +- Added shop domain verification when creating a session == Version 2.1.1 -* Added Checkout resource -* Updated to pyactiveresource v2.1.1 which includes a test-related bugfix -* Changed OAuth validation from MD5 to HMAC-SHA256 +- Added Checkout resource +- Updated to pyactiveresource v2.1.1 which includes a test-related bugfix +- Changed OAuth validation from MD5 to HMAC-SHA256 == Version 2.1.0 -* Added python 3 compatibility -* Fixed setting the format attribute on carrier and fulfillment services -* Add a specific exception for signature validation failures +- Added python 3 compatibility +- Fixed setting the format attribute on carrier and fulfillment services +- Add a specific exception for signature validation failures == Version 2.0.4 -* Bug fixes -* Added CarrierService resource -* Added Property resource to LineItem +- Bug fixes +- Added CarrierService resource +- Added Property resource to LineItem == Version 2.0.3 -* Add Order Risk resource +- Add Order Risk resource == Version 2.0.2 -* Add access to FulfillmentService endpoint -* Fix some import bugs +- Add access to FulfillmentService endpoint +- Fix some import bugs == Version 2.0.1 -* Package bug fix +- Package bug fix == Version 2.0.0 -* Removed support for legacy auth -* Updated to pyactiveresource v2.0.0 which changes the default form to JSON -* in Session::request_token params is no longer optional, you must pass all the params +- Removed support for legacy auth +- Updated to pyactiveresource v2.0.0 which changes the default form to JSON +- in Session::request_token params is no longer optional, you must pass all the params and the method will now extract the code -* made create_permission_url an instance method, you'll need an instance +- made create_permission_url an instance method, you'll need an instance of session to call this method from now on -* Updated session.request_token -* Updated Session to better match the ShopifyAPI Ruby gem -* Updated the readme to better describe how to use the library -* Added support for CustomerSavedSearch (CustomerGroup is deprecated) +- Updated session.request_token +- Updated Session to better match the ShopifyAPI Ruby gem +- Updated the readme to better describe how to use the library +- Added support for CustomerSavedSearch (CustomerGroup is deprecated) == Version 1.0.7 -* Fix thread local headers to store a copy of the default hash which -prevents activate_session in one thread from affecting other threads. +- Fix thread local headers to store a copy of the default hash which + prevents activate_session in one thread from affecting other threads. == Version 1.0.6 -* Fix deserializing and serializing fulfillments which can now contain -arrays of strings in the tracking_urls attribute. +- Fix deserializing and serializing fulfillments which can now contain + arrays of strings in the tracking_urls attribute. == Version 1.0.5 -* Fix parameter passing for order cancellation. -* Fix Product.price_range method for variants with different prices. +- Fix parameter passing for order cancellation. +- Fix Product.price_range method for variants with different prices. == Version 1.0.4 -* Fixed another bug in Image size methods regex. +- Fixed another bug in Image size methods regex. == Version 1.0.3 -* Fix bug in setting format attribute on Webhook instances. -* Fixed missing slash in return value of Image size methods -* Upgrade pyactiveresource to fix unicode encoding issues +- Fix bug in setting format attribute on Webhook instances. +- Fixed missing slash in return value of Image size methods +- Upgrade pyactiveresource to fix unicode encoding issues == Version 1.0.2 -* Made ShopifyResource.clear_session idempotent. +- Made ShopifyResource.clear_session idempotent. == Version 1.0.1 -* Use the correct redirect parameter in Session.create_permission_url. -Was redirect_url but corrected to redirect_uri. +- Use the correct redirect parameter in Session.create_permission_url. + Was redirect_url but corrected to redirect_uri. == Version 1.0.0 -* Added support for OAuth2. -* ShopifyResource.activate_session must now be used with OAuth2 instead -of setting ShopifyResource.site directly. -* Session.__init__ no longer allows params to be passed in as **params -* Session.__init__ now makes an HTTP request when using OAuth2 if -params are specified -* Session now exposes the access token through the token instance -variable to simplify session saving and resuming +- Added support for OAuth2. +- ShopifyResource.activate_session must now be used with OAuth2 instead + of setting ShopifyResource.site directly. +- Session.**init** no longer allows params to be passed in as \*\*params +- Session.**init** now makes an HTTP request when using OAuth2 if + params are specified +- Session now exposes the access token through the token instance + variable to simplify session saving and resuming == Version 0.4.0 -* Using setup.py no longer requires all dependencies -* More compatibility fixes for using the latest pyactiveresource -* ShopifyResource.activate_session is not recommended over setting site -directly for forward compatibility with coming OAuth2 changes. +- Using setup.py no longer requires all dependencies +- More compatibility fixes for using the latest pyactiveresource +- ShopifyResource.activate_session is not recommended over setting site + directly for forward compatibility with coming OAuth2 changes. == Version 0.3.1 -* Compatibility fixes for using latest (unreleased) pyactiveresource +- Compatibility fixes for using latest (unreleased) pyactiveresource == Version 0.3.0 -* Added support for customer search and customer group search. -* Resource errors are cleared on save from previous save attempt. -* Made the library thread-safe using thread-local connections. +- Added support for customer search and customer group search. +- Resource errors are cleared on save from previous save attempt. +- Made the library thread-safe using thread-local connections. == Version 0.2.1 -* Fixed a regression that caused a different connection -object to be created on each resource. +- Fixed a regression that caused a different connection + object to be created on each resource. == Version 0.2.0 -* Made responses available through the connection object. +- Made responses available through the connection object. == Version 0.1.8 -* Added ability to add metafields on customers. +- Added ability to add metafields on customers. == Version 0.1.7 -* Fixed missing theme_id in return value of Asset.find. +- Fixed missing theme_id in return value of Asset.find. == Version 0.1.6 -* Fixed attribute setting on Asset objects -* Strip path from shop_url to get just the shop's domain. +- Fixed attribute setting on Asset objects +- Strip path from shop_url to get just the shop's domain. == Version 0.1.5 -* Fixed Asset.find() -* Fixed Variant.find(id) -* Allow running from source directory with PYTHONPATH=./lib +- Fixed Asset.find() +- Fixed Variant.find(id) +- Allow running from source directory with PYTHONPATH=./lib == Version 0.1.4 -* Fixed a bug in metafields method caused by missing import. -* Prefix options can be specified in the attributes dict on creation -* Allow count method to be used the same way as find +- Fixed a bug in metafields method caused by missing import. +- Prefix options can be specified in the attributes dict on creation +- Allow count method to be used the same way as find == Version 0.1.3 -* Fixed the automatic download of dependencies. -* Updated the README instructions. +- Fixed the automatic download of dependencies. +- Updated the README instructions. == Version 0.1.2 -* Add python 2.5 compatibility +- Add python 2.5 compatibility == Version 0.1.1 -* Make creating a session simpler with django +- Make creating a session simpler with django == Version 0.1.0 -* ported ShopifyAPI from ruby to python +- ported ShopifyAPI from ruby to python diff --git a/shopify/api_version.py b/shopify/api_version.py index 8beee194..df2bc5bb 100644 --- a/shopify/api_version.py +++ b/shopify/api_version.py @@ -32,6 +32,7 @@ def define_known_versions(cls): cls.define_version(Release("2022-04")) cls.define_version(Release("2022-07")) cls.define_version(Release("2022-10")) + cls.define_version(Release("2023-01")) @classmethod def clear_defined_versions(cls): From b00e5061da834e74d49bd311b80760e755e99782 Mon Sep 17 00:00:00 2001 From: Paulo Margarido <64600052+paulomarg@users.noreply.github.com> Date: Thu, 5 Jan 2023 11:39:00 -0500 Subject: [PATCH 20/54] Release v12.2.0 --- CHANGELOG | 4 +++- shopify/version.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ab2b1e6b..0fede9d6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ == Unreleased -- Update API version with 2023-01 release ([#](https://github.com/Shopify/shopify_python_api/pull/)) +== Version 12.2.0 + +- Update API version with 2023-01 release ([#631](https://github.com/Shopify/shopify_python_api/pull/631)) == Version 12.1.0 diff --git a/shopify/version.py b/shopify/version.py index 910a54d5..e77ed636 100644 --- a/shopify/version.py +++ b/shopify/version.py @@ -1 +1 @@ -VERSION = "12.1.0" +VERSION = "12.2.0" From 4f21cbc843df44e41f1a3adc8b66fdbf65c3f762 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Wed, 12 Apr 2023 07:51:42 +0100 Subject: [PATCH 21/54] Remove unused cgi import --- CHANGELOG | 2 ++ shopify/collection.py | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0fede9d6..cacf47b7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,7 @@ == Unreleased +- Remove `cgi` import to avoid triggering a `DeprecationWarning` on Python 3.11. + == Version 12.2.0 - Update API version with 2023-01 release ([#631](https://github.com/Shopify/shopify_python_api/pull/631)) diff --git a/shopify/collection.py b/shopify/collection.py index 42bc8ebb..62728eb9 100644 --- a/shopify/collection.py +++ b/shopify/collection.py @@ -1,6 +1,4 @@ from pyactiveresource.collection import Collection -from six.moves.urllib.parse import urlparse, parse_qs -import cgi class PaginatedCollection(Collection): From 5f72f840f02db4e2bec9c094f4c9544bfc2a2ba7 Mon Sep 17 00:00:00 2001 From: Kevin O'Sullivan Date: Wed, 12 Apr 2023 11:41:51 -0400 Subject: [PATCH 22/54] Add API release 2023-04 --- shopify/api_version.py | 1 + 1 file changed, 1 insertion(+) diff --git a/shopify/api_version.py b/shopify/api_version.py index df2bc5bb..049ee45c 100644 --- a/shopify/api_version.py +++ b/shopify/api_version.py @@ -33,6 +33,7 @@ def define_known_versions(cls): cls.define_version(Release("2022-07")) cls.define_version(Release("2022-10")) cls.define_version(Release("2023-01")) + cls.define_version(Release("2023-04")) @classmethod def clear_defined_versions(cls): From 91945a47639b85013f81223349fe61655dc5f8de Mon Sep 17 00:00:00 2001 From: Kevin O'Sullivan Date: Wed, 12 Apr 2023 11:43:53 -0400 Subject: [PATCH 23/54] Update CHANGELOG --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 0fede9d6..796971ff 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,7 @@ == Unreleased +- Update API version with 2023-04 release ([#649](https://github.com/Shopify/shopify_python_api/pull/649)) + == Version 12.2.0 - Update API version with 2023-01 release ([#631](https://github.com/Shopify/shopify_python_api/pull/631)) From cfc417fbd5e9c268da92cd00a25a74b6b3ffec95 Mon Sep 17 00:00:00 2001 From: Kevin O'Sullivan Date: Wed, 12 Apr 2023 11:46:16 -0400 Subject: [PATCH 24/54] Add 3.8, 3.9 and 3.11 to test matrix --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 75aad488..2a44a442 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,13 +6,13 @@ jobs: name: Python ${{ matrix.version }} strategy: matrix: - version: ["3.7", "3.10"] + version: ["3.7", "3.8", "3.9", "3.10", "3.11"] steps: - name: Checkout uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.version }} - name: Install Dependencies From 8d8e01e0330c1d9e256f4eee73d4b8b5d2116cd3 Mon Sep 17 00:00:00 2001 From: Kevin O'Sullivan Date: Wed, 12 Apr 2023 11:52:12 -0400 Subject: [PATCH 25/54] Update setup.py with additional versions --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index a798cb78..dae5a810 100755 --- a/setup.py +++ b/setup.py @@ -39,11 +39,11 @@ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules", From 5f295932bebbdde1835d35c4865093ff83564cdc Mon Sep 17 00:00:00 2001 From: Kevin O'Sullivan Date: Wed, 12 Apr 2023 12:10:00 -0400 Subject: [PATCH 26/54] Release v12.3.0 --- CHANGELOG | 2 ++ shopify/version.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 796971ff..868d99c1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,7 @@ == Unreleased +== Version 12.3.0 + - Update API version with 2023-04 release ([#649](https://github.com/Shopify/shopify_python_api/pull/649)) == Version 12.2.0 diff --git a/shopify/version.py b/shopify/version.py index e77ed636..a48d177f 100644 --- a/shopify/version.py +++ b/shopify/version.py @@ -1 +1 @@ -VERSION = "12.2.0" +VERSION = "12.3.0" From df252c81c47e993d3a07cb0bb62c643f483dec02 Mon Sep 17 00:00:00 2001 From: Lewis Morris <36413348+lewis-morris@users.noreply.github.com> Date: Thu, 14 Sep 2023 21:51:35 +0100 Subject: [PATCH 27/54] Update README.md no imports listed in guide --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d473a015..cc61c076 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ pip install --upgrade ShopifyAPI 1. We then need to supply these keys to the Shopify Session Class so that it knows how to authenticate. ```python + import shopify shopify.Session.setup(api_key=API_KEY, secret=API_SECRET) ``` 1. In order to access a shop's data, apps need an access token from that specific shop. We need to authenticate with that shop using OAuth, which we can start in the following way: From 454481d70cfb8acc23ef67ddddaa097ecca9c88f Mon Sep 17 00:00:00 2001 From: Alessandro <72794815+alemrcc@users.noreply.github.com> Date: Wed, 29 Nov 2023 21:05:17 +0100 Subject: [PATCH 28/54] I added a bit more information about the usage of the method find() and the usage of parameters since it took me a while to figure out how to do it. --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index d473a015..3f9aa737 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,12 @@ product.destroy() # Delete the resource from the remote server (i.e. Shopify) ``` +Here is another example to retrieve a list of open orders using certain parameters: + +```python +new_orders = shopify.Order.find(status="open", limit="50") +``` + ### Prefix options Some resources such as `Fulfillment` are prefixed by a parent resource in the Shopify API (e.g. `orders/450789469/fulfillments/255858046`). In order to interact with these resources, you must specify the identifier of the parent resource in your request. From 5165407f50d7784c21c32d12e3b47c875647792d Mon Sep 17 00:00:00 2001 From: Paulo Margarido <64600052+paulomarg@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:22:02 -0300 Subject: [PATCH 29/54] Add support for missing API versions --- .github/workflows/pre-commit.yml | 2 +- CHANGELOG | 2 ++ shopify/api_version.py | 3 +++ test/session_token_test.py | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 54fc61d5..048bc5a2 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -12,6 +12,6 @@ jobs: - name: Checkout uses: actions/checkout@v2 - name: Setup - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 - name: Pre-commit uses: pre-commit/action@v2.0.0 diff --git a/CHANGELOG b/CHANGELOG index 868d99c1..3fb31f2c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,7 @@ == Unreleased +- Update API version with 2023-07, 2023-10, 2024-01 releases ([#694](https://github.com/Shopify/shopify_python_api/pull/694)) + == Version 12.3.0 - Update API version with 2023-04 release ([#649](https://github.com/Shopify/shopify_python_api/pull/649)) diff --git a/shopify/api_version.py b/shopify/api_version.py index 049ee45c..ba137d57 100644 --- a/shopify/api_version.py +++ b/shopify/api_version.py @@ -34,6 +34,9 @@ def define_known_versions(cls): cls.define_version(Release("2022-10")) cls.define_version(Release("2023-01")) cls.define_version(Release("2023-04")) + cls.define_version(Release("2023-07")) + cls.define_version(Release("2023-10")) + cls.define_version(Release("2024-01")) @classmethod def clear_defined_versions(cls): diff --git a/test/session_token_test.py b/test/session_token_test.py index f94fe0b2..0df7147f 100644 --- a/test/session_token_test.py +++ b/test/session_token_test.py @@ -79,7 +79,7 @@ def test_raises_if_aud_doesnt_match_api_key(self): with self.assertRaises(session_token.SessionTokenError) as cm: session_token.decode_from_header(self.build_auth_header(), api_key=self.api_key, secret=self.secret) - self.assertEqual("Invalid audience", str(cm.exception)) + self.assertEqual("Audience doesn't match", str(cm.exception)) def test_raises_if_issuer_hostname_is_invalid(self): self.payload["iss"] = "bad_shop_hostname" From 2b1561b9f4a08676410dee6299c6365bd0649b06 Mon Sep 17 00:00:00 2001 From: Melanie Wang Date: Wed, 10 Jan 2024 16:04:36 -0500 Subject: [PATCH 30/54] Release v12.4.0 --- CHANGELOG | 2 ++ shopify/version.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 3fb31f2c..fb65b5a9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,7 @@ == Unreleased +== 12.4.0 + - Update API version with 2023-07, 2023-10, 2024-01 releases ([#694](https://github.com/Shopify/shopify_python_api/pull/694)) == Version 12.3.0 diff --git a/shopify/version.py b/shopify/version.py index a48d177f..7c16e69e 100644 --- a/shopify/version.py +++ b/shopify/version.py @@ -1 +1 @@ -VERSION = "12.3.0" +VERSION = "12.4.0" From c1df76338fb779784b31a0c79c79d2faa0605446 Mon Sep 17 00:00:00 2001 From: Fai Date: Fri, 19 Jan 2024 23:31:32 +0800 Subject: [PATCH 31/54] Add ipython support for console interaction --- scripts/shopify_api.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/shopify_api.py b/scripts/shopify_api.py index 141f4bee..5dfab93a 100755 --- a/scripts/shopify_api.py +++ b/scripts/shopify_api.py @@ -16,10 +16,18 @@ def start_interpreter(**variables): # add the current working directory to the sys paths sys.path.append(os.getcwd()) - console = type("shopify " + shopify.version.VERSION, (code.InteractiveConsole, object), {}) - import readline + try: + from IPython import start_ipython + from traitlets.config.loader import Config - console(variables).interact() + config = Config(TerminalInteractiveShell={"banner2": "(shopify %s)" % shopify.version.VERSION}) + start_ipython(argv=[], user_ns=variables, config=config) + + except ImportError: + console = type("shopify " + shopify.version.VERSION, (code.InteractiveConsole, object), {}) + import readline + + console(variables).interact() class ConfigFileError(Exception): From 65b2408d97e03e646de66094e61f2766b4bcdd52 Mon Sep 17 00:00:00 2001 From: Luke Singham Date: Wed, 24 Jan 2024 13:31:22 +0000 Subject: [PATCH 32/54] Add code highlighting code block --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d473a015..eb051f4c 100644 --- a/README.md +++ b/README.md @@ -242,7 +242,7 @@ python setup.py test ## Relative Cursor Pagination Cursor based pagination support has been added in 6.0.0. -``` +```python import shopify page1 = shopify.Product.find() From 832a53d1f964004a677f29e3bc1727180883c21a Mon Sep 17 00:00:00 2001 From: Ju Liu Date: Tue, 13 Feb 2024 11:33:08 +0000 Subject: [PATCH 33/54] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d67ba2b..2329b18c 100644 --- a/README.md +++ b/README.md @@ -47,13 +47,14 @@ pip install --upgrade ShopifyAPI ```python import shopify + shopify.Session.setup(api_key=API_KEY, secret=API_SECRET) ``` 1. In order to access a shop's data, apps need an access token from that specific shop. We need to authenticate with that shop using OAuth, which we can start in the following way: ```python shop_url = "SHOP_NAME.myshopify.com" - api_version = '2020-10' + api_version = '2024-01' state = binascii.b2a_hex(os.urandom(15)).decode("utf-8") redirect_uri = "http://myapp.com/auth/shopify/callback" scopes = ['read_products', 'read_orders'] From 8c2931fe535b183fe5616bb4b668a97b92f5dfff Mon Sep 17 00:00:00 2001 From: Ju Liu Date: Tue, 13 Feb 2024 11:34:28 +0000 Subject: [PATCH 34/54] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2329b18c..7dc84ed5 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ pip install --upgrade ShopifyAPI ```python import shopify - + shopify.Session.setup(api_key=API_KEY, secret=API_SECRET) ``` 1. In order to access a shop's data, apps need an access token from that specific shop. We need to authenticate with that shop using OAuth, which we can start in the following way: From 81252346c63cb51d25ebdd1e0d44c85b68aa7479 Mon Sep 17 00:00:00 2001 From: Elizabeth Kenyon Date: Mon, 8 Apr 2024 13:43:41 -0500 Subject: [PATCH 35/54] Add support for April24 API version --- CHANGELOG | 1 + shopify/api_version.py | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index c7309ca8..0a0c47e4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ == Unreleased - Remove `cgi` import to avoid triggering a `DeprecationWarning` on Python 3.11. +- Update API version with 2024-04 release. == Version 12.4.0 diff --git a/shopify/api_version.py b/shopify/api_version.py index ba137d57..a0a1531e 100644 --- a/shopify/api_version.py +++ b/shopify/api_version.py @@ -37,6 +37,7 @@ def define_known_versions(cls): cls.define_version(Release("2023-07")) cls.define_version(Release("2023-10")) cls.define_version(Release("2024-01")) + cls.define_version(Release("2024-04")) @classmethod def clear_defined_versions(cls): From 74373bfc93ddc2539b2bd442f5ea2876ec5345ec Mon Sep 17 00:00:00 2001 From: Elizabeth Kenyon Date: Mon, 8 Apr 2024 14:58:51 -0500 Subject: [PATCH 36/54] Update codecov action Testing to see if this resolves the pipeline failures --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2a44a442..58a2a8cb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,7 @@ jobs: - name: Run Tests run: python -m pytest -v - name: upload coverage to Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: name: codecov-umbrella fail_ci_if_error: true From 8029a749cafeac18a95fe5546867a369a4c719c8 Mon Sep 17 00:00:00 2001 From: Elizabeth Kenyon Date: Tue, 9 Apr 2024 09:53:00 -0500 Subject: [PATCH 37/54] turn off CI failure for codecov We are getting increasing failures because of this task --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 58a2a8cb..e7ec6d36 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,7 @@ jobs: - name: Run Tests run: python -m pytest -v - name: upload coverage to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v1 with: name: codecov-umbrella - fail_ci_if_error: true + fail_ci_if_error: false From 65f5ce2a6f30d49995c8af6ff52796f5a0ffe9cc Mon Sep 17 00:00:00 2001 From: Elizabeth Kenyon Date: Tue, 9 Apr 2024 10:28:01 -0500 Subject: [PATCH 38/54] Preparing for release --- CHANGELOG | 3 ++- shopify/version.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0a0c47e4..c4462f6e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,8 @@ == Unreleased +== Version 12.5.0 - Remove `cgi` import to avoid triggering a `DeprecationWarning` on Python 3.11. -- Update API version with 2024-04 release. +- Update API version with 2024-04 release.([710](https://github.com/Shopify/shopify_python_api/pull/710)) == Version 12.4.0 diff --git a/shopify/version.py b/shopify/version.py index 7c16e69e..3958d1de 100644 --- a/shopify/version.py +++ b/shopify/version.py @@ -1 +1 @@ -VERSION = "12.4.0" +VERSION = "12.5.0" From 2ef7f2219fe06260e7af4d7ca531f9a8f9f3db3d Mon Sep 17 00:00:00 2001 From: bvoelsch Date: Thu, 11 Jan 2024 15:08:14 -0700 Subject: [PATCH 39/54] Update __init__.py Add FulfillmentV2 method to init --- shopify/resources/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shopify/resources/__init__.py b/shopify/resources/__init__.py index 16220739..0d420b38 100644 --- a/shopify/resources/__init__.py +++ b/shopify/resources/__init__.py @@ -38,7 +38,7 @@ from .page import Page from .country import Country from .refund import Refund -from .fulfillment import Fulfillment, FulfillmentOrders +from .fulfillment import Fulfillment, FulfillmentOrders, FulfillmentV2 from .fulfillment_event import FulfillmentEvent from .fulfillment_service import FulfillmentService from .carrier_service import CarrierService From a9277784740ef03c2789c868dfb957b3e670725a Mon Sep 17 00:00:00 2001 From: Matteo Depalo Date: Wed, 22 May 2024 15:43:20 +0100 Subject: [PATCH 40/54] Rename master to main --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/stale.yml | 2 +- README.md | 34 ++++++++++++++++++++------------ RELEASING | 2 +- SECURITY.md | 2 +- 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 048bc5a2..f92848d7 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -3,7 +3,7 @@ name: pre-commit on: pull_request: push: - branches: [master] + branches: [main] jobs: pre-commit: diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index cd1f94c0..2d0a3ec7 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -22,7 +22,7 @@ jobs: This probably means that it is not reproducible or it has been fixed in a newer version. If it’s an enhancement and hasn’t been taken on since it was submitted, then it seems other issues have taken priority. - If you still encounter this issue with the latest stable version, please reopen using the issue template. You can also contribute directly by submitting a pull request– see the [CONTRIBUTING.md](https://github.com/Shopify/shopify_python_api/blob/master/CONTRIBUTING.md) file for guidelines + If you still encounter this issue with the latest stable version, please reopen using the issue template. You can also contribute directly by submitting a pull request– see the [CONTRIBUTING.md](https://github.com/Shopify/shopify_python_api/blob/main/CONTRIBUTING.md) file for guidelines Thank you! days-before-pr-stale: -1 diff --git a/README.md b/README.md index 7dc84ed5..d8519b1b 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ [![Build Status](https://github.com/Shopify/shopify_python_api/workflows/CI/badge.svg)](https://github.com/Shopify/shopify_python_api/actions) [![PyPI version](https://badge.fury.io/py/ShopifyAPI.svg)](https://badge.fury.io/py/ShopifyAPI) -[![codecov](https://codecov.io/gh/Shopify/shopify_python_api/branch/master/graph/badge.svg?token=pNTx0TARUx)](https://codecov.io/gh/Shopify/shopify_python_api) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/Shopify/shopify_python_api/blob/master/LICENSE) +[![codecov](https://codecov.io/gh/Shopify/shopify_python_api/branch/main/graph/badge.svg?token=pNTx0TARUx)](https://codecov.io/gh/Shopify/shopify_python_api) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/Shopify/shopify_python_api/blob/main/LICENSE) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) The [Shopify Admin API](https://shopify.dev/docs/admin-api) Python Library @@ -23,20 +23,28 @@ pip install --upgrade ShopifyAPI ### Table of Contents -- [Getting Started](#getting-started) - - [Public and Custom Apps](#public-and-custom-apps) - - [Private Apps](#private-apps) -- [Billing](#billing) -- [Session Tokens](docs/session-tokens.md) -- [Handling Access Scope Operations](docs/api-access.md) -- [Advanced Usage](#advanced-usage) -- [Prefix Options](#prefix-options) -- [Console](#console) -- [GraphQL](#graphql) +- [Usage](#usage) + - [Requirements](#requirements) + - [Installation](#installation) + - [Table of Contents](#table-of-contents) + - [Getting Started](#getting-started) + - [Public and Custom Apps](#public-and-custom-apps) + - [Private Apps](#private-apps) + - [With full session](#with-full-session) + - [With temporary session](#with-temporary-session) + - [Billing](#billing) + - [Advanced Usage](#advanced-usage) + - [Prefix options](#prefix-options) + - [Console](#console) + - [GraphQL](#graphql) - [Using Development Version](#using-development-version) + - [Building and installing dev version](#building-and-installing-dev-version) + - [Running Tests](#running-tests) - [Relative Cursor Pagination](#relative-cursor-pagination) +- [Set up pre-commit locally \[OPTIONAL\]](#set-up-pre-commit-locally-optional) - [Limitations](#limitations) - [Additional Resources](#additional-resources) + - [Sample apps built using this library](#sample-apps-built-using-this-library) ### Getting Started @@ -263,7 +271,7 @@ page2 = shopify.Product.find(from_=next_url) ``` ## Set up pre-commit locally [OPTIONAL] -[Pre-commit](https://pre-commit.com/) is set up as a GitHub action that runs on pull requests and pushes to the `master` branch. If you want to run pre-commit locally, install it and set up the git hook scripts +[Pre-commit](https://pre-commit.com/) is set up as a GitHub action that runs on pull requests and pushes to the `main` branch. If you want to run pre-commit locally, install it and set up the git hook scripts ```shell pip install -r requirements.txt pre-commit install diff --git a/RELEASING b/RELEASING index f84fa314..a15667a0 100644 --- a/RELEASING +++ b/RELEASING @@ -15,6 +15,6 @@ Releasing shopify_python_api git tag -m "Release X.Y.Z" vX.Y.Z 7. Push the changes to github - git push --tags origin master + git push --tags origin main 8. Shipit! diff --git a/SECURITY.md b/SECURITY.md index 2d13b5e1..2a0e9c48 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,7 +4,7 @@ ### New features -New features will only be added to the master branch and will not be made available in point releases. +New features will only be added to the main branch and will not be made available in point releases. ### Bug fixes From 741555f072d41309d1233fe07e08977715498aa6 Mon Sep 17 00:00:00 2001 From: Paulo Margarido <64600052+paulomarg@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:19:41 -0400 Subject: [PATCH 41/54] Add support for 2024-07 API version --- .github/workflows/build.yml | 4 ++-- CHANGELOG | 3 +++ README.md | 2 +- shopify/api_version.py | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e7ec6d36..c0cd5ab9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,7 +6,7 @@ jobs: name: Python ${{ matrix.version }} strategy: matrix: - version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + version: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - name: Checkout @@ -18,7 +18,7 @@ jobs: - name: Install Dependencies run: | python -m pip install --upgrade pip - pip install pytest mock pytest-cov + pip install pytest mock pytest-cov setuptools python setup.py install pytest --cov=./ --cov-report=xml - name: Run Tests diff --git a/CHANGELOG b/CHANGELOG index c4462f6e..24fb1752 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ == Unreleased +- Update API version with 2024-07 release ([#](https://github.com/Shopify/shopify_python_api/pull/)) + == Version 12.5.0 + - Remove `cgi` import to avoid triggering a `DeprecationWarning` on Python 3.11. - Update API version with 2024-04 release.([710](https://github.com/Shopify/shopify_python_api/pull/710)) diff --git a/README.md b/README.md index d8519b1b..066bd343 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ pip install --upgrade ShopifyAPI ```python shop_url = "SHOP_NAME.myshopify.com" - api_version = '2024-01' + api_version = '2024-07' state = binascii.b2a_hex(os.urandom(15)).decode("utf-8") redirect_uri = "http://myapp.com/auth/shopify/callback" scopes = ['read_products', 'read_orders'] diff --git a/shopify/api_version.py b/shopify/api_version.py index a0a1531e..22df6052 100644 --- a/shopify/api_version.py +++ b/shopify/api_version.py @@ -38,6 +38,7 @@ def define_known_versions(cls): cls.define_version(Release("2023-10")) cls.define_version(Release("2024-01")) cls.define_version(Release("2024-04")) + cls.define_version(Release("2024-07")) @classmethod def clear_defined_versions(cls): From 05d59c88c82994dfebf683c35acdebea9a8fab7b Mon Sep 17 00:00:00 2001 From: Paulo Margarido <64600052+paulomarg@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:38:26 -0400 Subject: [PATCH 42/54] Release v12.6.0 --- CHANGELOG | 4 +++- shopify/version.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 24fb1752..cd636df3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ == Unreleased -- Update API version with 2024-07 release ([#](https://github.com/Shopify/shopify_python_api/pull/)) +== Version 12.6.0 + +- Update API version with 2024-07 release ([#723](https://github.com/Shopify/shopify_python_api/pull/723)) == Version 12.5.0 diff --git a/shopify/version.py b/shopify/version.py index 3958d1de..7293b298 100644 --- a/shopify/version.py +++ b/shopify/version.py @@ -1 +1 @@ -VERSION = "12.5.0" +VERSION = "12.6.0" From f7fe4c663c4d341fbbbed0b9691354ba288fa7ba Mon Sep 17 00:00:00 2001 From: James Gilmore Date: Tue, 9 Jul 2024 10:53:52 +0100 Subject: [PATCH 43/54] Add support for building the package in Python 3.12 As discussed in the [issue](https://github.com/Shopify/shopify_python_api/issues/725) there is an issue when trying to install this package when using Python 3.12. The issue is caused by [PEP-632](https://peps.python.org/pep-0632/) removing `distutils` from the built-in libraries this version of python is shipped with. In versions 6.0.0 and lower of PyYaml, this causes the build the fail. As mentioned in their [issue](https://github.com/yaml/pyyaml/issues/756) using v6.0.1 or later will resolve this issue. So updating our `setup.py` install_requires dependency specifications to reflect this. While I'm here, also update the classifiers to include support for PY3.12 and show this more clearly on the README of the repo. --- README.md | 1 + setup.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 066bd343..a8fa6d74 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Build Status](https://github.com/Shopify/shopify_python_api/workflows/CI/badge.svg)](https://github.com/Shopify/shopify_python_api/actions) [![PyPI version](https://badge.fury.io/py/ShopifyAPI.svg)](https://badge.fury.io/py/ShopifyAPI) +![Supported Python Versions](https://img.shields.io/badge/python-3.7%20|%203.8%20|%203.9%20|%203.10%20|%203.11%20|%203.12-brightgreen) [![codecov](https://codecov.io/gh/Shopify/shopify_python_api/branch/main/graph/badge.svg?token=pNTx0TARUx)](https://codecov.io/gh/Shopify/shopify_python_api) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/Shopify/shopify_python_api/blob/main/LICENSE) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) diff --git a/setup.py b/setup.py index dae5a810..eb23ab08 100755 --- a/setup.py +++ b/setup.py @@ -24,7 +24,8 @@ install_requires=[ "pyactiveresource>=2.2.2", "PyJWT >= 2.0.0", - "PyYAML", + "PyYAML>=6.0.1; python_version>='3.12'", + "PyYAML; python_version<'3.12'", "six", ], test_suite="test", @@ -44,6 +45,7 @@ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules", From fdc155e64bcc86504834b1a01d0871232b7c5e08 Mon Sep 17 00:00:00 2001 From: Elizabeth Kenyon Date: Tue, 24 Sep 2024 13:36:25 -0500 Subject: [PATCH 44/54] Make API version more flexible Allow the use of API versions that are not previsouly defined --- CHANGELOG | 1 + shopify/api_version.py | 4 ++++ test/api_version_test.py | 14 ++++++++++++++ test/session_test.py | 13 +++++++++++++ 4 files changed, 32 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index cd636df3..5a5ed5db 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,5 @@ == Unreleased +- Remove requirement to use a predefined API version. Now you can use any valid API version string. ([#737](https://github.com/Shopify/shopify_python_api/pull/737)) == Version 12.6.0 diff --git a/shopify/api_version.py b/shopify/api_version.py index 22df6052..32276668 100644 --- a/shopify/api_version.py +++ b/shopify/api_version.py @@ -17,6 +17,9 @@ def coerce_to_version(cls, version): try: return cls.versions[version] except KeyError: + # Dynamically create a new Release object if version string is not found + if Release.FORMAT.match(version): + return Release(version) raise VersionNotFoundError @classmethod @@ -39,6 +42,7 @@ def define_known_versions(cls): cls.define_version(Release("2024-01")) cls.define_version(Release("2024-04")) cls.define_version(Release("2024-07")) + cls.define_version(Release("2024-10")) @classmethod def clear_defined_versions(cls): diff --git a/test/api_version_test.py b/test/api_version_test.py index 3089daee..9dce8cb2 100644 --- a/test/api_version_test.py +++ b/test/api_version_test.py @@ -29,6 +29,20 @@ def test_coerce_to_version_raises_with_string_that_does_not_match_known_version( with self.assertRaises(shopify.VersionNotFoundError): shopify.ApiVersion.coerce_to_version("crazy-name") + def test_coerce_to_version_creates_new_release_on_the_fly(self): + new_version = "2025-01" + coerced_version = shopify.ApiVersion.coerce_to_version(new_version) + + self.assertIsInstance(coerced_version, shopify.Release) + self.assertEqual(coerced_version.name, new_version) + self.assertEqual( + coerced_version.api_path("https://test.myshopify.com"), + f"https://test.myshopify.com/admin/api/{new_version}", + ) + + # Verify that the new version is not added to the known versions + self.assertNotIn(new_version, shopify.ApiVersion.versions) + class ReleaseTest(TestCase): def test_raises_if_format_invalid(self): diff --git a/test/session_test.py b/test/session_test.py index 806d551b..d7cd5c3d 100644 --- a/test/session_test.py +++ b/test/session_test.py @@ -288,3 +288,16 @@ def normalize_url(self, url): scheme, netloc, path, query, fragment = urllib.parse.urlsplit(url) query = "&".join(sorted(query.split("&"))) return urllib.parse.urlunsplit((scheme, netloc, path, query, fragment)) + + def test_session_with_coerced_version(self): + future_version = "2030-01" + session = shopify.Session("test.myshopify.com", future_version, "token") + self.assertEqual(session.api_version.name, future_version) + self.assertEqual( + session.api_version.api_path("https://test.myshopify.com"), + f"https://test.myshopify.com/admin/api/{future_version}", + ) + + def test_session_with_invalid_version(self): + with self.assertRaises(shopify.VersionNotFoundError): + shopify.Session("test.myshopify.com", "invalid-version", "token") From 7229004441645b1bc0a4c848cc1a6593fc9d6281 Mon Sep 17 00:00:00 2001 From: Matteo Depalo Date: Wed, 30 Oct 2024 10:46:27 +0000 Subject: [PATCH 45/54] Release v12.7.0 --- CHANGELOG | 3 +++ shopify/version.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 5a5ed5db..50cae06e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,7 @@ == Unreleased + +== Version 12.7.0 + - Remove requirement to use a predefined API version. Now you can use any valid API version string. ([#737](https://github.com/Shopify/shopify_python_api/pull/737)) == Version 12.6.0 diff --git a/shopify/version.py b/shopify/version.py index 7293b298..126c3ab4 100644 --- a/shopify/version.py +++ b/shopify/version.py @@ -1 +1 @@ -VERSION = "12.6.0" +VERSION = "12.7.0" From 9451fe5f45c6d809787384e9ceaa294fec1b66c6 Mon Sep 17 00:00:00 2001 From: "yuichi.nasukawa" Date: Wed, 8 Jan 2025 22:01:30 +0900 Subject: [PATCH 46/54] Add REST API deprecation notice to README --- README.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a8fa6d74..6226bcb1 100644 --- a/README.md +++ b/README.md @@ -87,10 +87,11 @@ pip install --upgrade ShopifyAPI session = shopify.Session(shop_url, api_version, access_token) shopify.ShopifyResource.activate_session(session) - shop = shopify.Shop.current() # Get the current shop - product = shopify.Product.find(179761209) # Get a specific product + # Note: REST API examples will be deprecated in 2025 + shop = shopify.Shop.current() # Get the current shop + product = shopify.Product.find(179761209) # Get a specific product - # execute a graphQL call + # GraphQL API example shopify.GraphQL().execute("{ shop { name id } }") ``` @@ -150,6 +151,13 @@ _Note: Your application must be public to test the billing process. To test on a ``` ### Advanced Usage + +> **⚠️ Note**: As of October 1, 2024, the REST Admin API is legacy: +> - Public apps must migrate to GraphQL by February 2025 +> - Custom apps must migrate to GraphQL by April 2025 +> +> For migration guidance, see [Shopify's migration guide](https://shopify.dev/docs/apps/build/graphql/migrate/new-product-model) + It is recommended to have at least a basic grasp on the principles of the [pyactiveresource](https://github.com/Shopify/pyactiveresource) library, which is a port of rails/ActiveResource to Python and upon which this package relies heavily. Instances of `pyactiveresource` resources map to RESTful resources in the Shopify API. @@ -157,6 +165,7 @@ Instances of `pyactiveresource` resources map to RESTful resources in the Shopif `pyactiveresource` exposes life cycle methods for creating, finding, updating, and deleting resources which are equivalent to the `POST`, `GET`, `PUT`, and `DELETE` HTTP verbs. ```python +# Note: REST API examples will be deprecated in 2025 product = shopify.Product() product.title = "Shopify Logo T-Shirt" product.id # => 292082188312 @@ -182,6 +191,7 @@ new_orders = shopify.Order.find(status="open", limit="50") Some resources such as `Fulfillment` are prefixed by a parent resource in the Shopify API (e.g. `orders/450789469/fulfillments/255858046`). In order to interact with these resources, you must specify the identifier of the parent resource in your request. ```python +# Note: This REST API example will be deprecated in the future shopify.Fulfillment.find(255858046, order_id=450789469) ``` @@ -196,6 +206,9 @@ This package also includes the `shopify_api.py` script to make it easy to open a This library also supports Shopify's new [GraphQL API](https://help.shopify.com/en/api/graphql-admin-api). The authentication process is identical. Once your session is activated, simply construct a new graphql client and use `execute` to execute the query. +> **Note**: Shopify recommends using GraphQL API for new development as REST API will be deprecated. +> See [Migration Guide](https://shopify.dev/docs/apps/build/graphql/migrate/new-product-model) for more details. + ```python result = shopify.GraphQL().execute('{ shop { name id } }') ``` From 024d94691ed889d047704d2f1615f40a03cc02ac Mon Sep 17 00:00:00 2001 From: Tyler J Date: Sat, 11 Jan 2025 13:31:05 -0500 Subject: [PATCH 47/54] Refactor `create_permission_url` to handle optional `scope`. Modified `create_permission_url` to make `scope` optional, allowing it to be omitted when specified in the app's configuration (TOML). Updated the README to reflect this change and clarify usage. This improves flexibility and simplifies configuration management. --- README.md | 4 +++- shopify/session.py | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a8fa6d74..0b680d07 100644 --- a/README.md +++ b/README.md @@ -66,10 +66,12 @@ pip install --upgrade ShopifyAPI api_version = '2024-07' state = binascii.b2a_hex(os.urandom(15)).decode("utf-8") redirect_uri = "http://myapp.com/auth/shopify/callback" + # `scope` should be omitted if provided by app's TOML scopes = ['read_products', 'read_orders'] newSession = shopify.Session(shop_url, api_version) - auth_url = newSession.create_permission_url(scopes, redirect_uri, state) + # `scope` should be omitted if provided by app's TOML + auth_url = newSession.create_permission_url(redirect_uri, scopes, state) # redirect to auth_url ``` diff --git a/shopify/session.py b/shopify/session.py index 39ce5f7b..52dc83f4 100644 --- a/shopify/session.py +++ b/shopify/session.py @@ -53,10 +53,11 @@ def __init__(self, shop_url, version=None, token=None, access_scopes=None): self.access_scopes = access_scopes return - def create_permission_url(self, scope, redirect_uri, state=None): - query_params = dict(client_id=self.api_key, scope=",".join(scope), redirect_uri=redirect_uri) - if state: - query_params["state"] = state + def create_permission_url(self, redirect_uri, scope=None, state=None): + query_params = dict(client_id=self.api_key, redirect_uri=redirect_uri) + # `scope` should be omitted if provided by app's TOML + if scope: query_params["scope"] = ",".join(scope) + if state: query_params["state"] = state return "https://%s/admin/oauth/authorize?%s" % (self.url, urllib.parse.urlencode(query_params)) def request_token(self, params): From cdaa10d2d6a82d44652468d0d78aba537df08baa Mon Sep 17 00:00:00 2001 From: "yuichi.nasukawa" Date: Sun, 12 Jan 2025 08:40:56 +0900 Subject: [PATCH 48/54] chore: upgrade pre-commit dependencies --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 43267923..f3500257 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,15 +2,15 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.4.0 + rev: v5.0.0 hooks: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/psf/black - rev: 22.3.0 + rev: 24.10.0 hooks: - id: black - repo: https://github.com/PyCQA/pylint - rev: v2.15.8 + rev: v3.3.3 hooks: - id: pylint From 7b044441d59fe9087abc02554cbf267fb9a6d923 Mon Sep 17 00:00:00 2001 From: "yuichi.nasukawa" Date: Sun, 12 Jan 2025 08:44:30 +0900 Subject: [PATCH 49/54] fix: resolve new pylint warnings - Fix warnings introduced by pylint v3.3.3 upgrade --- scripts/shopify_api.py | 2 +- shopify/api_access.py | 1 - shopify/mixins.py | 2 +- shopify/session.py | 4 ++-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/shopify_api.py b/scripts/shopify_api.py index 5dfab93a..bab35f15 100755 --- a/scripts/shopify_api.py +++ b/scripts/shopify_api.py @@ -128,7 +128,7 @@ def add(cls, connection): if os.path.exists(filename): raise ConfigFileError("There is already a config file at " + filename) else: - config = dict(protocol="https") + config = {"protocol": "https"} domain = input("Domain? (leave blank for %s.myshopify.com) " % (connection)) if not domain.strip(): domain = "%s.myshopify.com" % (connection) diff --git a/shopify/api_access.py b/shopify/api_access.py index d5ffbe35..19b80671 100644 --- a/shopify/api_access.py +++ b/shopify/api_access.py @@ -14,7 +14,6 @@ class ApiAccessError(Exception): class ApiAccess: - SCOPE_DELIMITER = "," SCOPE_RE = re.compile(r"\A(?Punauthenticated_)?(write|read)_(?P.*)\Z") IMPLIED_SCOPE_RE = re.compile(r"\A(?Punauthenticated_)?write_(?P.*)\Z") diff --git a/shopify/mixins.py b/shopify/mixins.py index 54496dbf..5a13ca3a 100644 --- a/shopify/mixins.py +++ b/shopify/mixins.py @@ -24,7 +24,7 @@ def add_metafield(self, metafield): if self.is_new(): raise ValueError("You can only add metafields to a resource that has been saved") - metafield._prefix_options = dict(resource=self.__class__.plural, resource_id=self.id) + metafield._prefix_options = {"resource": self.__class__.plural, "resource_id": self.id} metafield.save() return metafield diff --git a/shopify/session.py b/shopify/session.py index 39ce5f7b..c3ec6d4b 100644 --- a/shopify/session.py +++ b/shopify/session.py @@ -54,7 +54,7 @@ def __init__(self, shop_url, version=None, token=None, access_scopes=None): return def create_permission_url(self, scope, redirect_uri, state=None): - query_params = dict(client_id=self.api_key, scope=",".join(scope), redirect_uri=redirect_uri) + query_params = {"client_id": self.api_key, "scope": ",".join(scope), "redirect_uri": redirect_uri} if state: query_params["state"] = state return "https://%s/admin/oauth/authorize?%s" % (self.url, urllib.parse.urlencode(query_params)) @@ -69,7 +69,7 @@ def request_token(self, params): code = params["code"] url = "https://%s/admin/oauth/access_token?" % self.url - query_params = dict(client_id=self.api_key, client_secret=self.secret, code=code) + query_params = {"client_id": self.api_key, "client_secret": self.secret, "code": code} request = urllib.request.Request(url, urllib.parse.urlencode(query_params).encode("utf-8")) response = urllib.request.urlopen(request) From ceada2433b004365b7d9f74669b9c1067e299ccb Mon Sep 17 00:00:00 2001 From: Tyler J Date: Sun, 12 Jan 2025 11:33:31 -0500 Subject: [PATCH 50/54] Update to version 12.7.1 and update the CHANGELOG. --- CHANGELOG | 2 ++ shopify/version.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 50cae06e..e9910c2e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,7 @@ == Unreleased +- Remove requirement to provide scopes to Permission URL, as it should be omitted if defined with the TOML file. + == Version 12.7.0 - Remove requirement to use a predefined API version. Now you can use any valid API version string. ([#737](https://github.com/Shopify/shopify_python_api/pull/737)) diff --git a/shopify/version.py b/shopify/version.py index 126c3ab4..dfb0b4e4 100644 --- a/shopify/version.py +++ b/shopify/version.py @@ -1 +1 @@ -VERSION = "12.7.0" +VERSION = "12.7.1" From 07d6c47146e00c35bb39a83d86033f9b250623af Mon Sep 17 00:00:00 2001 From: Tyler J Date: Sun, 12 Jan 2025 11:48:02 -0500 Subject: [PATCH 51/54] Fix typo in method signature of create_permission_url Removed an unnecessary extra space in the method signature of `create_permission_url`. --- shopify/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shopify/session.py b/shopify/session.py index 52dc83f4..eec40517 100644 --- a/shopify/session.py +++ b/shopify/session.py @@ -53,7 +53,7 @@ def __init__(self, shop_url, version=None, token=None, access_scopes=None): self.access_scopes = access_scopes return - def create_permission_url(self, redirect_uri, scope=None, state=None): + def create_permission_url(self, redirect_uri, scope=None, state=None): query_params = dict(client_id=self.api_key, redirect_uri=redirect_uri) # `scope` should be omitted if provided by app's TOML if scope: query_params["scope"] = ",".join(scope) From adaf770a0b5a99ae791048967f39d89e13ea500f Mon Sep 17 00:00:00 2001 From: Tyler J Date: Fri, 17 Jan 2025 14:28:20 -0500 Subject: [PATCH 52/54] Update tests for `create_permission_url` method. Updated tests to improve clarity and consistency in naming and arguments. Modified `create_permission_url` calls to match new positional order for `redirect_uri` and `scope`. Enhanced assertion coverage for edge cases like empty scopes and added tests for state parameter handling. --- test/session_test.py | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/test/session_test.py b/test/session_test.py index d7cd5c3d..04d30748 100644 --- a/test/session_test.py +++ b/test/session_test.py @@ -86,51 +86,69 @@ def test_temp_works_without_currently_active_session(self): self.assertEqual("https://testshop.myshopify.com/admin/api/unstable", assigned_site) self.assertEqual("https://none/admin/api/unstable", shopify.ShopifyResource.site) - def test_create_permission_url_returns_correct_url_with_single_scope_and_redirect_uri(self): + def test_create_permission_url_returns_correct_url_with_redirect_uri(self): + shopify.Session.setup(api_key="My_test_key", secret="My test secret") + session = shopify.Session("http://localhost.myshopify.com", "unstable") + permission_url = session.create_permission_url("my_redirect_uri.com") + self.assertEqual( + "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&redirect_uri=my_redirect_uri.com", + self.normalize_url(permission_url), + ) + + def test_create_permission_url_returns_correct_url_with_redirect_uri_and_single_scope(self): shopify.Session.setup(api_key="My_test_key", secret="My test secret") session = shopify.Session("http://localhost.myshopify.com", "unstable") scope = ["write_products"] - permission_url = session.create_permission_url(scope, "my_redirect_uri.com") + permission_url = session.create_permission_url("my_redirect_uri.com", scope=scope) self.assertEqual( "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&redirect_uri=my_redirect_uri.com&scope=write_products", self.normalize_url(permission_url), ) - def test_create_permission_url_returns_correct_url_with_dual_scope_and_redirect_uri(self): + def test_create_permission_url_returns_correct_url_with_redirect_uri_and_dual_scope(self): shopify.Session.setup(api_key="My_test_key", secret="My test secret") session = shopify.Session("http://localhost.myshopify.com", "unstable") scope = ["write_products", "write_customers"] - permission_url = session.create_permission_url(scope, "my_redirect_uri.com") + permission_url = session.create_permission_url("my_redirect_uri.com", scope=scope) self.assertEqual( "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&redirect_uri=my_redirect_uri.com&scope=write_products%2Cwrite_customers", self.normalize_url(permission_url), ) - def test_create_permission_url_returns_correct_url_with_no_scope_and_redirect_uri(self): + def test_create_permission_url_returns_correct_url_with_redirect_uri_and_empty_scope(self): shopify.Session.setup(api_key="My_test_key", secret="My test secret") session = shopify.Session("http://localhost.myshopify.com", "unstable") scope = [] - permission_url = session.create_permission_url(scope, "my_redirect_uri.com") + permission_url = session.create_permission_url("my_redirect_uri.com", scope=scope) + self.assertEqual( + "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&redirect_uri=my_redirect_uri.com", + self.normalize_url(permission_url), + ) + + def test_create_permission_url_returns_correct_url_with_redirect_uri_and_state(self): + shopify.Session.setup(api_key="My_test_key", secret="My test secret") + session = shopify.Session("http://localhost.myshopify.com", "unstable") + permission_url = session.create_permission_url("my_redirect_uri.com", state="mystate") self.assertEqual( - "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&redirect_uri=my_redirect_uri.com&scope=", + "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&redirect_uri=my_redirect_uri.com&state=mystate", self.normalize_url(permission_url), ) - def test_create_permission_url_returns_correct_url_with_no_scope_and_redirect_uri_and_state(self): + def test_create_permission_url_returns_correct_url_with_redirect_uri_empty_scope_and_state(self): shopify.Session.setup(api_key="My_test_key", secret="My test secret") session = shopify.Session("http://localhost.myshopify.com", "unstable") scope = [] - permission_url = session.create_permission_url(scope, "my_redirect_uri.com", state="mystate") + permission_url = session.create_permission_url("my_redirect_uri.com", scope=scope, state="mystate") self.assertEqual( - "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&redirect_uri=my_redirect_uri.com&scope=&state=mystate", + "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&redirect_uri=my_redirect_uri.com&state=mystate", self.normalize_url(permission_url), ) - def test_create_permission_url_returns_correct_url_with_single_scope_and_redirect_uri_and_state(self): + def test_create_permission_url_returns_correct_url_with_redirect_uri_and_single_scope_and_state(self): shopify.Session.setup(api_key="My_test_key", secret="My test secret") session = shopify.Session("http://localhost.myshopify.com", "unstable") scope = ["write_customers"] - permission_url = session.create_permission_url(scope, "my_redirect_uri.com", state="mystate") + permission_url = session.create_permission_url( "my_redirect_uri.com", scope=scope, state="mystate") self.assertEqual( "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&redirect_uri=my_redirect_uri.com&scope=write_customers&state=mystate", self.normalize_url(permission_url), From 12e933ba9cadd2ba5b834fe5143cb70438e9e34b Mon Sep 17 00:00:00 2001 From: Tyler J Date: Mon, 20 Jan 2025 08:32:20 -0500 Subject: [PATCH 53/54] Fix linting errors Removes extra white space in parameters in session_test.py and changes conditional formatting in shopify/session.py. --- shopify/session.py | 8 +++++--- test/session_test.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/shopify/session.py b/shopify/session.py index eec40517..dcb41d41 100644 --- a/shopify/session.py +++ b/shopify/session.py @@ -54,10 +54,12 @@ def __init__(self, shop_url, version=None, token=None, access_scopes=None): return def create_permission_url(self, redirect_uri, scope=None, state=None): - query_params = dict(client_id=self.api_key, redirect_uri=redirect_uri) + query_params = {"client_id": self.api_key, "redirect_uri": redirect_uri} # `scope` should be omitted if provided by app's TOML - if scope: query_params["scope"] = ",".join(scope) - if state: query_params["state"] = state + if scope: + query_params["scope"] = ",".join(scope) + if state: + query_params["state"] = state return "https://%s/admin/oauth/authorize?%s" % (self.url, urllib.parse.urlencode(query_params)) def request_token(self, params): diff --git a/test/session_test.py b/test/session_test.py index 04d30748..8d73e293 100644 --- a/test/session_test.py +++ b/test/session_test.py @@ -148,7 +148,7 @@ def test_create_permission_url_returns_correct_url_with_redirect_uri_and_single_ shopify.Session.setup(api_key="My_test_key", secret="My test secret") session = shopify.Session("http://localhost.myshopify.com", "unstable") scope = ["write_customers"] - permission_url = session.create_permission_url( "my_redirect_uri.com", scope=scope, state="mystate") + permission_url = session.create_permission_url("my_redirect_uri.com", scope=scope, state="mystate") self.assertEqual( "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&redirect_uri=my_redirect_uri.com&scope=write_customers&state=mystate", self.normalize_url(permission_url), From 2f998c691bd15608603ef25e31238f6c22abc544 Mon Sep 17 00:00:00 2001 From: Tyler J Date: Mon, 20 Jan 2025 08:40:04 -0500 Subject: [PATCH 54/54] Fix linting errors Removes extra white space in parameters in session_test.py and changes conditional formatting in shopify/session.py. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d8378880..cadda24e 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ _Note: Your application must be public to test the billing process. To test on a > **⚠️ Note**: As of October 1, 2024, the REST Admin API is legacy: > - Public apps must migrate to GraphQL by February 2025 > - Custom apps must migrate to GraphQL by April 2025 -> +> > For migration guidance, see [Shopify's migration guide](https://shopify.dev/docs/apps/build/graphql/migrate/new-product-model) It is recommended to have at least a basic grasp on the principles of the [pyactiveresource](https://github.com/Shopify/pyactiveresource) library, which is a port of rails/ActiveResource to Python and upon which this package relies heavily.