diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 483ad9f..f12ab33 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v2 with: - python-version: "3.9" + python-version: "3.11" - name: Cache pip uses: actions/cache@v2 with: @@ -31,7 +31,7 @@ jobs: strategy: fail-fast: false matrix: - python-versions: ["3.7", "3.8", "3.9", "3.10"] + python-versions: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-versions }} diff --git a/4.0-Upgrade.md b/4.0-Upgrade.md new file mode 100644 index 0000000..7173f19 --- /dev/null +++ b/4.0-Upgrade.md @@ -0,0 +1,30 @@ +# Upgrading to chartmogul-python 4.0.0 + +This new version replaces the existing pagination for the `.all()` endpoints that used a combination of `page` and `per_page` parameters, and instead uses a `cursor` based pagination. So to list (as an example) Plans you now can: + +```python +config = Config("your-token") + +# Getting the first page +plans = Plan.all(config, per_page=12) + +""" +This will return an array of plans (if available), and a cursor + has_more fields +""" +{ + "plans": [ + { + "uuid": "some_uuid", + "data_source_uuid": "some_uuid", + "name": "Master Plan" + } + ], + "has_more": True, + "cursor": "MjAyMy0wNy0yOFQwODowOToyMi4xNTQyMDMwMDBaJjk0NDQ0Mg==" +} + +if plans.has_more: + more_plans = Plan.all(config, per_page=12, cursor=plans.cursor) +``` + +If you have existing code that relies on the `page` parameter, those requests will throw an error now alerting you of their deprecation. diff --git a/CHANGELOG.md b/CHANGELOG.md index c91637d..c2071b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,17 @@ and this project adheres to [Semantic Versioning]. [Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ [Semantic Versioning]: https://semver.org/spec/v2.0.0.html +## [4.0.0] - 2023-10-04 + +### Added +- v4.0.0 upgrade instructions. +- Support for Python 3.12. + +### Removed +- Support for old pagination using `page` query params. +- Deprecated `imp` module. +- Support for Python 3.7. + ## [3.1.3] - 2023-09-27 ### Added diff --git a/README.md b/README.md index f197fff..acaf1cc 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ ## Installation -This library requires Python 3.5 to 3.9. It was last tested against Python 2.7 in version 1.3.0. +This library requires Python 3.8 to 3.12. It was last tested against Python 2.7 in version 1.3.0. ```sh pip3 install chartmogul @@ -376,6 +376,8 @@ To work on the library: * Fork it * Create your feature branch (`git checkout -b my-new-feature`) +* Setup a virtual environment (`python -m venv `) +* Activate the virtual environment (`source /bin/activate`) * Install dependencies: `pip3 install -r requirements.txt && python3 setup.py develop` * Fix bugs or add features. Make sure the changes pass the coding guidelines (use `pylama`). * Write tests for your new features. Use `requests_mock` for HTTP mocking. diff --git a/chartmogul/__init__.py b/chartmogul/__init__.py index 186921a..7c8ff4b 100644 --- a/chartmogul/__init__.py +++ b/chartmogul/__init__.py @@ -1,6 +1,11 @@ # -*- coding: utf-8 -*- from .api.config import Config -from .errors import APIError, ConfigurationError, ArgumentMissingError +from .errors import ( + APIError, + ConfigurationError, + ArgumentMissingError, + DeprecatedArgumentError, +) from .api.customers.activity import CustomerActivity from .api.attributes import Attributes @@ -24,9 +29,6 @@ from .version import __version__ -# Deprecated -import imp - """ ChartMogul API Python Client diff --git a/chartmogul/api/customer.py b/chartmogul/api/customer.py index 8165b37..3bb7199 100644 --- a/chartmogul/api/customer.py +++ b/chartmogul/api/customer.py @@ -31,11 +31,7 @@ class Customer(Resource): _path = "/customers{/uuid}" _root_key = "entries" - _many = namedtuple( - "Customers", - [_root_key, "has_more", "per_page", "page", "current_page", "total_pages", "cursor"], - defaults=[None, None, None, None, None, None], - ) + _many = namedtuple("Customers", [_root_key, "has_more", "cursor"], defaults=[None, None]) class _Schema(Schema): # All operations diff --git a/chartmogul/api/customers/activity.py b/chartmogul/api/customers/activity.py index de43eb5..660be4e 100644 --- a/chartmogul/api/customers/activity.py +++ b/chartmogul/api/customers/activity.py @@ -10,11 +10,7 @@ class CustomerActivity(Resource): _path = "/customers{/uuid}/activities" _root_key = "entries" - _many = namedtuple( - "Activities", - [_root_key, "has_more", "per_page", "page", "cursor"], - defaults=[None, None, None, None], - ) + _many = namedtuple("Activities", [_root_key, "has_more", "cursor"], defaults=[None, None]) class _Schema(Schema): id = fields.Int() diff --git a/chartmogul/api/customers/subscription.py b/chartmogul/api/customers/subscription.py index 2d14b9a..1c7dd25 100644 --- a/chartmogul/api/customers/subscription.py +++ b/chartmogul/api/customers/subscription.py @@ -11,11 +11,7 @@ class CustomerSubscription(Resource): _path = "/customers{/uuid}/subscriptions" _root_key = "entries" - _many = namedtuple( - "Subscriptions", - [_root_key, "has_more", "per_page", "page", "cursor"], - defaults=[None, None, None, None], - ) + _many = namedtuple("Subscriptions", [_root_key, "has_more", "cursor"], defaults=[None, None]) class _Schema(Schema): id = fields.Int(allow_none=True) @@ -52,19 +48,10 @@ def _loadJSON(cls, jsonObj): if "subscriptions" in jsonObj: _many = namedtuple( "Subscriptions", - [ - "subscriptions", - "current_page", - "total_pages", - "customer_uuid", - "has_more", - "cursor", - ], + ["subscriptions", "has_more", "cursor", "customer_uuid"], ) return _many( cls._schema.load(jsonObj["subscriptions"], many=True), - current_page=jsonObj.get("current_page", None), - total_pages=jsonObj.get("total_pages", None), customer_uuid=jsonObj.get("customer_uuid", None), has_more=jsonObj.get("has_more", None), cursor=jsonObj.get("cursor", None), diff --git a/chartmogul/api/invoice.py b/chartmogul/api/invoice.py index 43e3abe..967cec9 100644 --- a/chartmogul/api/invoice.py +++ b/chartmogul/api/invoice.py @@ -42,8 +42,8 @@ class Invoice(Resource): _root_key = "invoices" _many = namedtuple( "Invoices", - [_root_key, "current_page", "total_pages", "cursor", "has_more", "customer_uuid"], - defaults=[None, None, None, None, None], + [_root_key, "cursor", "has_more", "customer_uuid"], + defaults=[None, None, None], ) _many.__new__.__defaults__ = (None,) * len(_many._fields) @@ -82,6 +82,8 @@ def all(cls, config, **kwargs): Invoice.all_any = Invoice._method("all", "get", "/invoices") Invoice.destroy = Invoice._method("destroy", "delete", "/invoices{/uuid}") Invoice.destroy_all = Invoice._method( - "destroy_all", "delete", "/data_sources{/data_source_uuid}/customers{/customer_uuid}/invoices" + "destroy_all", + "delete", + "/data_sources{/data_source_uuid}/customers{/customer_uuid}/invoices", ) Invoice.retrieve = Invoice._method("retrieve", "get", "/invoices{/uuid}") diff --git a/chartmogul/api/plan.py b/chartmogul/api/plan.py index d35b373..43899d2 100644 --- a/chartmogul/api/plan.py +++ b/chartmogul/api/plan.py @@ -10,11 +10,7 @@ class Plan(Resource): _path = "/plans{/uuid}" _root_key = "plans" - _many = namedtuple( - "Plans", - [_root_key, "current_page", "total_pages", "has_more", "cursor"], - defaults=[None, None, None, None], - ) + _many = namedtuple("Plans", [_root_key, "has_more", "cursor"], defaults=[None, None]) class _Schema(Schema): uuid = fields.String() diff --git a/chartmogul/api/plan_group.py b/chartmogul/api/plan_group.py index 105601b..bf72dee 100644 --- a/chartmogul/api/plan_group.py +++ b/chartmogul/api/plan_group.py @@ -11,11 +11,7 @@ class PlanGroup(Resource): _path = "/plan_groups{/uuid}" _root_key = "plan_groups" - _many = namedtuple( - "PlanGroups", - [_root_key, "current_page", "total_pages", "has_more", "cursor"], - defaults=[None, None, None, None], - ) + _many = namedtuple("PlanGroups", [_root_key, "has_more", "cursor"], defaults=[None, None]) class _Schema(Schema): uuid = fields.String() diff --git a/chartmogul/api/plan_group_plans.py b/chartmogul/api/plan_group_plans.py index 4b01832..393cb68 100644 --- a/chartmogul/api/plan_group_plans.py +++ b/chartmogul/api/plan_group_plans.py @@ -10,11 +10,7 @@ class PlanGroupPlans(Resource): _path = "/plan_groups{/uuid}/plans" _root_key = "plans" - _many = namedtuple( - "PlanGroupPlans", - [_root_key, "current_page", "total_pages", "has_more", "cursor"], - defaults=[None, None, None, None], - ) + _many = namedtuple("PlanGroupPlans", [_root_key, "has_more", "cursor"], defaults=[None, None]) class _Schema(Schema): uuid = fields.String() diff --git a/chartmogul/api/subscription_event.py b/chartmogul/api/subscription_event.py index 6d65c05..03fe908 100644 --- a/chartmogul/api/subscription_event.py +++ b/chartmogul/api/subscription_event.py @@ -11,7 +11,7 @@ class SubscriptionEvent(Resource): _path = "/subscription_events" _root_key = "subscription_events" _many = namedtuple( - "SubscriptionEvents", [_root_key, "meta", "has_more", "cursor"], defaults=[None, None, None] + "SubscriptionEvents", [_root_key, "has_more", "cursor"], defaults=[None, None] ) class _Schema(Schema): diff --git a/chartmogul/errors.py b/chartmogul/errors.py index 50d1ebc..924a82c 100644 --- a/chartmogul/errors.py +++ b/chartmogul/errors.py @@ -14,6 +14,10 @@ class ArgumentMissingError(Exception): pass +class DeprecatedArgumentError(Exception): + pass + + def annotateHTTPError(err): if isinstance(err, HTTPError): raise_from(APIError(err.response.content), err) diff --git a/chartmogul/imp/__init__.py b/chartmogul/imp/__init__.py deleted file mode 100644 index a02d826..0000000 --- a/chartmogul/imp/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Deprecated -from .invoice import Invoice -from .transaction import Transaction -from .subscription import Subscription diff --git a/chartmogul/imp/invoice.py b/chartmogul/imp/invoice.py deleted file mode 100644 index 8078d6f..0000000 --- a/chartmogul/imp/invoice.py +++ /dev/null @@ -1,14 +0,0 @@ -from ..api.invoice import Invoice as InvoiceNew -from warnings import warn - - -class Invoice(InvoiceNew): - @classmethod - def create(cls, *args, **kwargs): - warn("chartmogul.imp namespace is deprecated, use chartmogul.Invoice.create!") - return super(Invoice, cls).create(*args, **kwargs) - - @classmethod - def all(cls, *args, **kwargs): - warn("chartmogul.imp namespace is deprecated, use chartmogul.Invoice.all!") - return super(Invoice, cls).all(*args, **kwargs) diff --git a/chartmogul/imp/subscription.py b/chartmogul/imp/subscription.py deleted file mode 100644 index 24051c1..0000000 --- a/chartmogul/imp/subscription.py +++ /dev/null @@ -1,16 +0,0 @@ -from ..api.customers.subscription import CustomerSubscription as SubsNew -from warnings import warn - - -class Subscription(SubsNew): - @classmethod - def all(cls, *args, **kwargs): - warn( - "chartmogul.imp namespace is deprecated, use chartmogul.CustomerSubscription.list_imported!" - ) - return super(Subscription, cls).list_imported(*args, **kwargs) - - @classmethod - def cancel(cls, *args, **kwargs): - warn("chartmogul.imp namespace is deprecated, use chartmogul.CustomerSubscription.cancel!") - return super(Subscription, cls).cancel(*args, **kwargs) diff --git a/chartmogul/imp/transaction.py b/chartmogul/imp/transaction.py deleted file mode 100644 index c189d4f..0000000 --- a/chartmogul/imp/transaction.py +++ /dev/null @@ -1,9 +0,0 @@ -from ..api.transaction import Transaction as TransactionNew -from warnings import warn - - -class Transaction(TransactionNew): - @classmethod - def create(cls, *args, **kwargs): - warn("chartmogul.imp namespace is deprecated, use chartmogul.Transaction.create!") - return super(Transaction, cls).create(*args, **kwargs) diff --git a/chartmogul/resource.py b/chartmogul/resource.py index 6521bf3..bdfffab 100644 --- a/chartmogul/resource.py +++ b/chartmogul/resource.py @@ -5,7 +5,12 @@ from uritemplate import URITemplate from .api.config import Config -from .errors import ArgumentMissingError, ConfigurationError, annotateHTTPError +from .errors import ( + ArgumentMissingError, + ConfigurationError, + annotateHTTPError, + DeprecatedArgumentError, +) from .retry_request import requests_retry_session from .version import __version__ @@ -29,18 +34,7 @@ "modify_with_params": "patch", } -LIST_PARAMS = [ - "current_page", - "total_pages", - "has_more", - "per_page", - "page", - "summary", - "customer_uuid", - "data_source_uuid", - "cursor", - "meta", -] +LIST_PARAMS = ["has_more", "summary", "customer_uuid", "data_source_uuid", "cursor"] ESCAPED_QUERY_KEYS = {"start_date": "start-date", "end_date": "end-date"} @@ -175,6 +169,8 @@ def _validate_arguments(cls, method, kwargs): raise ArgumentMissingError("Please pass 'uuid' parameter") if method in ["create", "modify"] and "data" not in kwargs: raise ArgumentMissingError("Please pass 'data' parameter") + if method == "all" and "page" in kwargs: + raise DeprecatedArgumentError("The 'page' parameter is deprecated") if ( method in ["destroy_all"] and "data_source_uuid" not in kwargs diff --git a/chartmogul/version.py b/chartmogul/version.py index f749372..ce1305b 100644 --- a/chartmogul/version.py +++ b/chartmogul/version.py @@ -1 +1 @@ -__version__ = "3.1.3" +__version__ = "4.0.0" diff --git a/docs/chartmogul.imp.rst b/docs/chartmogul.imp.rst deleted file mode 100644 index e59f11d..0000000 --- a/docs/chartmogul.imp.rst +++ /dev/null @@ -1,10 +0,0 @@ -chartmogul.imp package -====================== - -Module contents ---------------- - -.. automodule:: chartmogul.imp - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/chartmogul.rst b/docs/chartmogul.rst index 1460bf4..f5cedd2 100644 --- a/docs/chartmogul.rst +++ b/docs/chartmogul.rst @@ -8,7 +8,6 @@ Subpackages chartmogul.api chartmogul.enrichment - chartmogul.imp chartmogul.metrics Submodules diff --git a/docs/test.imp.rst b/docs/test.imp.rst deleted file mode 100644 index fe94e8a..0000000 --- a/docs/test.imp.rst +++ /dev/null @@ -1,30 +0,0 @@ -test.imp package -================ - -Submodules ----------- - -test.imp.test_invoice module ----------------------------- - -.. automodule:: test.imp.test_invoice - :members: - :undoc-members: - :show-inheritance: - -test.imp.test_subscription module ---------------------------------- - -.. automodule:: test.imp.test_subscription - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: test.imp - :members: - :undoc-members: - :show-inheritance: diff --git a/fixtures/fetch_account.yaml b/fixtures/fetch_account.yaml new file mode 100644 index 0000000..017da13 --- /dev/null +++ b/fixtures/fetch_account.yaml @@ -0,0 +1,60 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - chartmogul-python/4.0.0 + content-type: + - application/json + method: GET + uri: https://api.chartmogul.com/v1/account + response: + body: + string: '{"name":"Chartmogul Test","currency":"EUR","time_zone":"Europe/Lisbon","week_start_on":"monday"}' + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept,Authorization + Access-Control-Allow-Methods: + - GET, OPTIONS + Access-Control-Allow-Origin: + - '*' + Cache-Control: + - max-age=0, private, must-revalidate + Connection: + - keep-alive + Content-Length: + - '96' + Content-Type: + - application/json; charset=utf-8 + Date: + - Sun, 10 Sep 2023 20:18:46 GMT + ETag: + - W/"4c95c647e6119fa4820a4ca4d344ec3d" + Referrer-Policy: + - strict-origin-when-cross-origin + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Frame-Options: + - DENY + X-Permitted-Cross-Domain-Policies: + - none + X-Request-Id: + - a388e7b97b3cdbb5aceba74e80d345fc + X-Runtime: + - '0.022753' + X-XSS-Protection: + - 1; mode=block + status: + code: 200 + message: OK +version: 1 diff --git a/fixtures/fetch_subscription_events.yaml b/fixtures/fetch_subscription_events.yaml deleted file mode 100644 index bc1427d..0000000 --- a/fixtures/fetch_subscription_events.yaml +++ /dev/null @@ -1,78 +0,0 @@ -interactions: -- request: - body: null - headers: - Accept: - - '*/*' - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - User-Agent: - - chartmogul-python/3.1.2 - content-type: - - application/json - method: GET - uri: https://api.chartmogul.com/v1/subscription_events - response: - body: - string: !!binary | - H4sIAAAAAAAAA+2bXZOiOBSG/wvX7VS+P/wdfbVbUxRCUEGQhmDrdPV/3xC2dtepHRkJAbvKKm+U - Qzwkj29OXpOPoGk3TVzvK70/lqE6qVI3wfrPj2CfBGtMuUQCE/QSJJGOwubY1rEK27a7GCRNKDFM - oYzQKuZJuoJQJauNgnKVbjiPUkaTKJHBSxC3jT4Wqg7VWau6jA6hbYBDCTg0169yaJS+jivbw+Gn - mOt2ENn94Ni0Ux0i8wz//Y7+XvtYoXkEZdJGAOEVoCvIXwFbI7BG/A9zr0pTFev9Sf0cB/ArAGv7 - snFdF4X6UnVtXSUeR2WsDgeVdK39TxJ1faxN3358mg6plUkmCSP964Taqkv4dsxbG5V6ry/Bun/Q - uK1rVcb/vI+KY2uy3Zdh3A9sH6ajc/iLS7XSdRR339t3WjdQ3U2fL9dIQD9IQMEA64byqmfvRyLP - i0bwJxLdb28uJIAfJBCkEDB3JLIs3V2a8UiwR1MJm9CAStiYxVQCSz9IECoRBRMgQTWrd96QQLNP - HF8ACeEHCSgQ7/Tecd7Y/mDYRSTobZGYnwib0IBI2JjlRIL7IYIhTlBXfboiEVfbs0N1+USiW1H0 - hedvVpeY+UGCI8anmDc4T6pdNX7eII+mEjahAZWwMcupBPWDBKPUCIW7SuzqgorMGxLzr0G/ABLE - DxIQE47ciSCIxuVlPBH4tkjMT4RNaEAkbMxyIoH9EMEwR3gCV4LSfBN39tBIo+qJxP2lBPKEBAFi - CiSy8j19I+ORQI+mEjahAZWwMcuphCfvEhufindD6bjgIO8sSRxKiScS96uEJ++SAmjcS3ckUiYY - EuNVAj6aStiEBlTCxiymEsiTUcUwIXgCJHBxZmeHWmIAifmdqi+AhCdbgmEq4QROVYbzt62DSoDb - KjE/EjahAZWwMcuphCdbAgsMYDeUjrVE9l7k0sGpeiJxdy2BPNkS2FhVeILyMs0zWejRtQSUD6YS - fUK3VaKPWU4lPPkSxGzOYRMgIZDcvT+RMLuMZtstgZAfX4JALsQEuyVEqk+X8RMHFE+VuPdfL+TJ - l6AcCzGFSmRbpLt2xrmXQ0jMbmj3CQ1MHJbj5SYOj76EnOI/jktRoicSc04c0JMvATGXdIIVx1an - cZqNV4lH24wLbUIDKmFjFlMJ6GkHDSGSsAmQwLu3bONQSzyRuHsRCj2tOIyhjRkwv25HXyLfpCfq - oBKPthkX/sbOyz5mOZXwteKQUoAJ3Euc0wt2WIQOIDG7e/mQSHx/CQqlI3MKJSjNGZUwV+asyN/H - fKABpKrVqf+w37C3UemxVv0n/56cka8QralYQ/oNY2sRVtHWnIcxCxh91OZ4T/fWLH8I4p+ffwGd - 9Me3YzQAAA== - headers: - Access-Control-Allow-Credentials: - - 'true' - Cache-Control: - - max-age=0, private, must-revalidate - Connection: - - keep-alive - Content-Encoding: - - gzip - Content-Length: - - '1033' - Content-Type: - - application/json; charset=utf-8 - Date: - - Fri, 19 May 2023 12:58:15 GMT - ETag: - - W/"81eb5df6ece395240b6951a8223b5f5d" - Referrer-Policy: - - strict-origin-when-cross-origin - Vary: - - Accept-Encoding - - Accept-Encoding - X-Content-Type-Options: - - nosniff - X-Download-Options: - - noopen - X-Frame-Options: - - DENY - X-Permitted-Cross-Domain-Policies: - - none - X-Request-Id: - - 7ac6e671676b1fe526cf0c67d988f7b1 - X-Runtime: - - '0.128295' - X-XSS-Protection: - - 1; mode=block - status: - code: 200 - message: OK -version: 1 diff --git a/requirements-test.txt b/requirements-test.txt index 1853eca..502cf79 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,8 +1,7 @@ -r requirements.txt -yarl -mock>=1.0.1 -requests-mock>=1.3.0 -vcrpy<3.0.0 -PyYAML>=5.1.2 -httpretty>=0.9.6 -wrapt>=1.11.2 +mock>=5.1.0 +requests-mock>=1.11.0 +vcrpy>=4.4.0 +PyYAML>=6.0.1 +httpretty>=1.1.4 +wrapt>=1.15.0 diff --git a/requirements.txt b/requirements.txt index e62d693..ab36637 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,6 @@ requests>=2.10.0 uritemplate>=3.0.0 promise>=1.0.1 -marshmallow>=3.10.0 +marshmallow>=3.19.0 future>=0.18.3 -urllib3<2.0 -vcrpy<=4.0.0 \ No newline at end of file +urllib3<=2.0.4 diff --git a/setup.py b/setup.py index a9164d2..939c1e6 100644 --- a/setup.py +++ b/setup.py @@ -14,28 +14,26 @@ sys.exit() requires = [ - "requests>=2.10.0", - "uritemplate>=3.0.0", - "promise>=1.0.1", - "marshmallow>=3.10.0", + "requests>=2.31.0", + "uritemplate>=4.1.1", + "promise>=2.3.0", + "marshmallow>=3.19.0", "future>=0.18.3", - "urllib3<2.0", + "urllib3<=2.0.4", ] test_requirements = [ - # This is needed to circumvent a vcrpy dependency problem And can be - # deleted once it is solved. - 'yarl; python_version>"3.5"', - 'yarl<1.4; python_version=="3.5"', - "mock>=1.0.1", - "requests-mock>=1.3.0", - "vcrpy<3.0.0", - "PyYAML>=5.1.2", - "httpretty>=0.9.6", - "wrapt>=1.11.2", + "mock>=5.1.0", + "requests-mock>=1.11.0", + "vcrpy>=4.4.0", + "PyYAML>=6.0.1", + "httpretty>=1.1.4", + "wrapt>=1.15.0", ] with open("chartmogul/version.py", "r") as fd: - version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE).group(1) + version = re.search( + r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE + ).group(1) if not version: raise RuntimeError("Cannot find version information") @@ -49,12 +47,15 @@ author_email="petr@chartmogul.com", url="https://chartmogul.com", download_url=github_url + "/tarball/v" + version, - packages=["chartmogul", "chartmogul.api", "chartmogul.imp", "chartmogul.api.customers"], + packages=[ + "chartmogul", + "chartmogul.api", + "chartmogul.api.customers", + ], package_data={"": ["LICENSE", "NOTICE"], "chartmogul": ["*.pem"]}, package_dir={ "chartmogul": "chartmogul", "chartmogul.api": "chartmogul/api", - "chartmogul.imp": "chartmogul/imp", "chartmogul.api.customers": "chartmogul/api/customers", }, include_package_data=True, @@ -67,9 +68,10 @@ classifiers=[ "Programming Language :: Python", "Programming Language :: Python :: 3", - "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", + "Programming Language :: Python :: 3.12", ], ) diff --git a/test/api/test_activity.py b/test/api/test_activity.py index 1b7a631..4e7834c 100644 --- a/test/api/test_activity.py +++ b/test/api/test_activity.py @@ -38,7 +38,6 @@ def test_all(self, mock_requests): }, ], "has_more": False, - "per_page": 200, "cursor": "cursor==", }, ) diff --git a/test/api/test_common.py b/test/api/test_common.py index 115b248..e8131e6 100644 --- a/test/api/test_common.py +++ b/test/api/test_common.py @@ -4,7 +4,13 @@ import requests_mock from requests.exceptions import HTTPError -from chartmogul import DataSource, Config, APIError, ArgumentMissingError +from chartmogul import ( + DataSource, + Config, + APIError, + ArgumentMissingError, + DeprecatedArgumentError, +) class CommonTestCase(unittest.TestCase): @@ -15,7 +21,9 @@ class CommonTestCase(unittest.TestCase): @requests_mock.mock() def test_forget_uuid_destroy(self, mock_requests): mock_requests.register_uri( - "DELETE", "https://api.chartmogul.com/v1/data_sources/my_uuid", status_code=204 + "DELETE", + "https://api.chartmogul.com/v1/data_sources/my_uuid", + status_code=204, ) mock_requests.register_uri( "DELETE", @@ -58,13 +66,38 @@ def test_forget_uuid_retrieve(self, mock_requests): else: self.fail("ArgumentMissingError not raised") + @requests_mock.mock() + def test_page_parameter_deprecated(self, mock_requests): + mock_requests.register_uri( + "GET", + "https://api.chartmogul.com/v1/data_sources?page=1", + status_code=400, + json={ + "code": 400, + "message": 'Parameter "page" is deprecated', + "param": "page", + }, + ) + + config = Config("token") + try: + DataSource.all(config, page=1).get() + except DeprecatedArgumentError: + pass + else: + self.fail("DeprecatedArgumentError not raised") + @requests_mock.mock() def test_api_incorrect(self, mock_requests): mock_requests.register_uri( "POST", "https://api.chartmogul.com/v1/data_sources", status_code=400, - json={"code": 400, "message": 'Parameter "name" is missing', "param": "name"}, + json={ + "code": 400, + "message": 'Parameter "name" is missing', + "param": "name", + }, ) config = Config("token") diff --git a/test/api/test_customer.py b/test/api/test_customer.py index 9d5f4bf..d82fc73 100644 --- a/test/api/test_customer.py +++ b/test/api/test_customer.py @@ -76,15 +76,7 @@ "currency-sign": "$", } -allContactsOld = { - "entries": [entry], - "per_page": 50, - "page": 1, - "current_page": 1, - "total_pages": 4, -} - -allContactsNew = {"entries": [entry], "cursor": "cursor==", "has_more": True} +allContacts = {"entries": [entry], "cursor": "cursor==", "has_more": True} deserializedCustomer = Customer( id=25647, @@ -294,49 +286,13 @@ class CustomerTestCase(unittest.TestCase): """ @requests_mock.mock() - def test_all_old_pagination(self, mock_requests): - mock_requests.register_uri( - "GET", - "https://api.chartmogul.com/v1/customers", - request_headers={"Authorization": "Basic dG9rZW46"}, - status_code=200, - json=allContactsOld, - ) - - config = Config("token") - customers = Customer.all(config).get() - - expected = Customer._many( - entries=[deserializedCustomer], per_page=50, page=1, current_page=1, total_pages=4 - ) - - self.assertEqual(mock_requests.call_count, 1, "expected call") - self.assertEqual(mock_requests.last_request.qs, {}) - self.assertEqual(mock_requests.last_request.text, None) - # Complete comparing too complicated, would need to: - # 1) sort all dictionaries, - # 2) use special class/library for timezones (Python has no default) - # self.assertEqual(str(customers), str(expected)) - # => check only first level fields are OK - self.assertEqual(sorted(dir(customers)), sorted(dir(expected))) - self.assertEqual( - sorted(customers.entries[0].attributes.stripe), - sorted(expected.entries[0].attributes.stripe), - ) - self.assertEqual( - sorted(customers.entries[0].attributes.clearbit), - sorted(expected.entries[0].attributes.clearbit), - ) - self.assertTrue(isinstance(customers.entries[0], Customer)) - - @requests_mock.mock() - def test_all_new_pagination(self, mock_requests): + def test_all(self, mock_requests): mock_requests.register_uri( "GET", "https://api.chartmogul.com/v1/customers", request_headers={"Authorization": "Basic dG9rZW46"}, status_code=200, - json=allContactsNew, + json=allContacts, ) config = Config("token") @@ -366,7 +322,10 @@ def test_all_new_pagination(self, mock_requests): @requests_mock.mock() def test_create(self, mock_requests): mock_requests.register_uri( - "POST", "https://api.chartmogul.com/v1/customers", status_code=200, json=entry + "POST", + "https://api.chartmogul.com/v1/customers", + status_code=200, + json=entry, ) config = Config("token") @@ -376,31 +335,12 @@ def test_create(self, mock_requests): self.assertEqual(mock_requests.last_request.json(), sentCreateExpected) @requests_mock.mock() - def test_search_old_pagination(self, mock_requests): - mock_requests.register_uri( - "GET", - "https://api.chartmogul.com/v1/customers/search?email=tralala@someemail.com", - status_code=200, - json=allContactsOld, - ) - - config = Config("token") - result = Customer.search(config, email="tralala@someemail.com").get() - self.assertEqual(mock_requests.call_count, 1, "expected call") - self.assertEqual(mock_requests.last_request.qs, {"email": ["tralala@someemail.com"]}) - self.assertEqual(mock_requests.last_request.text, None) - self.assertTrue(isinstance(result, Customer._many)) - self.assertTrue(isinstance(result.entries[0], Customer)) - self.assertEqual(result.current_page, 1) - self.assertEqual(result.total_pages, 4) - - @requests_mock.mock() - def test_search_new_pagination(self, mock_requests): + def test_search(self, mock_requests): mock_requests.register_uri( "GET", "https://api.chartmogul.com/v1/customers/search?email=tralala@someemail.com", status_code=200, - json=allContactsNew, + json=allContacts, ) config = Config("token") @@ -507,12 +447,12 @@ def test_contacts(self, mock_requests): "GET", "https://api.chartmogul.com/v1/customers/cus_00000000-0000-0000-0000-000000000000/contacts", status_code=200, - json=allContactsNew, + json=allContacts, ) config = Config("token") contacts = Customer.contacts(config, uuid="cus_00000000-0000-0000-0000-000000000000").get() - expected = Contact._many(**allContactsNew) + expected = Contact._many(**allContacts) self.assertEqual(mock_requests.call_count, 1, "expected call") self.assertEqual(mock_requests.last_request.qs, {}) diff --git a/test/api/test_customers/test_activity.py b/test/api/test_customers/test_activity.py index 3dac82c..2fe645e 100644 --- a/test/api/test_customers/test_activity.py +++ b/test/api/test_customers/test_activity.py @@ -35,7 +35,6 @@ def test_all(self, mock_requests): ], "has_more": False, "per_page": 200, - "page": 1, "cursor": "cursor==", }, ) diff --git a/test/api/test_customers/test_subscription.py b/test/api/test_customers/test_subscription.py index 563a3d4..4f94d0c 100644 --- a/test/api/test_customers/test_subscription.py +++ b/test/api/test_customers/test_subscription.py @@ -30,7 +30,9 @@ def test_cancel_subscription(self, mock_requests): ) config = Config("token") # is actually checked in mock result = CustomerSubscription.cancel( - config, uuid="some_uuid", data={"cancelled_at": datetime(2016, 1, 15, 0, 0, 0)} + config, + uuid="some_uuid", + data={"cancelled_at": datetime(2016, 1, 15, 0, 0, 0)}, ).get() self.assertEqual(mock_requests.call_count, 1, "expected call") @@ -110,6 +112,8 @@ def test_list_imported_subscriptions(self, mock_requests): self.assertEqual(mock_requests.last_request.qs, {}) self.assertEqual(result.__class__.__name__, CustomerSubscription._many.__name__) self.assertEqual(result.customer_uuid, "some_uuid") + self.assertEqual(result.cursor, "cursor==") + self.assertFalse(result.has_more) @requests_mock.mock() def test_all(self, mock_requests): @@ -139,7 +143,6 @@ def test_all(self, mock_requests): ], "has_more": False, "per_page": 200, - "page": 1, "cursor": "cursor==", }, ) @@ -150,5 +153,5 @@ def test_all(self, mock_requests): self.assertEqual(mock_requests.last_request.qs, {}) self.assertEqual(result.__class__.__name__, CustomerSubscription._many.__name__) self.assertEqual(result.entries[0].external_id, "sub_0001") - self.assertEqual(result.page, 1) self.assertEqual(result.cursor, "cursor==") + self.assertFalse(result.has_more) diff --git a/test/api/test_invoice.py b/test/api/test_invoice.py index 24cabb4..0f362e7 100644 --- a/test/api/test_invoice.py +++ b/test/api/test_invoice.py @@ -166,66 +166,7 @@ ] } -oldInvoiceListExample = { - "invoices": [ - { - "uuid": "inv_565c73b2-85b9-49c9-a25e-2b7df6a677c9", - "customer_uuid": "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7", - "external_id": "INV0001", - "date": "2015-11-01T00:00:00.000Z", - "due_date": "2015-11-15T00:00:00.000Z", - "currency": "USD", - "line_items": [ - { - "uuid": "li_d72e6843-5793-41d0-bfdf-0269514c9c56", - "external_id": None, - "type": "subscription", - "subscription_uuid": "sub_e6bc5407-e258-4de0-bb43-61faaf062035", - "plan_uuid": "pl_eed05d54-75b4-431b-adb2-eb6b9e543206", - "prorated": False, - "service_period_start": "2015-11-01T00:00:00.000Z", - "service_period_end": "2015-12-01T00:00:00.000Z", - "amount_in_cents": 5000, - "quantity": 1, - "discount_code": "PSO86", - "discount_amount_in_cents": 1000, - "tax_amount_in_cents": 900, - "account_code": None, - }, - { - "uuid": "li_0cc8c112-beac-416d-af11-f35744ca4e83", - "external_id": None, - "type": "one_time", - "description": "Setup Fees", - "amount_in_cents": 2500, - "quantity": 1, - "discount_code": "PSO86", - "discount_amount_in_cents": 500, - "tax_amount_in_cents": 450, - "account_code": None, - "discount_description": "Special 20 % discount", - "transaction_fees_in_cents": 50, - "transaction_fees_currency": "CZK", - "event_order": 5, - }, - ], - "transactions": [ - { - "uuid": "tr_879d560a-1bec-41bb-986e-665e38a2f7bc", - "external_id": None, - "type": "payment", - "date": "2015-11-05T00:14:23.000Z", - "result": "successful", - } - ], - } - ], - "current_page": 1, - "total_pages": 1, -} - - -newInvoiceListExample = { +invoiceListExample = { "invoices": [ { "uuid": "inv_565c73b2-85b9-49c9-a25e-2b7df6a677c9", @@ -366,8 +307,8 @@ def test_create(self, mock_requests): @requests_mock.mock() def test_list_has_customer_uuid(self, mock_requests): responseData["customer_uuid"] = "UUID" - responseData["total_pages"] = 1 - responseData["current_page"] = 1 + responseData["cursor"] = None + responseData["has_more"] = False mock_requests.register_uri( "GET", @@ -388,8 +329,8 @@ def test_list_has_customer_uuid(self, mock_requests): self.assertTrue(isinstance(result.invoices[0], Invoice)) self.assertEqual(result.invoices[0].uuid, "inv_565c73b2-85b9-49c9-a25e-2b7df6a677c9") self.assertEqual(result.customer_uuid, "UUID") - self.assertEqual(result.total_pages, 1) - self.assertEqual(result.current_page, 1) + self.assertEqual(result.cursor, None) + self.assertFalse(result.has_more) @requests_mock.mock() def test_new_list_old_pagination(self, mock_requests): @@ -402,47 +343,14 @@ def test_new_list_old_pagination(self, mock_requests): request_headers={"Authorization": "Basic dG9rZW46"}, headers={"Content-Type": "application/json"}, status_code=200, - json=oldInvoiceListExample, + json=invoiceListExample, ) config = Config("token") # is actually checked in mock result = Invoice.all( - config, customer_uuid="cus_f466e33d-ff2b-4a11-8f85-417eb02157a7", external_id="INV0001" - ).get() - - self.assertEqual(mock_requests.call_count, 1, "expected call") - cu = [] - cu.append("cus_f466e33d-ff2b-4a11-8f85-417eb02157a7") - ei = [] - ei.append("inv0001") - self.assertEqual(mock_requests.last_request.qs, {"customer_uuid": cu, "external_id": ei}) - # Struct too complex to do 1:1 comparison - self.assertTrue(isinstance(result, Invoice._many)) - self.assertEqual(len(result.invoices), 1) - - self.assertEqual( - result.invoices[0].customer_uuid, "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7" - ) - self.assertEqual(result.current_page, 1) - self.assertEqual(result.total_pages, 1) - - @requests_mock.mock() - def test_new_list_new_pagination(self, mock_requests): - mock_requests.register_uri( - "GET", - ( - "https://api.chartmogul.com/v1/invoices" - "?external_id=INV0001&customer_uuid=cus_f466e33d-ff2b-4a11-8f85-417eb02157a7" - ), - request_headers={"Authorization": "Basic dG9rZW46"}, - headers={"Content-Type": "application/json"}, - status_code=200, - json=newInvoiceListExample, - ) - - config = Config("token") # is actually checked in mock - result = Invoice.all( - config, customer_uuid="cus_f466e33d-ff2b-4a11-8f85-417eb02157a7", external_id="INV0001" + config, + customer_uuid="cus_f466e33d-ff2b-4a11-8f85-417eb02157a7", + external_id="INV0001", ).get() self.assertEqual(mock_requests.call_count, 1, "expected call") @@ -458,8 +366,8 @@ def test_new_list_new_pagination(self, mock_requests): self.assertEqual( result.invoices[0].customer_uuid, "cus_f466e33d-ff2b-4a11-8f85-417eb02157a7" ) - self.assertFalse(result.has_more) self.assertEqual(result.cursor, "cursor==") + self.assertFalse(result.has_more) @requests_mock.mock() def test_delete(self, mock_requests): diff --git a/test/api/test_plan.py b/test/api/test_plan.py index c0f4776..b95e4a1 100644 --- a/test/api/test_plan.py +++ b/test/api/test_plan.py @@ -10,10 +10,8 @@ class PlanTestCase(unittest.TestCase): Tests cursor query parameters & modify (patch a plan). """ - maxDiff = None - @requests_mock.mock() - def test_cursor_list_plans_old_pagination(self, mock_requests): + def test_cursor_list_plans(self, mock_requests): expected_plan_dict = { "uuid": "whatever_uuid", "data_source_uuid": "some_uuid", @@ -25,62 +23,37 @@ def test_cursor_list_plans_old_pagination(self, mock_requests): mock_requests.register_uri( "GET", ( - "https://api.chartmogul.com/v1/plans?page=5" + "https://api.chartmogul.com/v1/plans?" "&per_page=12&data_source_uuid=some_uuid&external_id=custom_filter" ), request_headers={"Authorization": "Basic dG9rZW46"}, status_code=200, - json={"plans": [expected_plan_dict], "current_page": 5, "total_pages": 18}, + json={ + "plans": [expected_plan_dict], + "cursor": "cursor==", + "has_more": False, + }, ) config = Config("token") # is actually checked in mock plan = Plan.all( - config, page=5, per_page=12, data_source_uuid="some_uuid", external_id="custom_filter" + config, + per_page=12, + data_source_uuid="some_uuid", + external_id="custom_filter", ).get() - expected = Plan._many([Plan(**expected_plan_dict)], current_page=5, total_pages=18) + expected = Plan._many([Plan(**expected_plan_dict)], cursor="cursor==", has_more=False) self.assertEqual(mock_requests.call_count, 1, "expected call") self.assertEqual( mock_requests.last_request.qs, { "data_source_uuid": ["some_uuid"], "external_id": ["custom_filter"], - "page": ["5"], "per_page": ["12"], }, ) self.assertEqual(mock_requests.last_request.text, None) self.assertEqual(str(plan), str(expected)) - @requests_mock.mock() - def test_cursor_list_plans_new_pagination(self, mock_requests): - expected_plan_dict = { - "uuid": "whatever_uuid", - "data_source_uuid": "some_uuid", - "name": "some plan", - "interval_count": 2, - "interval_unit": "moonshines", - "external_id": "custom_filter", - } - mock_requests.register_uri( - "GET", - ( - "https://api.chartmogul.com/v1/plans?cursor=cursor==" - "&per_page=12&data_source_uuid=some_uuid&external_id=custom_filter" - ), - request_headers={"Authorization": "Basic dG9rZW46"}, - status_code=200, - json={"plans": [expected_plan_dict], "has_more": True, "cursor": "cursor=="}, - ) - config = Config("token") # is actually checked in mock - plan = Plan.all( - config, - cursor="cursor==", - per_page=12, - data_source_uuid="some_uuid", - external_id="custom_filter", - ).get() - expected = Plan._many([Plan(**expected_plan_dict)], has_more=True, cursor="cursor==") - self.assertEqual(str(plan), str(expected)) - @requests_mock.mock() def test_modify_plan(self, mock_requests): expected_plan_dict = { diff --git a/test/api/test_plan_group.py b/test/api/test_plan_group.py index fab5511..982cd45 100644 --- a/test/api/test_plan_group.py +++ b/test/api/test_plan_group.py @@ -66,7 +66,7 @@ def test_retrieve_plan_group(self, mock_requests): self.assertEqual(result.plans_count, 2) @requests_mock.mock() - def test_retrieve_plan_group_plans_old_pagination(self, mock_requests): + def test_retrieve_plan_group_plans(self, mock_requests): expected_plans = { "plans": [ { @@ -86,51 +86,8 @@ def test_retrieve_plan_group_plans_old_pagination(self, mock_requests): "external_id": "plan_EOsEG3pyySMBEP", }, ], - "current_page": 1, - "total_pages": 1, - } - mock_requests.register_uri( - "GET", - "https://api.chartmogul.com/v1/plan_groups/whatever_uuid/plans", - request_headers={"Authorization": "Basic dG9rZW46"}, - status_code=200, - json=expected_plans, - ) - - config = Config("token") # is actually checked in mock - result = PlanGroup.all(config, uuid="whatever_uuid").get() - - self.assertEqual(mock_requests.call_count, 1, "expected call") - self.assertEqual(mock_requests.last_request.qs, {}) - self.assertEqual(result.plans[0].uuid, "pl_cef31082-37be-11ea-a7bc-cb55fa0afcbb") - self.assertEqual(result.plans[1].uuid, "pl_cef46630-37be-11ea-a7bc-a316cc9407e9") - self.assertEqual(len(result.plans), 2) - self.assertEqual(result.total_pages, 1) - self.assertEqual(result.current_page, 1) - - @requests_mock.mock() - def test_retrieve_plan_group_plans_new_pagination(self, mock_requests): - expected_plans = { - "plans": [ - { - "name": "Berghain Flatrate Pack - bi-annual", - "uuid": "pl_cef31082-37be-11ea-a7bc-cb55fa0afcbb", - "data_source_uuid": "ds_73c24b7e-37be-11ea-85a4-03a4322daccc", - "interval_count": 6, - "interval_unit": "month", - "external_id": "plan_EOwj9vInDKILy1", - }, - { - "name": "Berghain Flatrate Pack - Skip the Queue Pack", - "uuid": "pl_cef46630-37be-11ea-a7bc-a316cc9407e9", - "data_source_uuid": "ds_73c24b7e-37be-11ea-85a4-03a4322daccc", - "interval_count": 1, - "interval_unit": "month", - "external_id": "plan_EOsEG3pyySMBEP", - }, - ], - "has_more": False, "cursor": "cursor==", + "has_more": False, } mock_requests.register_uri( "GET", @@ -153,35 +110,6 @@ def test_retrieve_plan_group_plans_new_pagination(self, mock_requests): @requests_mock.mock() def test_all_plan_groups_old_pagination(self, mock_requests): - expected_plan_groups = { - "plan_groups": [ - {"uuid": "whatever_uuid", "name": "good_plan", "plans_count": 2}, - {"uuid": "my_uuid", "name": "best_plan", "plans_count": 5}, - ], - "current_page": 1, - "total_pages": 1, - } - mock_requests.register_uri( - "GET", - "https://api.chartmogul.com/v1/plan_groups", - status_code=200, - json=expected_plan_groups, - ) - - config = Config("token") - result = PlanGroup.all(config).get() - - self.assertEqual(mock_requests.call_count, 1, "expected call") - self.assertEqual(mock_requests.last_request.qs, {}) - self.assertEqual(mock_requests.last_request.text, None) - self.assertTrue(isinstance(result.plan_groups[0], PlanGroup)) - self.assertEqual(result.plan_groups[0].uuid, "whatever_uuid") - self.assertEqual(result.plan_groups[1].uuid, "my_uuid") - self.assertEqual(result.total_pages, 1) - self.assertEqual(result.current_page, 1) - - @requests_mock.mock() - def test_all_plan_groups_new_pagination(self, mock_requests): expected_plan_groups = { "plan_groups": [ {"uuid": "whatever_uuid", "name": "good_plan", "plans_count": 2}, @@ -212,7 +140,9 @@ def test_all_plan_groups_new_pagination(self, mock_requests): @requests_mock.mock() def test_destroy_plan_group(self, mock_requests): mock_requests.register_uri( - "DELETE", "https://api.chartmogul.com/v1/plan_groups/my_uuid", status_code=204 + "DELETE", + "https://api.chartmogul.com/v1/plan_groups/my_uuid", + status_code=204, ) config = Config("token") @@ -225,7 +155,11 @@ def test_destroy_plan_group(self, mock_requests): @requests_mock.mock() def test_modify_plan_group_name(self, mock_requests): - expected_plan_group_dict = {"uuid": "whatever_uuid", "name": "new_name", "plans_count": 2} + expected_plan_group_dict = { + "uuid": "whatever_uuid", + "name": "new_name", + "plans_count": 2, + } mock_requests.register_uri( "PATCH", "https://api.chartmogul.com/v1/plan_groups/whatever_uuid", @@ -245,7 +179,11 @@ def test_modify_plan_group_name(self, mock_requests): @requests_mock.mock() def test_modify_plan_group_plans(self, mock_requests): - expected_plan_group_dict = {"uuid": "whatever_uuid", "name": "new_name", "plans_count": 3} + expected_plan_group_dict = { + "uuid": "whatever_uuid", + "name": "new_name", + "plans_count": 3, + } mock_requests.register_uri( "PATCH", "https://api.chartmogul.com/v1/plan_groups/whatever_uuid", @@ -255,7 +193,9 @@ def test_modify_plan_group_plans(self, mock_requests): ) config = Config("token") # is actually checked in mock result = PlanGroup.modify( - config, uuid="whatever_uuid", data={"plans": "[pl_uuid_1, pl_uuid_2, pl_uuid_3]"} + config, + uuid="whatever_uuid", + data={"plans": "[pl_uuid_1, pl_uuid_2, pl_uuid_3]"}, ).get() self.assertEqual(mock_requests.call_count, 1, "expected call") diff --git a/test/api/test_subscription_event.py b/test/api/test_subscription_event.py index 356f32f..713b02f 100644 --- a/test/api/test_subscription_event.py +++ b/test/api/test_subscription_event.py @@ -23,32 +23,7 @@ "amount_in_cents": 1000, } -sub_ev_list_expected_old = { - "subscription_events": [ - { - "id": 7654321, - "external_id": "evnt_026", - "customer_external_id": "scus_022", - "data_source_uuid": "ds_1fm3eaac-62d0-31ec-clf4-4bf0mbe81aba", - "event_type": "subscription_start_scheduled", - "event_date": "2022-03-30 23:00:00.000", - "effective_date": "2022-04-01 23:00:00.000", - "subscription_external_id": "sub_0001", - "plan_external_id": "gol d_monthly", - "currency": "USD", - "amount_in_cents": 1000, - } - ], - "meta": { - "next_key": 67048503, - "prev_key": None, - "before_key": "2022-04-10T22:27:35.834Z", - "page": 1, - "total_pages": 166, - }, -} - -sub_ev_list_expected_new = { +sub_ev_list_expected = { "subscription_events": [ { "id": 7654321, @@ -221,27 +196,20 @@ def test_modify_subscription_event_with_bad_params(self, mock_requests): self.fail("ArgumentMissingError not raised") @requests_mock.mock() - def test_all_subscription_events_old_pagination(self, mock_requests): + def test_all_subscription_events(self, mock_requests): mock_requests.register_uri( "GET", "https://api.chartmogul.com/v1/subscription_events", request_headers={"Authorization": "Basic dG9rZW46"}, status_code=200, - json=sub_ev_list_expected_old, + json=sub_ev_list_expected, ) config = Config("token") subscription_events = SubscriptionEvent.all(config).get() expected = SubscriptionEvent._many( - subscription_events=[sub_ev_one], - meta={ - "next_key": 67048503, - "prev_key": None, - "before_key": "2022-04-10T22:27:35.834Z", - "page": 1, - "total_pages": 166, - }, + subscription_events=[sub_ev_one], has_more=True, cursor="cursor==" ) self.assertEqual(mock_requests.call_count, 1, "expected call") @@ -262,7 +230,7 @@ def test_all_subscription_events_with_filters(self, mock_requests): "&customer_external_id=scus_022&event_type=subscription_start_scheduled&plan_external_id=gol d_monthly", request_headers={"Authorization": "Basic dG9rZW46"}, status_code=200, - json=sub_ev_list_expected_new, + json=sub_ev_list_expected, ) config = Config("token") diff --git a/test/integration/fixtures/delete_invoice.yaml b/test/integration/fixtures/delete_invoice.yaml index b1311e0..8949150 100644 --- a/test/integration/fixtures/delete_invoice.yaml +++ b/test/integration/fixtures/delete_invoice.yaml @@ -11,7 +11,7 @@ interactions: Content-Length: - '2' User-Agent: - - chartmogul-python/3.1.1 + - chartmogul-python/4.0.0 content-type: - application/json method: POST diff --git a/test/integration/fixtures/fetch_subscription_events.yaml b/test/integration/fixtures/fetch_subscription_events.yaml deleted file mode 100644 index 57e6f1c..0000000 --- a/test/integration/fixtures/fetch_subscription_events.yaml +++ /dev/null @@ -1,78 +0,0 @@ -interactions: -- request: - body: null - headers: - Accept: - - '*/*' - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - User-Agent: - - chartmogul-python/3.1.1 - content-type: - - application/json - method: GET - uri: https://api.chartmogul.com/v1/subscription_events - response: - body: - string: !!binary | - H4sIAAAAAAAAA+2b35KiOBTG34Xrdir/Q3yOvtqtKQohqCBIQ7B1uvrdNwlbu+vUjoyEgF1llTfK - IR6Sn19OPpOPoO02bdLsa7U/VpE8yUq1wfrPj2CfBmtMuUAhJuglSGMVR+2xaxIZdZ25GKRtJDDM - oIjRKuFptoJQpquNhGKVbTiPM0bTOBXBS5B0rTqWsonkWcmmig+RbYBDATjU169yaKW6jqu6w+Gn - mOt2ENn94Fi3Ux9i/Qz//Y7+XvtYkX4EqdNGAOEVoCvIXwFbI7BG/A99r8wymaj9Sf4cB/ArAGv7 - snGmiyJ1qU1bV4kncZXIw0GmprX/SaJpjo3u249P3SGN1MmkUax+nVBXm4Rvx7x1caX26hKs+wdN - uqaRVfLP+7g8djrbfRUl/cD2YSo+R7+41EjVxIn53r7TzECZmz5frpGAfpCAIQPMDOVVz96PRFGU - bcifSJjf3lxIAD9IIEghYO5I5Hm2u7TjkWCPphI2oQGVsDGLqQQWfpAgVCAKJkCCKtbsvCGBZp84 - vgASoR8kYIi40XvHeWP7g2EXkaC3RWJ+ImxCAyJhY5YTCe6HCIY4Qab6dEUiqbdnh+ryiYRZUfSF - 529Wl5j5QYIjxqeYNzhP6109ft4gj6YSNqEBlbAxy6kE9YMEo1QLhbtK7JqShrk3JOZfg34BJIgf - JCAmHLkTQRBNqst4IvBtkZifCJvQgEjYmOVEAvshgmGO8ASuBKXFJjH20Eij6onE/aUE8oQEAeEU - SOTVe/ZGxiOBHk0lbEIDKmFjllMJT94l1j4VN0PpuOAg7yxNHUqJJxL3q4Qn75ICqN1LdyQyFjIU - jlcJ+GgqYRMaUAkbs5hKIE9GFcOE4AmQwOWZnR1qiQEk5neqvgASnmwJhqmAEzhVOS7etg4qAW6r - xPxI2IQGVMLGLKcSnmwJHGIAzVA61hL5e1kIB6fqicTdtQTyZEtgbVXhCcrLrMhFqUbXElA8mEr0 - Cd1WiT5mOZXw5EsQvTmHTYBEiMTu/YmE3mU0224JhPz4EgTyMJxgt0SYqdNl/MQBw6dK3PuvF/Lk - S1COw3AKlci3SJl2xrmXQ0jMbmj3CQ1MHJbj5SYOj76EmOI/jktZoScSc04c0JMvATEXdIIVx1Zl - SZaPV4lH24wLbUIDKmFjFlMJ6GkHDSGCsAmQwLu3fONQSzyRuHsRCj2tOLShjRnQv25HX6LYZCfq - oBKPthkX/sbOyz5mOZXwteIQIgQTuJe4oBfssAgdQGJ29/Ihkfj+EpRSxfoUSlDpMypRIfVZkb+P - +UANSN3IU/9hv2FvI7NjI/tP/j05I14hXgO8JvgbR9YPquOtPg+jFzDqqPTxHvNWL38I4p+ffwES - uS0yYzQAAA== - headers: - Access-Control-Allow-Credentials: - - 'true' - Cache-Control: - - max-age=0, private, must-revalidate - Connection: - - keep-alive - Content-Encoding: - - gzip - Content-Length: - - '1033' - Content-Type: - - application/json; charset=utf-8 - Date: - - Fri, 19 May 2023 13:03:43 GMT - ETag: - - W/"605f65f25551e36f294b1276648844b4" - Referrer-Policy: - - strict-origin-when-cross-origin - Vary: - - Accept-Encoding - - Accept-Encoding - X-Content-Type-Options: - - nosniff - X-Download-Options: - - noopen - X-Frame-Options: - - DENY - X-Permitted-Cross-Domain-Policies: - - none - X-Request-Id: - - 4549e2f044e141372f3e09f1bf571314 - X-Runtime: - - '0.052033' - X-XSS-Protection: - - 1; mode=block - status: - code: 200 - message: OK -version: 1 diff --git a/test/integration/test_fetch_account.py b/test/integration/test_fetch_account.py new file mode 100644 index 0000000..5088493 --- /dev/null +++ b/test/integration/test_fetch_account.py @@ -0,0 +1,16 @@ +import unittest +import vcr +from chartmogul import Config, Account + +config = Config(api_key="-") + + +class FetchAccountTestCase(unittest.TestCase): + """ + Tests errors & user mistakes. + """ + + @vcr.use_cassette("fixtures/fetch_account.yaml", filter_headers=["authorization"], record=True) + def test_fetch_account(self): + account = Account.retrieve(config).get() + self.assertTrue(isinstance(account, Account)) diff --git a/test/integration/test_fetch_subscription_events.py b/test/integration/test_fetch_subscription_events.py deleted file mode 100644 index cad28ee..0000000 --- a/test/integration/test_fetch_subscription_events.py +++ /dev/null @@ -1,15 +0,0 @@ -import unittest -import vcr -from chartmogul import Config, SubscriptionEvent - -config = Config(api_key="-") - - -class FetchSubscriptionEventsTestCase(unittest.TestCase): - """ - Tests errors & user mistakes. - """ - - @vcr.use_cassette("fixtures/fetch_subscription_events.yaml", filter_headers=["authorization"]) - def test_subscription_events(self): - result = SubscriptionEvent.all(config).get()