├── .flake8 ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── publish.yml │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.rst ├── aftership ├── __init__.py ├── const.py ├── courier.py ├── estimated_delivery_date.py ├── exception.py ├── notification.py ├── request.py ├── response.py ├── tracking.py └── util.py ├── docs ├── Makefile ├── conf.py ├── index.rst └── make.bat ├── examples ├── courier_example.py ├── estimated_delivery_date_example.py ├── notification_example.py └── tracking_example.py ├── poetry.lock ├── pyproject.toml ├── setup.cfg └── tests ├── __init__.py ├── conftest.py ├── fixtures └── cassettes │ ├── CourierTestCase.test_detect_courier.yaml │ ├── CourierTestCase.test_get_all_couriers.yaml │ ├── CourierTestCase.test_get_couriers.yaml │ ├── EstimatedDeliveryDateTestCase.test_batch_predict_estimated_delivery_date.yaml │ ├── NotificationTestCase.test_add_notification.yaml │ ├── NotificationTestCase.test_list_notification.yaml │ ├── NotificationTestCase.test_remove_notification.yaml │ ├── TrackingTestCase.test_create_tracking.yaml │ ├── TrackingTestCase.test_get_last_checkpoint.yaml │ ├── TrackingTestCase.test_get_tracking.yaml │ ├── TrackingTestCase.test_list_trackings.yaml │ ├── TrackingTestCase.test_retrack.yaml │ ├── TrackingTestCase.test_update_tracking.yaml │ ├── TrackingWithAdditionalFieldsTestCase.test_create_tracking.yaml │ ├── TrackingWithAdditionalFieldsTestCase.test_get_last_checkpoint.yaml │ ├── TrackingWithAdditionalFieldsTestCase.test_get_tracking.yaml │ ├── TrackingWithAdditionalFieldsTestCase.test_get_tracking_by_id.yaml │ ├── TrackingWithAdditionalFieldsTestCase.test_get_tracking_with_internal_error.yaml │ └── TrackingWithAdditionalFieldsTestCase.test_update_tracking.yaml ├── test_couriers.py ├── test_estimated_delivery_date.py ├── test_notifications.py ├── test_trackings.py └── test_util.py /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 119 3 | exclude = venv,build,.tox,setup.py,tests,docs 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Versions** 11 | Python version: 12 | SDK version: 13 | OS type: 14 | OS version: 15 | OS architecture: 16 | 17 | **Describe the bug** 18 | A clear and concise description of what the bug is, steps to reproduce the behavior. 19 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Package Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Setup Python # Set Python version 14 | uses: actions/setup-python@v2 15 | with: 16 | python-version: 3.9 17 | - name: Install dependencies 18 | run: | 19 | python -m pip install --upgrade pip poetry 20 | poetry config virtualenvs.in-project --unset 21 | make install 22 | - name: Lint 23 | run: | 24 | make lint 25 | - name: Test 26 | run: | 27 | make test 28 | - name: Build 29 | run: | 30 | make build 31 | - name: Get the version 32 | id: get_version 33 | run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} 34 | - name: Upload artifact 35 | uses: actions/upload-artifact@v2 36 | with: 37 | name: ${{ steps.get_version.outputs.VERSION }} 38 | path: dist 39 | - name: Publish release to PyPI 40 | run: | 41 | pip install twine 42 | twine upload -u ${{ secrets.PYPI_USERNAME }} -p ${{ secrets.PYPI_PASSWORD }} --verbose dist/* 43 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Python Lint & Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | python-version: 17 | - "3.6" 18 | - "3.7" 19 | - "3.8" 20 | - "3.9" 21 | - "3.10" 22 | 23 | steps: 24 | - uses: actions/checkout@v2 25 | - name: Set up Python ${{ matrix.python-version }} 26 | uses: actions/setup-python@v2 27 | with: 28 | python-version: ${{ matrix.python-version }} 29 | - name: Cache Poetry 30 | uses: actions/cache@v2 31 | with: 32 | # This path is specific to Ubuntu 33 | path: | 34 | ~/.cache/pip 35 | ~/.cache/pypoetry/cache 36 | ~/.cache/pre-commit 37 | # Use lock file as cache key 38 | key: ${{ runner.os }}-poetry-${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }} 39 | restore-keys: | 40 | ${{ runner.os }}-poetry-${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }} 41 | ${{ runner.os }}-poetry-${{ matrix.python-version }}- 42 | - name: Install dependencies 43 | run: | 44 | python -m pip install --upgrade pip poetry 45 | poetry config virtualenvs.in-project --unset 46 | make install 47 | - name: Lint 48 | run: | 49 | make lint 50 | - name: Test 51 | run: | 52 | make test 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | # macOS cache 107 | .DS_Store 108 | 109 | # IntelliJ Or PyCharm settings 110 | .idea/ 111 | 112 | # Emacs 113 | *~ 114 | .*~ 115 | .#* 116 | \#*# 117 | 118 | # Environment files 119 | .envrc 120 | 121 | # VS code settings 122 | .vscode/ 123 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [1.4.1] - 2022-07-20 8 | ### Added 9 | - add predict-batch endpoint https://github.com/AfterShip/aftership-sdk-python/pull/38 10 | 11 | ## [1.4.0] - 2022-05-24 12 | 13 | ### Added 14 | 15 | - feat: add more fields for `Get trackings` API (#33) 16 | 17 | ## [1.3.0] - 2021-07-13 18 | 19 | ### Changed 20 | 21 | - Fix: throws JSONDecoder if we got 502 error from Cloudflare 22 | [#31](https://github.com/AfterShip/aftership-sdk-python/issues/31). 23 | 24 | ### Removed 25 | 26 | - Python 3.5 support. 27 | 28 | ## [1.2.1] - 2021-03-26 29 | 30 | ### Changed 31 | 32 | - Update package setup.py. 33 | 34 | ## [1.2.0] - 2021-03-26 35 | 36 | ### Changed 37 | 38 | - Add tracking support additional fields. 39 | 40 | ## [1.1.0] - 2020-08-17 41 | 42 | A dummy version, NO CHANGES. 43 | 44 | ## [1.0.post2] - 2020-03-11 45 | 46 | ### Changed 47 | 48 | - Bump version. 49 | 50 | ## [1.0.post1] - 2020-03-11 51 | 52 | ### Changed 53 | 54 | - Fix import aftership problem [#15](https://github.com/AfterShip/aftership-sdk-python/issues/15). 55 | 56 | ## [1.0] - 2020-03-10 57 | 58 | ### Added 59 | 60 | - Python 3.5+ support. 61 | 62 | ### Changed 63 | 64 | - This package is not compatible with previous releases. 65 | 66 | ### Removed 67 | 68 | - Python 2.X support. 69 | 70 | [1.4.1]: https://github.com/AfterShip/aftership-sdk-python/compare/1.4.0...1.4.1 71 | [1.4.0]: https://github.com/AfterShip/aftership-sdk-python/compare/1.3.0...1.4.0 72 | [1.3.0]: https://github.com/AfterShip/aftership-sdk-python/compare/1.2.1...1.3.0 73 | [1.2.1]: https://github.com/AfterShip/aftership-sdk-python/compare/1.2.0...1.2.1 74 | [1.2.0]: https://github.com/AfterShip/aftership-sdk-python/compare/1.1.0...1.2.0 75 | [1.1.0]: https://github.com/AfterShip/aftership-sdk-python/compare/1.0.post2...1.1.0 76 | [1.0.post2]: https://github.com/AfterShip/aftership-sdk-python/compare/1.0...1.0.post2 77 | [1.0.post1]: https://github.com/AfterShip/aftership-sdk-python/compare/1.0.post1...1.0 78 | [1.0]: https://github.com/AfterShip/aftership-sdk-python/releases/tag/1.0 79 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 AFTERSHIP LTD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: docs clean build 2 | 3 | install: 4 | poetry install 5 | 6 | test: 7 | poetry run py.test --cov=aftership 8 | 9 | record: 10 | poetry run py.test --vcr-record=new_episodes 11 | 12 | lint: 13 | poetry run flake8 aftership 14 | 15 | docs: 16 | cd docs && make html 17 | @echo "\033[95m\n\nBuild successful! View the docs homepage at docs/_build/html/index.html.\n\033[0m" 18 | 19 | build: 20 | poetry build 21 | 22 | clean: 23 | -rm -r docs/_build 24 | -rm -r build dist aftership.egg-info 25 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | Deprecation notice: New Version Available 3 | ==================== 4 | 5 | This version of the SDK has been deprecated and replaced with the newly reconstructed SDK. 6 | 7 | For the latest API features and improved integration, please visit our updated repository at https://github.com/AfterShip/tracking-sdk-python and follow the provided instructions. 8 | 9 | ==================== 10 | aftership-sdk-python 11 | ==================== 12 | 13 | .. image:: https://github.com/aftership/aftership-sdk-python/actions/workflows/test.yml/badge.svg?branch=master 14 | :target: https://github.com/AfterShip/aftership-sdk-python/actions/workflows/test.yml?query=branch%3Amaster 15 | 16 | .. image:: https://coveralls.io/repos/github/AfterShip/aftership-sdk-python/badge.svg?branch=master 17 | :target: https://coveralls.io/github/AfterShip/aftership-sdk-python?branch=master 18 | 19 | 20 | aftership-sdk-python is Python SDK (module) for `AfterShip API `_. 21 | Module provides clean way to access API endpoints. 22 | 23 | IMPORTANT NOTE 24 | -------------- 25 | 26 | Current version of aftership-sdk-python `>=0.3` not **compatible** with 27 | previous version of sdk `<=0.2`. 28 | 29 | Also, version since 1.0 is **not** support Python 2.X anymore. If you want 30 | to use this SDK under Python 2.X, please use versions `<1.0`. 31 | 32 | 33 | Supported Python Versions 34 | ========================= 35 | 36 | - 3.6 37 | - 3.7 38 | - 3.8 39 | - 3.9 40 | - 3.10 41 | - pypy3 42 | 43 | Installation 44 | ------------ 45 | 46 | Via pip 47 | ======= 48 | 49 | Use Virtual Environment 50 | ======================= 51 | We recommend using a `virtualenv `_ or `poem `_ 52 | to use this SDK. 53 | 54 | .. code-block:: bash 55 | 56 | $ pip install aftership 57 | 58 | Via source code 59 | =============== 60 | 61 | Download the code archive, without unzip it, go to the 62 | source root directory, then run: 63 | 64 | .. code-block:: bash 65 | 66 | $ pip install aftership-sdk-python.zip 67 | 68 | Usage 69 | ----- 70 | 71 | You need a valid API key to use this SDK. If you don't have one, please visit https://www.aftership.com/apps/api. 72 | 73 | Quick Start 74 | =========== 75 | 76 | The following code gets list of supported couriers 77 | 78 | .. code-block:: python 79 | 80 | import aftership 81 | aftership.api_key = 'YOUR_API_KEY_FROM_AFTERSHIP' 82 | couriers = aftership.courier.list_couriers() 83 | 84 | You can also set API key via setting :code:`AFTERSHIP_API_KEY` environment varaible. 85 | 86 | .. code-block:: bash 87 | 88 | export AFTERSHIP_API_KEY=THIS_IS_MY_API_KEY 89 | 90 | .. code-block:: python 91 | 92 | import aftership 93 | tracking = aftership.get_tracking(tracking_id='your_tracking_id') 94 | 95 | The functions of the SDK will return `data` field value if the API endpoints 96 | return response with HTTP status :code:`2XX`, otherwise will throw an 97 | exception. 98 | 99 | Exceptions 100 | ========== 101 | 102 | 103 | Exceptions are mapped from https://docs.aftership.com/api/4/errors, 104 | and this table is the exception attributes mapping. 105 | 106 | +------------------+----------------------+ 107 | | API error | AfterShipError | 108 | +==================+======================+ 109 | | http status code | :code:`http_status` | 110 | +------------------+----------------------+ 111 | | :code:`meta.code`| :code:`code` | 112 | +------------------+----------------------+ 113 | | :code:`meta.type`| :code:`message` | 114 | +------------------+----------------------+ 115 | 116 | 117 | Keyword arguments 118 | ================= 119 | 120 | Most of SDK functions only accept keyword arguments. 121 | 122 | 123 | Examples 124 | ======== 125 | 126 | Goto `examples `_ to see more examples. 127 | -------------------------------------------------------------------------------- /aftership/__init__.py: -------------------------------------------------------------------------------- 1 | from . import courier, exception, tracking, notification, estimated_delivery_date # noqa 2 | 3 | 4 | __version__ = '1.3.0' 5 | 6 | api_key = None 7 | -------------------------------------------------------------------------------- /aftership/const.py: -------------------------------------------------------------------------------- 1 | API_KEY_FILED_NAME = 'aftership-api-key' 2 | 3 | API_VERSION = "v4" 4 | API_ENDPOINT = "https://api.aftership.com/v4/" 5 | -------------------------------------------------------------------------------- /aftership/courier.py: -------------------------------------------------------------------------------- 1 | from .request import make_request 2 | from .response import process_response 3 | 4 | __all__ = ['list_couriers', 'list_all_couriers', 'detect_courier'] 5 | 6 | 7 | def list_couriers(**kwargs): 8 | """Return a list of couriers activated at your AfterShip account. 9 | """ 10 | response = make_request('GET', 'couriers', **kwargs) 11 | return process_response(response) 12 | 13 | 14 | def list_all_couriers(**kwargs): 15 | """Return a list of all couriers. 16 | """ 17 | response = make_request('GET', 'couriers/all', **kwargs) 18 | return process_response(response) 19 | 20 | 21 | def detect_courier(tracking, **kwargs): 22 | """Return a list of matched couriers based on tracking number format and 23 | selected couriers or a list of couriers. 24 | """ 25 | response = make_request('POST', 'couriers/detect', json=dict(tracking=tracking), **kwargs) 26 | return process_response(response) 27 | -------------------------------------------------------------------------------- /aftership/estimated_delivery_date.py: -------------------------------------------------------------------------------- 1 | from .request import make_request 2 | from .response import process_response 3 | 4 | __all__ = ['batch_predict_estimated_delivery_date'] 5 | 6 | 7 | def batch_predict_estimated_delivery_date(estimated_delivery_dates, **kwargs): 8 | """Batch predict the estimated delivery dates 9 | """ 10 | response = make_request('POST', 'estimated-delivery-date/predict-batch', 11 | json=dict(estimated_delivery_dates=estimated_delivery_dates), **kwargs) 12 | return process_response(response) 13 | -------------------------------------------------------------------------------- /aftership/exception.py: -------------------------------------------------------------------------------- 1 | class AfterShipError(Exception): 2 | def __init__(self, message=None, code=None, 3 | http_status=None, response=None, 4 | ): 5 | super(AfterShipError, self).__init__() 6 | self.message = message 7 | self.code = code 8 | self.http_status = http_status 9 | self.response = response 10 | 11 | def __str__(self): 12 | return '{}: {}'.format(self.__class__.__name__, self.message) 13 | 14 | 15 | class BadRequest(AfterShipError): 16 | pass 17 | 18 | 19 | class Unauthorized(AfterShipError): 20 | pass 21 | 22 | 23 | class Forbidden(AfterShipError): 24 | pass 25 | 26 | 27 | class NotFound(AfterShipError): 28 | pass 29 | 30 | 31 | class TooManyRequests(AfterShipError): 32 | pass 33 | 34 | 35 | class InternalError(AfterShipError): 36 | pass 37 | 38 | 39 | class UnexpectedError(AfterShipError): 40 | pass 41 | -------------------------------------------------------------------------------- /aftership/notification.py: -------------------------------------------------------------------------------- 1 | from .request import make_request 2 | from .response import process_response 3 | from .util import _build_tracking_url 4 | 5 | 6 | def list_notifications(*, tracking_id=None, slug=None, tracking_number=None, **kwargs): 7 | """ Get contact information for the users to notify when the tracking changes. 8 | Please note that only customer receivers will be returned. Any `email`, `sms` 9 | or `webhook` that belongs to the Store will not be returned. 10 | """ 11 | url = 'notifications/{}'.format(_build_tracking_url(tracking_id, slug, tracking_number)) 12 | response = make_request('GET', url, **kwargs) 13 | return process_response(response) 14 | 15 | 16 | def add_notification(*, notification, tracking_id=None, slug=None, tracking_number=None, **kwargs): 17 | """Add notification receivers to a tracking number. 18 | """ 19 | url = 'notifications/{}/add'.format(_build_tracking_url(tracking_id, slug, tracking_number)) 20 | response = make_request('POST', url, json=dict(notification=notification), **kwargs) 21 | return process_response(response) 22 | 23 | 24 | def remove_notification(*, notification, tracking_id=None, slug=None, tracking_number=None, **kwargs): 25 | """Remove notification receivers from a tracking number. 26 | """ 27 | url = 'notifications/{}/remove'.format(_build_tracking_url(tracking_id, slug, tracking_number)) 28 | response = make_request('POST', url, json=dict(notification=notification), **kwargs) 29 | return process_response(response) 30 | -------------------------------------------------------------------------------- /aftership/request.py: -------------------------------------------------------------------------------- 1 | from urllib.parse import urljoin 2 | 3 | import requests 4 | 5 | from .const import API_KEY_FILED_NAME, API_ENDPOINT 6 | from .util import get_api_key 7 | 8 | 9 | def build_request_url(path): 10 | return urljoin(API_ENDPOINT, path) 11 | 12 | 13 | def make_request(method, path, **kwargs): 14 | url = build_request_url(path) 15 | 16 | headers = kwargs.pop('headers', dict()) 17 | if headers.get(API_KEY_FILED_NAME) is None: 18 | headers[API_KEY_FILED_NAME] = get_api_key() 19 | kwargs['headers'] = headers 20 | return requests.request(method, url, **kwargs) 21 | -------------------------------------------------------------------------------- /aftership/response.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .exception import BadRequest, Forbidden, NotFound, Unauthorized, TooManyRequests, InternalError, UnexpectedError 4 | 5 | error_mapping = { 6 | 'BadRequest': BadRequest, 7 | 'Unauthorized': Unauthorized, 8 | 'Forbidden': Forbidden, 9 | 'NotFound': NotFound, 10 | 'TooManyRequests': TooManyRequests, 11 | 'InternalError': InternalError, 12 | } 13 | 14 | 15 | def process_response(response): 16 | try: 17 | json_content = response.json() 18 | except json.JSONDecodeError: 19 | raise InternalError 20 | 21 | if response.status_code // 100 == 2: 22 | return json_content['data'] 23 | 24 | error_type = json_content['meta']['type'] 25 | 26 | if error_type in error_mapping: 27 | error_cls = error_mapping[error_type] 28 | else: 29 | error_cls = UnexpectedError 30 | 31 | raise error_cls(message=json_content['meta']['message'], 32 | code=json_content['meta']['code'], 33 | http_status=response.status_code, 34 | response=response, 35 | ) 36 | -------------------------------------------------------------------------------- /aftership/tracking.py: -------------------------------------------------------------------------------- 1 | from .request import make_request 2 | from .response import process_response 3 | from .util import _build_tracking_url 4 | 5 | 6 | def create_tracking(tracking, **kwargs): 7 | """Create a tracking. 8 | """ 9 | response = make_request('POST', 'trackings', json=dict(tracking=tracking), **kwargs) 10 | return process_response(response) 11 | 12 | 13 | def get_tracking(*, tracking_id=None, slug=None, tracking_number=None, 14 | **kwargs): 15 | """Create a tracking. 16 | """ 17 | optional_keys = ('tracking_postal_code', 'tracking_ship_date', 'tracking_account_number', 'tracking_key', 18 | 'tracking_origin_country', 'tracking_destination_country', 'tracking_state', 19 | 'fields', 'lang') 20 | params = {key: kwargs.pop(key) for key in optional_keys if key in kwargs} 21 | url = 'trackings/{}'.format(_build_tracking_url(tracking_id, slug, tracking_number)) 22 | response = make_request('GET', url, params=params, **kwargs) 23 | return process_response(response) 24 | 25 | 26 | def update_tracking(*, tracking, tracking_id=None, slug=None, tracking_number=None, **kwargs): 27 | """Update a tracking. 28 | """ 29 | url = 'trackings/{}'.format(_build_tracking_url(tracking_id, slug, tracking_number)) 30 | response = make_request('PUT', url, json=dict(tracking=tracking), **kwargs) 31 | return process_response(response) 32 | 33 | 34 | def retrack(*, tracking_id=None, slug=None, tracking_number=None, **kwargs): 35 | """Retrack an expired tracking. Max 3 times per tracking. 36 | """ 37 | url = 'trackings/{}/retrack'.format(_build_tracking_url(tracking_id, slug, tracking_number)) 38 | response = make_request('POST', url, **kwargs) 39 | return process_response(response) 40 | 41 | 42 | def get_last_checkpoint(*, tracking_id=None, slug=None, tracking_number=None, **kwargs): 43 | """Return the tracking information of the last checkpoint of a single tracking. 44 | """ 45 | url = 'last_checkpoint/{}'.format(_build_tracking_url(tracking_id, slug, tracking_number)) 46 | response = make_request('GET', url, **kwargs) 47 | return process_response(response) 48 | 49 | 50 | def delete_tracking(*, tracking_id=None, slug=None, tracking_number=None, **kwargs): 51 | """Delete a tracking. 52 | """ 53 | url = 'trackings/{}'.format(_build_tracking_url(tracking_id, slug, tracking_number)) 54 | response = make_request('DELETE', url, **kwargs) 55 | return process_response(response) 56 | 57 | 58 | def list_trackings(**kwargs): 59 | """Get tracking results of multiple trackings. 60 | """ 61 | optional_keys = ( 62 | 'page', 63 | 'limit', 64 | 'keyword', 65 | 'tracking_numbers', 66 | 'slug', 67 | 'delivery_time', 68 | 'origin', 69 | 'destination', 70 | 'tag', 71 | 'created_at_min', 72 | 'created_at_max', 73 | 'updated_at_min', 74 | 'updated_at_max', 75 | 'fields', 76 | 'lang', 77 | 'last_updated_at', 78 | 'return_to_sender', 79 | 'courier_destination_country_iso3', 80 | ) 81 | 82 | params = {key: kwargs.pop(key) for key in optional_keys if key in kwargs} 83 | 84 | response = make_request('GET', 'trackings', params=params, **kwargs) 85 | return process_response(response) 86 | -------------------------------------------------------------------------------- /aftership/util.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | import aftership 5 | 6 | logger = logging.getLogger("aftership") 7 | 8 | 9 | def _build_tracking_url(tracking_id, slug, tracking_number): 10 | if tracking_id and (slug or tracking_number): 11 | raise ValueError('Cannot specify tracking number and tracking id at the same time') 12 | elif tracking_id: 13 | url = '{}'.format(tracking_id) 14 | elif slug and tracking_number: 15 | url = '{}/{}'.format(slug, tracking_number) 16 | else: 17 | raise ValueError('You must specify the tracking number of tracking id') 18 | return url 19 | 20 | 21 | def get_api_key(): 22 | """Get AfterShip API key""" 23 | if aftership.api_key is not None: 24 | return aftership.api_key 25 | return os.getenv('AFTERSHIP_API_KEY') 26 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, os.path.abspath('.')) 16 | 17 | import os 18 | import sys 19 | sys.path.insert(0, os.path.abspath('..')) 20 | sys.path.insert(0, os.path.abspath('_themes')) 21 | 22 | import aftership 23 | 24 | # -- Project information ----------------------------------------------------- 25 | 26 | project = 'aftership-python-sdk' 27 | copyright = '2020, aftership.com' 28 | author = 'support@aftership.com' 29 | 30 | # The full version, including alpha/beta/rc tags 31 | version = aftership.__version__ 32 | release = aftership.__version__ 33 | 34 | 35 | # -- General configuration --------------------------------------------------- 36 | 37 | # Add any Sphinx extension module names here, as strings. They can be 38 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 39 | # ones. 40 | extensions = [ 41 | 'sphinx.ext.autodoc', 42 | 'sphinx.ext.doctest', 43 | 'sphinx.ext.intersphinx', 44 | 'sphinx.ext.todo', 45 | 'sphinx.ext.viewcode', 46 | ] 47 | 48 | # Add any paths that contain templates here, relative to this directory. 49 | templates_path = ['_templates'] 50 | 51 | # The language for content autogenerated by Sphinx. Refer to documentation 52 | # for a list of supported languages. 53 | # 54 | # This is also used if you do content translation via gettext catalogs. 55 | # Usually you set "language" from the command line for these cases. 56 | language = 'en' 57 | 58 | # List of patterns, relative to source directory, that match files and 59 | # directories to ignore when looking for source files. 60 | # This pattern also affects html_static_path and html_extra_path. 61 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 62 | 63 | 64 | # -- Options for HTML output ------------------------------------------------- 65 | 66 | # The theme to use for HTML and HTML Help pages. See the documentation for 67 | # a list of builtin themes. 68 | # 69 | html_theme = 'alabaster' 70 | 71 | # Add any paths that contain custom static files (such as style sheets) here, 72 | # relative to this directory. They are copied after the builtin static files, 73 | # so a file named "default.css" will overwrite the builtin "default.css". 74 | html_static_path = ['_static'] 75 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. aftership-python-sdk documentation master file, created by 2 | sphinx-quickstart on Mon Feb 17 17:46:44 2020. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to aftership-python-sdk's documentation! 7 | ================================================ 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /examples/courier_example.py: -------------------------------------------------------------------------------- 1 | import aftership 2 | 3 | aftership.api_key = 'PUT_YOUR_AFTERSHIP_KEY_HERE' 4 | 5 | 6 | def get_enabled_courier_names(): 7 | result = aftership.courier.list_couriers() 8 | courier_list = [courier['name'] for courier in result['couriers']] 9 | return courier_list 10 | 11 | 12 | def get_supported_courier_names(): 13 | result = aftership.courier.list_all_couriers() 14 | courier_list = [courier['name'] for courier in result['couriers']] 15 | return courier_list 16 | 17 | 18 | if __name__ == '__main__': 19 | enabled_couriers = get_enabled_courier_names() 20 | print(enabled_couriers) 21 | -------------------------------------------------------------------------------- /examples/estimated_delivery_date_example.py: -------------------------------------------------------------------------------- 1 | import aftership 2 | 3 | aftership.api_key = 'PUT_YOUR_AFTERSHIP_KEY_HERE' 4 | 5 | 6 | def batch_predict_estimated_delivery_date(): 7 | result = aftership.estimated_delivery_date.batch_predict_estimated_delivery_date( 8 | [ 9 | { 10 | "slug": "fedex", 11 | "service_type_name": "FEDEX HOME DELIVERY", 12 | "origin_address": { 13 | "country": "USA", 14 | "state": "WA", 15 | "postal_code": "98108", 16 | "raw_location": "Seattle, Washington, 98108, USA, United States" 17 | }, 18 | "destination_address": { 19 | "country": "USA", 20 | "state": "CA", 21 | "postal_code": "92019", 22 | "raw_location": "El Cajon, California, 92019, USA, United States" 23 | }, 24 | "weight": { 25 | "unit": "kg", 26 | "value": 8 27 | }, 28 | "estimated_pickup": { 29 | "order_time": "2021-07-01 15:04:05", 30 | "order_cutoff_time": "20:00:00", 31 | "business_days": [ 32 | 1, 33 | 2, 34 | 3, 35 | 4, 36 | 5, 37 | 6, 38 | 7 39 | ], 40 | "order_processing_time": { 41 | "unit": "day", 42 | "value": 0 43 | } 44 | } 45 | } 46 | ] 47 | ) 48 | return result['estimated_delivery_dates'] 49 | 50 | if __name__ == '__main__': 51 | list = batch_predict_estimated_delivery_date() 52 | print(list) -------------------------------------------------------------------------------- /examples/notification_example.py: -------------------------------------------------------------------------------- 1 | import aftership 2 | 3 | 4 | # aftership.api_key = 'PUT_YOUR_AFTERSHIP_KEY_HERE' 5 | 6 | 7 | def add_notification(tracking_id, emails=None, smses=None, webhook=None): 8 | update_params = {} 9 | if emails: 10 | update_params['emails'] = emails 11 | if smses: 12 | update_params['smses'] = smses 13 | if webhook: 14 | update_params['webhook'] = webhook 15 | 16 | if not update_params: 17 | raise ValueError('You must specify one of emails, smses or webhook') 18 | 19 | aftership.notification.add_notification(tracking_id=tracking_id, notification=update_params) 20 | 21 | 22 | def list_notifications(tracking_id): 23 | notification = aftership.notification.list_notifications(tracking_id=tracking_id) 24 | return notification 25 | 26 | 27 | def delete_all_notification(tracking_id): 28 | result = list_notifications(tracking_id) 29 | notification = result['notification'] 30 | aftership.notification.remove_notification(tracking_id=tracking_id, notification=notification) 31 | 32 | 33 | def create_tracking(slug, tracking_number): 34 | """Create tracking, return tracking ID 35 | """ 36 | tracking = {'slug': slug, 'tracking_number': tracking_number} 37 | result = aftership.tracking.create_tracking(tracking=tracking, timeout=10) 38 | return result['tracking']['id'] 39 | 40 | 41 | def delete_tracking(tracking_id): 42 | try: 43 | aftership.tracking.delete_tracking(tracking_id=tracking_id) 44 | except aftership.exception.NotFound: 45 | return False 46 | return True 47 | 48 | 49 | if __name__ == '__main__': 50 | delete_tracking('jmclbpqav9syfk72s8a0k019') 51 | tid = create_tracking('china-post', '40419890604404') 52 | add_notification(tid, 'support@aftership.com') 53 | delete_all_notification(tid) 54 | notifications = list_notifications(tid) 55 | delete_tracking(tid) 56 | -------------------------------------------------------------------------------- /examples/tracking_example.py: -------------------------------------------------------------------------------- 1 | import aftership 2 | 3 | 4 | # aftership.api_key = 'PUT_YOUR_AFTERSHIP_KEY_HERE' 5 | 6 | 7 | def create_tracking(slug, tracking_number): 8 | """Create tracking, return tracking ID 9 | """ 10 | tracking = {'slug': slug, 'tracking_number': tracking_number} 11 | result = aftership.tracking.create_tracking(tracking=tracking, timeout=10) 12 | return result['tracking']['id'] 13 | 14 | 15 | def update_tracking(tracking_id, **values): 16 | aftership.tracking.update_tracking(tracking_id=tracking_id, tracking=values) 17 | return True 18 | 19 | 20 | def get_tracking(*, tracking_id=None, slug=None, tracking_number=None, 21 | fields=None): 22 | """Get tracking by tracking_id or slug + tracking_number 23 | """ 24 | try: 25 | result = aftership.tracking.get_tracking(tracking_id=tracking_id, 26 | slug=slug, 27 | tracking_number=tracking_number, 28 | fields=','.join(fields)) 29 | except aftership.exception.NotFound: 30 | return None 31 | 32 | return result['tracking'] 33 | 34 | 35 | def delete_tracking(tracking_id): 36 | try: 37 | aftership.tracking.delete_tracking(tracking_id=tracking_id) 38 | except aftership.exception.NotFound: 39 | return False 40 | return True 41 | 42 | 43 | if __name__ == '__main__': 44 | _tracking_id = create_tracking('usps', 'TEST12345678') 45 | print(f'tracking_id: {_tracking_id}') 46 | 47 | update_tracking(_tracking_id, title='new title') 48 | 49 | # Get tracking by tracking_id 50 | _tracking = get_tracking(tracking_id=_tracking_id, fields=['title', 'checkpoints']) 51 | print('Get tracking by tracking_id:', _tracking) 52 | 53 | # Get tracking by slug and tracking_number 54 | _tracking = get_tracking(slug='usps', tracking_number='HA19260817', 55 | fields=['title', 'checkpoints']) 56 | print('Get tracking by slug and tracking_number:', _tracking) 57 | 58 | is_deleted = delete_tracking(_tracking_id) 59 | print('Delete tracking result:', is_deleted) 60 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "atomicwrites" 3 | version = "1.4.0" 4 | description = "Atomic file writes." 5 | category = "dev" 6 | optional = false 7 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 8 | 9 | [[package]] 10 | name = "attrs" 11 | version = "20.3.0" 12 | description = "Classes Without Boilerplate" 13 | category = "dev" 14 | optional = false 15 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 16 | 17 | [package.extras] 18 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] 19 | docs = ["furo", "sphinx", "zope.interface"] 20 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] 21 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] 22 | 23 | [[package]] 24 | name = "certifi" 25 | version = "2020.12.5" 26 | description = "Python package for providing Mozilla's CA Bundle." 27 | category = "main" 28 | optional = false 29 | python-versions = "*" 30 | 31 | [[package]] 32 | name = "chardet" 33 | version = "4.0.0" 34 | description = "Universal encoding detector for Python 2 and 3" 35 | category = "main" 36 | optional = false 37 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 38 | 39 | [[package]] 40 | name = "colorama" 41 | version = "0.4.4" 42 | description = "Cross-platform colored terminal text." 43 | category = "dev" 44 | optional = false 45 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 46 | 47 | [[package]] 48 | name = "coverage" 49 | version = "5.5" 50 | description = "Code coverage measurement for Python" 51 | category = "dev" 52 | optional = false 53 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" 54 | 55 | [package.extras] 56 | toml = ["toml"] 57 | 58 | [[package]] 59 | name = "coveralls" 60 | version = "2.2.0" 61 | description = "Show coverage stats online via coveralls.io" 62 | category = "dev" 63 | optional = false 64 | python-versions = ">= 3.5" 65 | 66 | [package.dependencies] 67 | coverage = ">=4.1,<6.0" 68 | docopt = ">=0.6.1" 69 | requests = ">=1.0.0" 70 | 71 | [package.extras] 72 | yaml = ["PyYAML (>=3.10)"] 73 | 74 | [[package]] 75 | name = "docopt" 76 | version = "0.6.2" 77 | description = "Pythonic argument parser, that will make you smile" 78 | category = "dev" 79 | optional = false 80 | python-versions = "*" 81 | 82 | [[package]] 83 | name = "flake8" 84 | version = "3.9.2" 85 | description = "the modular source code checker: pep8 pyflakes and co" 86 | category = "dev" 87 | optional = false 88 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 89 | 90 | [package.dependencies] 91 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 92 | mccabe = ">=0.6.0,<0.7.0" 93 | pycodestyle = ">=2.7.0,<2.8.0" 94 | pyflakes = ">=2.3.0,<2.4.0" 95 | 96 | [[package]] 97 | name = "idna" 98 | version = "2.10" 99 | description = "Internationalized Domain Names in Applications (IDNA)" 100 | category = "main" 101 | optional = false 102 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 103 | 104 | [[package]] 105 | name = "importlib-metadata" 106 | version = "2.1.1" 107 | description = "Read metadata from Python packages" 108 | category = "dev" 109 | optional = false 110 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 111 | 112 | [package.dependencies] 113 | zipp = ">=0.5" 114 | 115 | [package.extras] 116 | docs = ["sphinx", "rst.linker"] 117 | testing = ["packaging", "pep517", "unittest2", "importlib-resources (>=1.3)"] 118 | 119 | [[package]] 120 | name = "iniconfig" 121 | version = "1.1.1" 122 | description = "iniconfig: brain-dead simple config-ini parsing" 123 | category = "dev" 124 | optional = false 125 | python-versions = "*" 126 | 127 | [[package]] 128 | name = "mccabe" 129 | version = "0.6.1" 130 | description = "McCabe checker, plugin for flake8" 131 | category = "dev" 132 | optional = false 133 | python-versions = "*" 134 | 135 | [[package]] 136 | name = "multidict" 137 | version = "5.1.0" 138 | description = "multidict implementation" 139 | category = "dev" 140 | optional = false 141 | python-versions = ">=3.6" 142 | 143 | [[package]] 144 | name = "packaging" 145 | version = "20.9" 146 | description = "Core utilities for Python packages" 147 | category = "dev" 148 | optional = false 149 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 150 | 151 | [package.dependencies] 152 | pyparsing = ">=2.0.2" 153 | 154 | [[package]] 155 | name = "pluggy" 156 | version = "0.13.1" 157 | description = "plugin and hook calling mechanisms for python" 158 | category = "dev" 159 | optional = false 160 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 161 | 162 | [package.dependencies] 163 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 164 | 165 | [package.extras] 166 | dev = ["pre-commit", "tox"] 167 | 168 | [[package]] 169 | name = "py" 170 | version = "1.10.0" 171 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 172 | category = "dev" 173 | optional = false 174 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 175 | 176 | [[package]] 177 | name = "pycodestyle" 178 | version = "2.7.0" 179 | description = "Python style guide checker" 180 | category = "dev" 181 | optional = false 182 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 183 | 184 | [[package]] 185 | name = "pyflakes" 186 | version = "2.3.1" 187 | description = "passive checker of Python programs" 188 | category = "dev" 189 | optional = false 190 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 191 | 192 | [[package]] 193 | name = "pyparsing" 194 | version = "2.4.7" 195 | description = "Python parsing module" 196 | category = "dev" 197 | optional = false 198 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 199 | 200 | [[package]] 201 | name = "pytest" 202 | version = "6.2.5" 203 | description = "pytest: simple powerful testing with Python" 204 | category = "dev" 205 | optional = false 206 | python-versions = ">=3.6" 207 | 208 | [package.dependencies] 209 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 210 | attrs = ">=19.2.0" 211 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 212 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 213 | iniconfig = "*" 214 | packaging = "*" 215 | pluggy = ">=0.12,<2.0" 216 | py = ">=1.8.2" 217 | toml = "*" 218 | 219 | [package.extras] 220 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 221 | 222 | [[package]] 223 | name = "pytest-cov" 224 | version = "2.12.1" 225 | description = "Pytest plugin for measuring coverage." 226 | category = "dev" 227 | optional = false 228 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 229 | 230 | [package.dependencies] 231 | coverage = ">=5.2.1" 232 | pytest = ">=4.6" 233 | toml = "*" 234 | 235 | [package.extras] 236 | testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] 237 | 238 | [[package]] 239 | name = "pytest-vcr" 240 | version = "1.0.2" 241 | description = "Plugin for managing VCR.py cassettes" 242 | category = "dev" 243 | optional = false 244 | python-versions = "*" 245 | 246 | [package.dependencies] 247 | pytest = ">=3.6.0" 248 | vcrpy = "*" 249 | 250 | [[package]] 251 | name = "pyyaml" 252 | version = "5.3.1" 253 | description = "YAML parser and emitter for Python" 254 | category = "dev" 255 | optional = false 256 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 257 | 258 | [[package]] 259 | name = "requests" 260 | version = "2.25.1" 261 | description = "Python HTTP for Humans." 262 | category = "main" 263 | optional = false 264 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 265 | 266 | [package.dependencies] 267 | certifi = ">=2017.4.17" 268 | chardet = ">=3.0.2,<5" 269 | idna = ">=2.5,<3" 270 | urllib3 = ">=1.21.1,<1.27" 271 | 272 | [package.extras] 273 | security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] 274 | socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] 275 | 276 | [[package]] 277 | name = "six" 278 | version = "1.15.0" 279 | description = "Python 2 and 3 compatibility utilities" 280 | category = "dev" 281 | optional = false 282 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 283 | 284 | [[package]] 285 | name = "toml" 286 | version = "0.10.2" 287 | description = "Python Library for Tom's Obvious, Minimal Language" 288 | category = "dev" 289 | optional = false 290 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 291 | 292 | [[package]] 293 | name = "typing-extensions" 294 | version = "3.7.4.3" 295 | description = "Backported and Experimental Type Hints for Python 3.5+" 296 | category = "dev" 297 | optional = false 298 | python-versions = "*" 299 | 300 | [[package]] 301 | name = "urllib3" 302 | version = "1.26.4" 303 | description = "HTTP library with thread-safe connection pooling, file post, and more." 304 | category = "main" 305 | optional = false 306 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" 307 | 308 | [package.extras] 309 | secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] 310 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 311 | brotli = ["brotlipy (>=0.6.0)"] 312 | 313 | [[package]] 314 | name = "vcrpy" 315 | version = "4.1.1" 316 | description = "Automatically mock your HTTP interactions to simplify and speed up testing" 317 | category = "dev" 318 | optional = false 319 | python-versions = ">=3.5" 320 | 321 | [package.dependencies] 322 | PyYAML = "*" 323 | six = ">=1.5" 324 | wrapt = "*" 325 | yarl = {version = "*", markers = "python_version >= \"3.6\""} 326 | 327 | [[package]] 328 | name = "wrapt" 329 | version = "1.12.1" 330 | description = "Module for decorators, wrappers and monkey patching." 331 | category = "dev" 332 | optional = false 333 | python-versions = "*" 334 | 335 | [[package]] 336 | name = "yarl" 337 | version = "1.6.3" 338 | description = "Yet another URL library" 339 | category = "dev" 340 | optional = false 341 | python-versions = ">=3.6" 342 | 343 | [package.dependencies] 344 | idna = ">=2.0" 345 | multidict = ">=4.0" 346 | typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} 347 | 348 | [[package]] 349 | name = "zipp" 350 | version = "1.2.0" 351 | description = "Backport of pathlib-compatible object wrapper for zip files" 352 | category = "dev" 353 | optional = false 354 | python-versions = ">=2.7" 355 | 356 | [package.extras] 357 | docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] 358 | testing = ["pathlib2", "unittest2", "jaraco.itertools", "func-timeout"] 359 | 360 | [metadata] 361 | lock-version = "1.1" 362 | python-versions = "^3.6" 363 | content-hash = "d9063182842e4d5c1642f5474c6139016dc26d67e1de0430145a48dc8abd4a75" 364 | 365 | [metadata.files] 366 | atomicwrites = [ 367 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, 368 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, 369 | ] 370 | attrs = [ 371 | {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, 372 | {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, 373 | ] 374 | certifi = [ 375 | {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, 376 | {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, 377 | ] 378 | chardet = [ 379 | {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, 380 | {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, 381 | ] 382 | colorama = [ 383 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 384 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 385 | ] 386 | coverage = [ 387 | {file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"}, 388 | {file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"}, 389 | {file = "coverage-5.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669"}, 390 | {file = "coverage-5.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90"}, 391 | {file = "coverage-5.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c"}, 392 | {file = "coverage-5.5-cp27-cp27m-win32.whl", hash = "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a"}, 393 | {file = "coverage-5.5-cp27-cp27m-win_amd64.whl", hash = "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82"}, 394 | {file = "coverage-5.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905"}, 395 | {file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"}, 396 | {file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"}, 397 | {file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"}, 398 | {file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"}, 399 | {file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"}, 400 | {file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"}, 401 | {file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"}, 402 | {file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"}, 403 | {file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"}, 404 | {file = "coverage-5.5-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701"}, 405 | {file = "coverage-5.5-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793"}, 406 | {file = "coverage-5.5-cp35-cp35m-win32.whl", hash = "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e"}, 407 | {file = "coverage-5.5-cp35-cp35m-win_amd64.whl", hash = "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3"}, 408 | {file = "coverage-5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066"}, 409 | {file = "coverage-5.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a"}, 410 | {file = "coverage-5.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465"}, 411 | {file = "coverage-5.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb"}, 412 | {file = "coverage-5.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821"}, 413 | {file = "coverage-5.5-cp36-cp36m-win32.whl", hash = "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45"}, 414 | {file = "coverage-5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184"}, 415 | {file = "coverage-5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a"}, 416 | {file = "coverage-5.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53"}, 417 | {file = "coverage-5.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d"}, 418 | {file = "coverage-5.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638"}, 419 | {file = "coverage-5.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3"}, 420 | {file = "coverage-5.5-cp37-cp37m-win32.whl", hash = "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a"}, 421 | {file = "coverage-5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a"}, 422 | {file = "coverage-5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6"}, 423 | {file = "coverage-5.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2"}, 424 | {file = "coverage-5.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759"}, 425 | {file = "coverage-5.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873"}, 426 | {file = "coverage-5.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a"}, 427 | {file = "coverage-5.5-cp38-cp38-win32.whl", hash = "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6"}, 428 | {file = "coverage-5.5-cp38-cp38-win_amd64.whl", hash = "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502"}, 429 | {file = "coverage-5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b"}, 430 | {file = "coverage-5.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529"}, 431 | {file = "coverage-5.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b"}, 432 | {file = "coverage-5.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff"}, 433 | {file = "coverage-5.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b"}, 434 | {file = "coverage-5.5-cp39-cp39-win32.whl", hash = "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6"}, 435 | {file = "coverage-5.5-cp39-cp39-win_amd64.whl", hash = "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03"}, 436 | {file = "coverage-5.5-pp36-none-any.whl", hash = "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079"}, 437 | {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"}, 438 | {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, 439 | ] 440 | coveralls = [ 441 | {file = "coveralls-2.2.0-py2.py3-none-any.whl", hash = "sha256:2301a19500b06649d2ec4f2858f9c69638d7699a4c63027c5d53daba666147cc"}, 442 | {file = "coveralls-2.2.0.tar.gz", hash = "sha256:b990ba1f7bc4288e63340be0433698c1efe8217f78c689d254c2540af3d38617"}, 443 | ] 444 | docopt = [ 445 | {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, 446 | ] 447 | flake8 = [ 448 | {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, 449 | {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, 450 | ] 451 | idna = [ 452 | {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, 453 | {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, 454 | ] 455 | importlib-metadata = [ 456 | {file = "importlib_metadata-2.1.1-py2.py3-none-any.whl", hash = "sha256:c2d6341ff566f609e89a2acb2db190e5e1d23d5409d6cc8d2fe34d72443876d4"}, 457 | {file = "importlib_metadata-2.1.1.tar.gz", hash = "sha256:b8de9eff2b35fb037368f28a7df1df4e6436f578fa74423505b6c6a778d5b5dd"}, 458 | ] 459 | iniconfig = [ 460 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, 461 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, 462 | ] 463 | mccabe = [ 464 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, 465 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, 466 | ] 467 | multidict = [ 468 | {file = "multidict-5.1.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f"}, 469 | {file = "multidict-5.1.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:9dd6e9b1a913d096ac95d0399bd737e00f2af1e1594a787e00f7975778c8b2bf"}, 470 | {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281"}, 471 | {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab820665e67373de5802acae069a6a05567ae234ddb129f31d290fc3d1aa56d"}, 472 | {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:9436dc58c123f07b230383083855593550c4d301d2532045a17ccf6eca505f6d"}, 473 | {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:830f57206cc96ed0ccf68304141fec9481a096c4d2e2831f311bde1c404401da"}, 474 | {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:2e68965192c4ea61fff1b81c14ff712fc7dc15d2bd120602e4a3494ea6584224"}, 475 | {file = "multidict-5.1.0-cp36-cp36m-win32.whl", hash = "sha256:2f1a132f1c88724674271d636e6b7351477c27722f2ed789f719f9e3545a3d26"}, 476 | {file = "multidict-5.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:3a4f32116f8f72ecf2a29dabfb27b23ab7cdc0ba807e8459e59a93a9be9506f6"}, 477 | {file = "multidict-5.1.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:46c73e09ad374a6d876c599f2328161bcd95e280f84d2060cf57991dec5cfe76"}, 478 | {file = "multidict-5.1.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:018132dbd8688c7a69ad89c4a3f39ea2f9f33302ebe567a879da8f4ca73f0d0a"}, 479 | {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:4b186eb7d6ae7c06eb4392411189469e6a820da81447f46c0072a41c748ab73f"}, 480 | {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3a041b76d13706b7fff23b9fc83117c7b8fe8d5fe9e6be45eee72b9baa75f348"}, 481 | {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:051012ccee979b2b06be928a6150d237aec75dd6bf2d1eeeb190baf2b05abc93"}, 482 | {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:6a4d5ce640e37b0efcc8441caeea8f43a06addace2335bd11151bc02d2ee31f9"}, 483 | {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:5cf3443199b83ed9e955f511b5b241fd3ae004e3cb81c58ec10f4fe47c7dce37"}, 484 | {file = "multidict-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:f200755768dc19c6f4e2b672421e0ebb3dd54c38d5a4f262b872d8cfcc9e93b5"}, 485 | {file = "multidict-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:05c20b68e512166fddba59a918773ba002fdd77800cad9f55b59790030bab632"}, 486 | {file = "multidict-5.1.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:54fd1e83a184e19c598d5e70ba508196fd0bbdd676ce159feb412a4a6664f952"}, 487 | {file = "multidict-5.1.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:0e3c84e6c67eba89c2dbcee08504ba8644ab4284863452450520dad8f1e89b79"}, 488 | {file = "multidict-5.1.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:dc862056f76443a0db4509116c5cd480fe1b6a2d45512a653f9a855cc0517456"}, 489 | {file = "multidict-5.1.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:0e929169f9c090dae0646a011c8b058e5e5fb391466016b39d21745b48817fd7"}, 490 | {file = "multidict-5.1.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:d81eddcb12d608cc08081fa88d046c78afb1bf8107e6feab5d43503fea74a635"}, 491 | {file = "multidict-5.1.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:585fd452dd7782130d112f7ddf3473ffdd521414674c33876187e101b588738a"}, 492 | {file = "multidict-5.1.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:37e5438e1c78931df5d3c0c78ae049092877e5e9c02dd1ff5abb9cf27a5914ea"}, 493 | {file = "multidict-5.1.0-cp38-cp38-win32.whl", hash = "sha256:07b42215124aedecc6083f1ce6b7e5ec5b50047afa701f3442054373a6deb656"}, 494 | {file = "multidict-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:929006d3c2d923788ba153ad0de8ed2e5ed39fdbe8e7be21e2f22ed06c6783d3"}, 495 | {file = "multidict-5.1.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b797515be8743b771aa868f83563f789bbd4b236659ba52243b735d80b29ed93"}, 496 | {file = "multidict-5.1.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d5c65bdf4484872c4af3150aeebe101ba560dcfb34488d9a8ff8dbcd21079647"}, 497 | {file = "multidict-5.1.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b47a43177a5e65b771b80db71e7be76c0ba23cc8aa73eeeb089ed5219cdbe27d"}, 498 | {file = "multidict-5.1.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:806068d4f86cb06af37cd65821554f98240a19ce646d3cd24e1c33587f313eb8"}, 499 | {file = "multidict-5.1.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:46dd362c2f045095c920162e9307de5ffd0a1bfbba0a6e990b344366f55a30c1"}, 500 | {file = "multidict-5.1.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:ace010325c787c378afd7f7c1ac66b26313b3344628652eacd149bdd23c68841"}, 501 | {file = "multidict-5.1.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:ecc771ab628ea281517e24fd2c52e8f31c41e66652d07599ad8818abaad38cda"}, 502 | {file = "multidict-5.1.0-cp39-cp39-win32.whl", hash = "sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80"}, 503 | {file = "multidict-5.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7df80d07818b385f3129180369079bd6934cf70469f99daaebfac89dca288359"}, 504 | {file = "multidict-5.1.0.tar.gz", hash = "sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5"}, 505 | ] 506 | packaging = [ 507 | {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, 508 | {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, 509 | ] 510 | pluggy = [ 511 | {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, 512 | {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, 513 | ] 514 | py = [ 515 | {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, 516 | {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, 517 | ] 518 | pycodestyle = [ 519 | {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, 520 | {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, 521 | ] 522 | pyflakes = [ 523 | {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, 524 | {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, 525 | ] 526 | pyparsing = [ 527 | {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, 528 | {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, 529 | ] 530 | pytest = [ 531 | {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, 532 | {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, 533 | ] 534 | pytest-cov = [ 535 | {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"}, 536 | {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"}, 537 | ] 538 | pytest-vcr = [ 539 | {file = "pytest-vcr-1.0.2.tar.gz", hash = "sha256:23ee51b75abbcc43d926272773aae4f39f93aceb75ed56852d0bf618f92e1896"}, 540 | {file = "pytest_vcr-1.0.2-py2.py3-none-any.whl", hash = "sha256:2f316e0539399bea0296e8b8401145c62b6f85e9066af7e57b6151481b0d6d9c"}, 541 | ] 542 | pyyaml = [ 543 | {file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"}, 544 | {file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"}, 545 | {file = "PyYAML-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2"}, 546 | {file = "PyYAML-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c"}, 547 | {file = "PyYAML-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2"}, 548 | {file = "PyYAML-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648"}, 549 | {file = "PyYAML-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"}, 550 | {file = "PyYAML-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf"}, 551 | {file = "PyYAML-5.3.1-cp38-cp38-win32.whl", hash = "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97"}, 552 | {file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"}, 553 | {file = "PyYAML-5.3.1-cp39-cp39-win32.whl", hash = "sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a"}, 554 | {file = "PyYAML-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:6034f55dab5fea9e53f436aa68fa3ace2634918e8b5994d82f3621c04ff5ed2e"}, 555 | {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, 556 | ] 557 | requests = [ 558 | {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, 559 | {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, 560 | ] 561 | six = [ 562 | {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, 563 | {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, 564 | ] 565 | toml = [ 566 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 567 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 568 | ] 569 | typing-extensions = [ 570 | {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, 571 | {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, 572 | {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, 573 | ] 574 | urllib3 = [ 575 | {file = "urllib3-1.26.4-py2.py3-none-any.whl", hash = "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df"}, 576 | {file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"}, 577 | ] 578 | vcrpy = [ 579 | {file = "vcrpy-4.1.1-py2.py3-none-any.whl", hash = "sha256:12c3fcdae7b88ecf11fc0d3e6d77586549d4575a2ceee18e82eee75c1f626162"}, 580 | {file = "vcrpy-4.1.1.tar.gz", hash = "sha256:57095bf22fc0a2d99ee9674cdafebed0f3ba763018582450706f7d3a74fff599"}, 581 | ] 582 | wrapt = [ 583 | {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, 584 | ] 585 | yarl = [ 586 | {file = "yarl-1.6.3-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:0355a701b3998dcd832d0dc47cc5dedf3874f966ac7f870e0f3a6788d802d434"}, 587 | {file = "yarl-1.6.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:bafb450deef6861815ed579c7a6113a879a6ef58aed4c3a4be54400ae8871478"}, 588 | {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:547f7665ad50fa8563150ed079f8e805e63dd85def6674c97efd78eed6c224a6"}, 589 | {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:63f90b20ca654b3ecc7a8d62c03ffa46999595f0167d6450fa8383bab252987e"}, 590 | {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:97b5bdc450d63c3ba30a127d018b866ea94e65655efaf889ebeabc20f7d12406"}, 591 | {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:d8d07d102f17b68966e2de0e07bfd6e139c7c02ef06d3a0f8d2f0f055e13bb76"}, 592 | {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:15263c3b0b47968c1d90daa89f21fcc889bb4b1aac5555580d74565de6836366"}, 593 | {file = "yarl-1.6.3-cp36-cp36m-win32.whl", hash = "sha256:b5dfc9a40c198334f4f3f55880ecf910adebdcb2a0b9a9c23c9345faa9185721"}, 594 | {file = "yarl-1.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:b2e9a456c121e26d13c29251f8267541bd75e6a1ccf9e859179701c36a078643"}, 595 | {file = "yarl-1.6.3-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:ce3beb46a72d9f2190f9e1027886bfc513702d748047b548b05dab7dfb584d2e"}, 596 | {file = "yarl-1.6.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2ce4c621d21326a4a5500c25031e102af589edb50c09b321049e388b3934eec3"}, 597 | {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:d26608cf178efb8faa5ff0f2d2e77c208f471c5a3709e577a7b3fd0445703ac8"}, 598 | {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:4c5bcfc3ed226bf6419f7a33982fb4b8ec2e45785a0561eb99274ebbf09fdd6a"}, 599 | {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:4736eaee5626db8d9cda9eb5282028cc834e2aeb194e0d8b50217d707e98bb5c"}, 600 | {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:68dc568889b1c13f1e4745c96b931cc94fdd0defe92a72c2b8ce01091b22e35f"}, 601 | {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:7356644cbed76119d0b6bd32ffba704d30d747e0c217109d7979a7bc36c4d970"}, 602 | {file = "yarl-1.6.3-cp37-cp37m-win32.whl", hash = "sha256:00d7ad91b6583602eb9c1d085a2cf281ada267e9a197e8b7cae487dadbfa293e"}, 603 | {file = "yarl-1.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:69ee97c71fee1f63d04c945f56d5d726483c4762845400a6795a3b75d56b6c50"}, 604 | {file = "yarl-1.6.3-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:e46fba844f4895b36f4c398c5af062a9808d1f26b2999c58909517384d5deda2"}, 605 | {file = "yarl-1.6.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:31ede6e8c4329fb81c86706ba8f6bf661a924b53ba191b27aa5fcee5714d18ec"}, 606 | {file = "yarl-1.6.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71"}, 607 | {file = "yarl-1.6.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:72a660bdd24497e3e84f5519e57a9ee9220b6f3ac4d45056961bf22838ce20cc"}, 608 | {file = "yarl-1.6.3-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:324ba3d3c6fee56e2e0b0d09bf5c73824b9f08234339d2b788af65e60040c959"}, 609 | {file = "yarl-1.6.3-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:e6b5460dc5ad42ad2b36cca524491dfcaffbfd9c8df50508bddc354e787b8dc2"}, 610 | {file = "yarl-1.6.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:6d6283d8e0631b617edf0fd726353cb76630b83a089a40933043894e7f6721e2"}, 611 | {file = "yarl-1.6.3-cp38-cp38-win32.whl", hash = "sha256:9ede61b0854e267fd565e7527e2f2eb3ef8858b301319be0604177690e1a3896"}, 612 | {file = "yarl-1.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a"}, 613 | {file = "yarl-1.6.3-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:329412812ecfc94a57cd37c9d547579510a9e83c516bc069470db5f75684629e"}, 614 | {file = "yarl-1.6.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c49ff66d479d38ab863c50f7bb27dee97c6627c5fe60697de15529da9c3de724"}, 615 | {file = "yarl-1.6.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f040bcc6725c821a4c0665f3aa96a4d0805a7aaf2caf266d256b8ed71b9f041c"}, 616 | {file = "yarl-1.6.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:d5c32c82990e4ac4d8150fd7652b972216b204de4e83a122546dce571c1bdf25"}, 617 | {file = "yarl-1.6.3-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:d597767fcd2c3dc49d6eea360c458b65643d1e4dbed91361cf5e36e53c1f8c96"}, 618 | {file = "yarl-1.6.3-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:8aa3decd5e0e852dc68335abf5478a518b41bf2ab2f330fe44916399efedfae0"}, 619 | {file = "yarl-1.6.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:73494d5b71099ae8cb8754f1df131c11d433b387efab7b51849e7e1e851f07a4"}, 620 | {file = "yarl-1.6.3-cp39-cp39-win32.whl", hash = "sha256:5b883e458058f8d6099e4420f0cc2567989032b5f34b271c0827de9f1079a424"}, 621 | {file = "yarl-1.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:4953fb0b4fdb7e08b2f3b3be80a00d28c5c8a2056bb066169de00e6501b986b6"}, 622 | {file = "yarl-1.6.3.tar.gz", hash = "sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10"}, 623 | ] 624 | zipp = [ 625 | {file = "zipp-1.2.0-py2.py3-none-any.whl", hash = "sha256:e0d9e63797e483a30d27e09fffd308c59a700d365ec34e93cc100844168bf921"}, 626 | {file = "zipp-1.2.0.tar.gz", hash = "sha256:c70410551488251b0fee67b460fb9a536af8d6f9f008ad10ac51f615b6a521b1"}, 627 | ] 628 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "aftership" 3 | version = "1.4.1" 4 | description = "The python SDK of AfterShip API" 5 | authors = ["AfterShip "] 6 | license = "MIT" 7 | readme = "README.rst" 8 | homepage = "https://developers.aftership.com" 9 | repository = "https://github.com/aftership/aftership-sdk-python" 10 | documentation = "https://github.com/aftership/aftership-sdk-python" 11 | keywords = ["aftership", "api", "tracking", "shipping", "logistics"] 12 | 13 | classifiers = [ 14 | "Development Status :: 5 - Production/Stable", 15 | "Intended Audience :: Developers", 16 | "License :: OSI Approved :: MIT License", 17 | "Topic :: Software Development", 18 | "Programming Language :: Python :: 3.6", 19 | "Programming Language :: Python :: 3.7", 20 | "Programming Language :: Python :: 3.8", 21 | "Programming Language :: Python :: 3.9", 22 | "Programming Language :: Python :: 3.10", 23 | "Programming Language :: Python :: Implementation :: PyPy", 24 | ] 25 | 26 | packages = [ 27 | { include = "aftership" }, 28 | { include = "*.md" }, 29 | { include = "*.rst" }, 30 | { include = "LICENSE" }, 31 | ] 32 | 33 | [tool.poetry.dependencies] 34 | python = "^3.6" 35 | requests = "^2.0.0'" 36 | 37 | [tool.poetry.dev-dependencies] 38 | pytest = "^6.0.1" 39 | pytest-cov = "^2.10.1" 40 | pytest-vcr = "^1.0.2" 41 | flake8 = "^3.8.3" 42 | coveralls = "^2.1.2" 43 | 44 | [build-system] 45 | requires = ["poetry>=0.12"] 46 | build-backend = "poetry.masonry.api" 47 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal = 0 3 | 4 | [metadata] 5 | license_file = LICENSE 6 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AfterShip/aftership-sdk-python/738dbb47ddd9c5e2981e041396b7eaed96a3bfb1/tests/__init__.py -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.fixture(scope='session') 5 | def vcr_config(): 6 | return { 7 | 'cassette_library_dir': 'tests/fixtures/cassettes', 8 | 'serializer': 'yaml', 9 | 'filter_headers': [('aftership-api-key', 'YOUR_API_KEY_IS_HERE')], 10 | 'record_mode': 'none', 11 | 'match_on': ['uri', 'method', 'query', 'body'], 12 | } 13 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/CourierTestCase.test_detect_courier.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: '{"tracking": {"tracking_number": "1234567890"}}' 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | Content-Length: 12 | - '47' 13 | Content-Type: 14 | - application/json 15 | User-Agent: 16 | - python-requests/2.23.0 17 | aftership-api-key: 18 | - YOUR_API_KEY_IS_HERE 19 | method: POST 20 | uri: https://api.aftership.com/v4/couriers/detect 21 | response: 22 | body: 23 | string: !!binary | 24 | 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 76 | headers: 77 | Access-Control-Allow-Credentials: 78 | - 'true' 79 | Access-Control-Allow-Headers: 80 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key 81 | Access-Control-Allow-Methods: 82 | - GET,OPTIONS 83 | Access-Control-Allow-Origin: 84 | - '*' 85 | Cache-Control: 86 | - no-store, no-cache, must-revalidate, proxy-revalidate 87 | Connection: 88 | - keep-alive 89 | Content-Encoding: 90 | - gzip 91 | Content-Type: 92 | - application/json; charset=utf-8 93 | Date: 94 | - Tue, 25 Feb 2020 09:38:00 GMT 95 | Expires: 96 | - '0' 97 | Pragma: 98 | - no-cache 99 | Server: 100 | - nginx 101 | Surrogate-Control: 102 | - no-store 103 | Vary: 104 | - X-HTTP-Method-Override, Accept-Encoding 105 | X-RateLimit-Limit: 106 | - '10000' 107 | X-RateLimit-Remaining: 108 | - '9991' 109 | X-RateLimit-Reset: 110 | - '1582623526' 111 | X-Response-Time: 112 | - 37.438ms 113 | p3p: 114 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 115 | transfer-encoding: 116 | - chunked 117 | status: 118 | code: 200 119 | message: OK 120 | - request: 121 | body: '{"tracking": {"tracking_number": "1234567890"}}' 122 | headers: 123 | Accept: 124 | - '*/*' 125 | Accept-Encoding: 126 | - gzip, deflate 127 | Connection: 128 | - keep-alive 129 | Content-Length: 130 | - '47' 131 | Content-Type: 132 | - application/json 133 | User-Agent: 134 | - python-requests/2.23.0 135 | aftership-api-key: 136 | - YOUR_API_KEY_IS_HERE 137 | method: POST 138 | uri: https://api.aftership.com/v4/couriers/detect 139 | response: 140 | body: 141 | string: !!binary | 142 | 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 194 | headers: 195 | Access-Control-Allow-Credentials: 196 | - 'true' 197 | Access-Control-Allow-Headers: 198 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key 199 | Access-Control-Allow-Methods: 200 | - GET,OPTIONS 201 | Access-Control-Allow-Origin: 202 | - '*' 203 | Cache-Control: 204 | - no-store, no-cache, must-revalidate, proxy-revalidate 205 | Connection: 206 | - keep-alive 207 | Content-Encoding: 208 | - gzip 209 | Content-Type: 210 | - application/json; charset=utf-8 211 | Date: 212 | - Tue, 25 Feb 2020 09:40:35 GMT 213 | Expires: 214 | - '0' 215 | Pragma: 216 | - no-cache 217 | Server: 218 | - nginx 219 | Surrogate-Control: 220 | - no-store 221 | Vary: 222 | - X-HTTP-Method-Override, Accept-Encoding 223 | X-RateLimit-Limit: 224 | - '10000' 225 | X-RateLimit-Remaining: 226 | - '9997' 227 | X-RateLimit-Reset: 228 | - '1582623688' 229 | X-Response-Time: 230 | - 38.063ms 231 | p3p: 232 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 233 | transfer-encoding: 234 | - chunked 235 | status: 236 | code: 200 237 | message: OK 238 | version: 1 239 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/EstimatedDeliveryDateTestCase.test_batch_predict_estimated_delivery_date.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: '{"estimated_delivery_dates": [{"slug":"fedex","service_type_name":"FEDEX HOME DELIVERY","origin_address":{"country":"USA","state":"WA","postal_code":"98108","raw_location":"Seattle, Washington, 98108, USA, United States"},"destination_address":{"country":"USA","state":"CA","postal_code":"92019","raw_location":"El Cajon, California, 92019, USA, United States"},"weight":{"unit":"kg","value":11},"package_count":1,"pickup_time":"2021-07-01 15:00:00","estimated_pickup":{"order_processing_time":{},"pickup_time":""}}]}' 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | Content-Length: 12 | - '517' 13 | Content-Type: 14 | - application/json 15 | User-Agent: 16 | - python-requests/2.23.0 17 | aftership-api-key: 18 | - YOUR_API_KEY_IS_HERE 19 | method: POST 20 | uri: https://api.aftership.com/v4/estimated-delivery-date/predict-batch 21 | response: 22 | body: 23 | string: '{"meta":{"code":200},"data":{"estimated_delivery_dates":[{"slug":"fedex","service_type_name":"FEDEX HOME DELIVERY","origin_address":{"country":"USA","state":"WA","postal_code":"98108","raw_location":"Seattle, Washington, 98108, USA, United States","city":null},"destination_address":{"country":"USA","state":"CA","postal_code":"92019","raw_location":"El Cajon, California, 92019, USA, United States","city":null},"weight":{"unit":"kg","value":11},"package_count":1,"pickup_time":"2021-07-01 15:00:00","estimated_pickup":null,"estimated_delivery_date":"2021-07-05","estimated_delivery_date_min":"2021-07-04","estimated_delivery_date_max":"2021-07-05"}]}}' 24 | headers: 25 | Cache-Control: 26 | - no-store, no-cache, must-revalidate, proxy-revalidate 27 | Connection: 28 | - keep-alive 29 | Content-Length: 30 | - '653' 31 | Content-Type: 32 | - application/json; charset=utf-8 33 | Expires: 34 | - '0' 35 | Pragma: 36 | - no-cache 37 | Server: 38 | - nginx 39 | Surrogate-Control: 40 | - no-store 41 | Vary: 42 | - X-HTTP-Method-Override, Accept-Encoding 43 | X-RateLimit-Limit: 44 | - '10000' 45 | X-RateLimit-Remaining: 46 | - '9994' 47 | X-RateLimit-Reset: 48 | - '1582623688' 49 | X-Response-Time: 50 | - 256.222ms 51 | p3p: 52 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 53 | status: 54 | code: 200 55 | message: OK 56 | version: 1 -------------------------------------------------------------------------------- /tests/fixtures/cassettes/NotificationTestCase.test_add_notification.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: '{"notification": {"emails": ["jk.zhang@aftership.com"]}}' 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | Content-Length: 12 | - '56' 13 | Content-Type: 14 | - application/json 15 | User-Agent: 16 | - python-requests/2.23.0 17 | aftership-api-key: 18 | - YOUR_API_KEY_IS_HERE 19 | method: POST 20 | uri: https://api.aftership.com/v4/notifications/k5lh7dy7vvqeck71p5loe011/add 21 | response: 22 | body: 23 | string: '{"meta":{"code":201},"data":{"notification":{"android":[],"emails":["jk.zhang@aftership.com"],"ios":[],"smses":[]}}}' 24 | headers: 25 | Cache-Control: 26 | - no-store, no-cache, must-revalidate, proxy-revalidate 27 | Connection: 28 | - keep-alive 29 | Content-Length: 30 | - '116' 31 | Content-Type: 32 | - application/json; charset=utf-8 33 | Date: 34 | - Tue, 25 Feb 2020 09:40:39 GMT 35 | Expires: 36 | - '0' 37 | Pragma: 38 | - no-cache 39 | Server: 40 | - nginx 41 | Surrogate-Control: 42 | - no-store 43 | Vary: 44 | - X-HTTP-Method-Override, Accept-Encoding 45 | X-RateLimit-Limit: 46 | - '10000' 47 | X-RateLimit-Remaining: 48 | - '9994' 49 | X-RateLimit-Reset: 50 | - '1582623688' 51 | X-Response-Time: 52 | - 256.222ms 53 | p3p: 54 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 55 | status: 56 | code: 201 57 | message: Created 58 | version: 1 59 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/NotificationTestCase.test_list_notification.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | User-Agent: 12 | - python-requests/2.23.0 13 | aftership-api-key: 14 | - YOUR_API_KEY_IS_HERE 15 | method: GET 16 | uri: https://api.aftership.com/v4/notifications/k5lh7dy7vvqeck71p5loe011 17 | response: 18 | body: 19 | string: '{"meta":{"code":200},"data":{"notification":{"android":[],"emails":["jk.zhang@aftership.com"],"ios":[],"smses":[]}}}' 20 | headers: 21 | Cache-Control: 22 | - no-store, no-cache, must-revalidate, proxy-revalidate 23 | Connection: 24 | - keep-alive 25 | Content-Length: 26 | - '116' 27 | Content-Type: 28 | - application/json; charset=utf-8 29 | Date: 30 | - Tue, 25 Feb 2020 09:40:41 GMT 31 | Expires: 32 | - '0' 33 | Pragma: 34 | - no-cache 35 | Server: 36 | - nginx 37 | Surrogate-Control: 38 | - no-store 39 | Vary: 40 | - Accept-Encoding 41 | X-RateLimit-Limit: 42 | - '10000' 43 | X-RateLimit-Remaining: 44 | - '9993' 45 | X-RateLimit-Reset: 46 | - '1582623688' 47 | X-Response-Time: 48 | - 74.699ms 49 | p3p: 50 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 51 | status: 52 | code: 200 53 | message: OK 54 | version: 1 55 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/NotificationTestCase.test_remove_notification.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: '{"notification": {"emails": ["support@aftership.com"]}}' 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | Content-Length: 12 | - '55' 13 | Content-Type: 14 | - application/json 15 | User-Agent: 16 | - python-requests/2.23.0 17 | aftership-api-key: 18 | - YOUR_API_KEY_IS_HERE 19 | method: POST 20 | uri: https://api.aftership.com/v4/notifications/k5lh7dy7vvqeck71p5loe011/remove 21 | response: 22 | body: 23 | string: '{"meta":{"code":201},"data":{"notification":{"android":[],"emails":["jk.zhang@aftership.com"],"ios":[],"smses":[]}}}' 24 | headers: 25 | Cache-Control: 26 | - no-store, no-cache, must-revalidate, proxy-revalidate 27 | Connection: 28 | - keep-alive 29 | Content-Length: 30 | - '116' 31 | Content-Type: 32 | - application/json; charset=utf-8 33 | Date: 34 | - Tue, 25 Feb 2020 09:40:42 GMT 35 | Expires: 36 | - '0' 37 | Pragma: 38 | - no-cache 39 | Server: 40 | - nginx 41 | Surrogate-Control: 42 | - no-store 43 | Vary: 44 | - X-HTTP-Method-Override, Accept-Encoding 45 | X-RateLimit-Limit: 46 | - '10000' 47 | X-RateLimit-Remaining: 48 | - '9992' 49 | X-RateLimit-Reset: 50 | - '1582623688' 51 | X-Response-Time: 52 | - 357.226ms 53 | p3p: 54 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 55 | status: 56 | code: 201 57 | message: Created 58 | version: 1 59 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/TrackingTestCase.test_create_tracking.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: '{"tracking": {"slug": "4px", "tracking_number": "HH19260817"}}' 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | Content-Length: 12 | - '62' 13 | Content-Type: 14 | - application/json 15 | User-Agent: 16 | - python-requests/2.23.0 17 | aftership-api-key: 18 | - YOUR_API_KEY_IS_HERE 19 | method: POST 20 | uri: https://api.aftership.com/v4/trackings 21 | response: 22 | body: 23 | string: !!binary | 24 | H4sIAAAAAAAAA41Uy27bMBD8F16bALRcO62+IMceeisKgibX8lYUyfKR2Aj8711alixZBpqbOTPa 25 | 5ewO/cE6SJLVH0w5Dayu+Or8xLTssRSkatE25TdqVjPfcVjvD8c/67XS7UsVIfkTrzbsiakAMoEW 26 | MpGu4hV/5tVztf3J1/VmW29WXzivOSdh9vpzQiNjEp9WD3cVNnc7CKR+fV19r7b82+qF6Ggy2WBf 27 | /ZEOUiV8I7cpZKCT1cEVe79+k40ck+vEHsHoyGqbjRlACMLKDgZQg6Ei4SQSTsGY0MqEzgrlsk3E 28 | Y3TrsZLLAanQ/3TQSTSxvxIcPagyg6HjIEJ3VViXxhu4oKl+sTM/Cy/T4QZig487xwP6DmwivWpl 29 | A71oyaJqsxdlOQtunMxDNp38EnwHbA7LLj0sssUbh42lWezGKcQuwnUOkaarqDiTHkskZFn5D7C6 30 | ZJjovJtBgvPVCIsOYiS/sy8SJgP3Ubokja5wHQy/JrVDA2JMYczeu0BbG65ppG3ypX5/Jk9/M33g 31 | WrDUQYMPoErUy1s6gGq9Q5sGY3kXVcAddZ3avaHTvARIOViqLCIZKU9hL02EIQo+uA7jJE6zNd1S 32 | PVnTddnGqUti7+Bp+kb/Ul3GM77GO3oewAX94HksNC0sMe9ikkb0/2V3XAnVzOqNSSN6Pp//Afhr 33 | zikTBQAA 34 | headers: 35 | Access-Control-Allow-Credentials: 36 | - 'true' 37 | Access-Control-Allow-Headers: 38 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key 39 | Access-Control-Allow-Methods: 40 | - GET,OPTIONS 41 | Access-Control-Allow-Origin: 42 | - '*' 43 | Cache-Control: 44 | - no-store, no-cache, must-revalidate, proxy-revalidate 45 | Connection: 46 | - keep-alive 47 | Content-Encoding: 48 | - gzip 49 | Content-Type: 50 | - application/json; charset=utf-8 51 | Date: 52 | - Wed, 26 Feb 2020 03:56:51 GMT 53 | Expires: 54 | - '0' 55 | Pragma: 56 | - no-cache 57 | Server: 58 | - nginx 59 | Surrogate-Control: 60 | - no-store 61 | Vary: 62 | - X-HTTP-Method-Override, Accept-Encoding 63 | X-RateLimit-Limit: 64 | - '10000' 65 | X-RateLimit-Remaining: 66 | - '9996' 67 | X-RateLimit-Reset: 68 | - '1582689439' 69 | X-Response-Time: 70 | - 160.362ms 71 | p3p: 72 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 73 | transfer-encoding: 74 | - chunked 75 | status: 76 | code: 201 77 | message: Created 78 | version: 1 79 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/TrackingTestCase.test_get_last_checkpoint.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | User-Agent: 12 | - python-requests/2.23.0 13 | aftership-api-key: 14 | - YOUR_API_KEY_IS_HERE 15 | method: GET 16 | uri: https://api.aftership.com/v4/last_checkpoint/k5lh7dy7vvqeck71p5loe011 17 | response: 18 | body: 19 | string: !!binary | 20 | H4sIAAAAAAAAA1WPwW7DIBBE/2XPrgSpUrf+it6rChFANjIGF5ZIbuR/zxJcO73B25nZ2RtMBiV0 21 | N1BBG+hOjK0NaFmZ1dDBeHZDq5f2ev0xamz5fHbBMM6hAYxSjdb3wufpYiKJ+cfpjb3zlobJ5Z6I 22 | GqyXL3NIWAyyoE/jNbmKJl/+IcFYya1YTCYl2VOrJ4caqMQcrMdSuu7w2bkGVDQSjRaSJhvZtQLt 23 | RDkbtrjs7xAidSFjgu7rm1JC9hgXYVN4PUSVeXmE7N1qZkKK+NM/Ttr4duDz77ir0l87V/m6rnfW 24 | feLVkAEAAA== 25 | headers: 26 | Cache-Control: 27 | - no-store, no-cache, must-revalidate, proxy-revalidate 28 | Connection: 29 | - keep-alive 30 | Content-Encoding: 31 | - gzip 32 | Content-Length: 33 | - '235' 34 | Content-Type: 35 | - application/json; charset=utf-8 36 | Date: 37 | - Wed, 26 Feb 2020 03:56:52 GMT 38 | Expires: 39 | - '0' 40 | Pragma: 41 | - no-cache 42 | Server: 43 | - nginx 44 | Surrogate-Control: 45 | - no-store 46 | Vary: 47 | - Accept-Encoding 48 | - Accept-Encoding 49 | X-RateLimit-Limit: 50 | - '10000' 51 | X-RateLimit-Remaining: 52 | - '9994' 53 | X-RateLimit-Reset: 54 | - '1582689438' 55 | X-Response-Time: 56 | - 144.109ms 57 | p3p: 58 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 59 | status: 60 | code: 200 61 | message: OK 62 | version: 1 63 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/TrackingTestCase.test_get_tracking.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | User-Agent: 12 | - python-requests/2.23.0 13 | aftership-api-key: 14 | - YOUR_API_KEY_IS_HERE 15 | method: GET 16 | uri: https://api.aftership.com/v4/trackings/4px/HH19260817 17 | response: 18 | body: 19 | string: !!binary | 20 | H4sIAAAAAAAAA41Uy27bMBD8F16bALRcO62+IMceeisKgibX8lYUyfKR2Aj8711alixZBpqbOTPa 21 | 5ewO/cE6SJLVH0w5DayuOD8/MS17LAWpWrRN+Y2a1cx3HNb7w/HPeq10+1JFSP7Eqw17YiqATKCF 22 | TKSreMWfefVcbX/ydb3Z1pvVF85rzkmYvf6c0MiYxKfVw12Fzd0OAqlfX1ffqy3/tnohOppMNthX 23 | f6SDVAnfyG0KGehkdXDF3q/fZCPH5DqxRzA6stpmYwYQgrCygwHUYKhIOImEUzAmtDKhs0K5bBPx 24 | GN16rORyQCr0Px10Ek3srwRHD6rMYOg4iNBdFdal8QYuaKpf7MzPwst0uIHY4OPO8YC+A5tIr1rZ 25 | QC9asqja7EVZzoIbJ/OQTSe/BN8Bm8OySw+LbPHGYWNpFrtxCrGLcJ1DpOkqKs6kxxIJWVb+A6wu 26 | GSY672aQ4Hw1wqKDGMnv7IuEycB9lC5JoytcB8OvSe3QgBhTGLP3LtDWhmsaaZt8qd+fydPfTB+4 27 | Fix10OADqBL18pYOoFrv0KbBWN5FFXBHXad2b+g0LwFSDpYqi0hGylPYSxNhiIIPrsM4idNsTbdU 28 | T9Z0XbZx6pLYO3iavtG/VJfxjK/xjp4HcEE/eB4LTQtLzLuYpBH9f9kdV0I1s3pj0oiez+d/mFcR 29 | hBMFAAA= 30 | headers: 31 | Access-Control-Allow-Credentials: 32 | - 'true' 33 | Access-Control-Allow-Headers: 34 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key 35 | Access-Control-Allow-Methods: 36 | - GET,OPTIONS 37 | Access-Control-Allow-Origin: 38 | - '*' 39 | Cache-Control: 40 | - no-store, no-cache, must-revalidate, proxy-revalidate 41 | Connection: 42 | - keep-alive 43 | Content-Encoding: 44 | - gzip 45 | Content-Type: 46 | - application/json; charset=utf-8 47 | Date: 48 | - Wed, 26 Feb 2020 03:56:54 GMT 49 | Expires: 50 | - '0' 51 | Pragma: 52 | - no-cache 53 | Server: 54 | - nginx 55 | Surrogate-Control: 56 | - no-store 57 | Vary: 58 | - Accept-Encoding 59 | X-RateLimit-Limit: 60 | - '10000' 61 | X-RateLimit-Remaining: 62 | - '9993' 63 | X-RateLimit-Reset: 64 | - '1582689439' 65 | X-Response-Time: 66 | - 214.350ms 67 | p3p: 68 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 69 | transfer-encoding: 70 | - chunked 71 | status: 72 | code: 200 73 | message: OK 74 | version: 1 75 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/TrackingTestCase.test_list_trackings.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | User-Agent: 12 | - python-requests/2.23.0 13 | aftership-api-key: 14 | - YOUR_API_KEY_IS_HERE 15 | method: GET 16 | uri: https://api.aftership.com/v4/trackings?limit=1&slug=4px 17 | response: 18 | body: 19 | string: !!binary | 20 | H4sIAAAAAAAAA4VUy27bMBD8F15rA5RcO7G+IMceegsCgqbWMiu+ykdjw/C/d/W0ZLkpoAM1uyRn 21 | Z2d5JRoiJ8WVCFsCKXJKbytS8g5zvEIsWxEltYztSthkcJXvt3S/W5EaLp/Wl6QgZEWCShWuvrsz 22 | /lgvK2lI8f6B50GI0vAobQ9EXnVbjhJUGbq18MAjlIxHppudJKfZfp1l6/z1J90U2x1+3ygtKH1I 23 | 5uc2Oadrmq/z3TJZ8RBZcmW/gxQmKbUiHmLyhkXLApgSfMcNK/QSPJuQZm3V/sJksJu+As9FLU2F 24 | 3N+vRDYKOE1hczydf202oqxf8gDRXWi+nbF9yjQbmU5Jfpm4KOnL7IEtM0kfmkLJ21u2z3f0NXt5 25 | bBwXUf7BtkefAP9M6W1TXitNCtFqNjStU7EDUTDDNQxgCQoPQcWinIL/UrQ/6b/Kd3mguVShowRn 26 | B6LRYLhxSJK2zzA2jgzQqnh+U878nzkeT3ewce7Tm8NJOg0mYr6ocThYPw6PUSnq5FjTnEVsVOZp 27 | NF7cEvwEWZ2Wt3QwS0beY7IyqMVhVCHoAL0OAdUVeDjhTpJhBH+g8dEXjQfSYQYxSrMRZhpCaB+D 28 | yY4oo4JHK7VOQwq9MLR3qpYK2OjCkJyzHrs20FTcVKk9v/vHmn4n3GBraB6CEpwH0Vi9maUTiNpZ 29 | aeJQWDoE4eUBb52We0enflnO/JGrAIMVnLdahomdZm26u3rSpr7Zyor+gZvBU/eN9XPRyjNO40N4 30 | bsBF+Ml4LHLwXV5gzobIFese+odYY6pZqfdIHNHbx+32FyJiU6ExBgAA 31 | headers: 32 | Access-Control-Allow-Credentials: 33 | - 'true' 34 | Access-Control-Allow-Headers: 35 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key 36 | Access-Control-Allow-Methods: 37 | - GET,OPTIONS 38 | Access-Control-Allow-Origin: 39 | - '*' 40 | Cache-Control: 41 | - no-store, no-cache, must-revalidate, proxy-revalidate 42 | Connection: 43 | - keep-alive 44 | Content-Encoding: 45 | - gzip 46 | Content-Type: 47 | - application/json; charset=utf-8 48 | Date: 49 | - Wed, 26 Feb 2020 03:56:56 GMT 50 | Expires: 51 | - '0' 52 | Pragma: 53 | - no-cache 54 | Server: 55 | - nginx 56 | Surrogate-Control: 57 | - no-store 58 | Vary: 59 | - Accept-Encoding 60 | X-RateLimit-Limit: 61 | - '10000' 62 | X-RateLimit-Remaining: 63 | - '9992' 64 | X-RateLimit-Reset: 65 | - '1582689439' 66 | X-Response-Time: 67 | - 244.104ms 68 | p3p: 69 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 70 | transfer-encoding: 71 | - chunked 72 | status: 73 | code: 200 74 | message: OK 75 | - request: 76 | body: null 77 | headers: 78 | Accept: 79 | - '*/*' 80 | Accept-Encoding: 81 | - gzip, deflate 82 | Connection: 83 | - keep-alive 84 | User-Agent: 85 | - python-requests/2.23.0 86 | aftership-api-key: 87 | - YOUR_API_KEY_IS_HERE 88 | method: GET 89 | uri: https://api.aftership.com/v4/trackings?slug=4px&limit=1 90 | response: 91 | body: 92 | string: !!binary | 93 | H4sIAAAAAAAAA4VUy27bMBD8F15rA5RcO7G+IMceegsCgqbWMiu+ykdjw/C/d/W0ZLkpoAM1uyRn 94 | Z2d5JRoiJ8WVCFsCKXJKbytS8g5zvEIsWxEltYztSthkcJXvt3S/W5EaLp/Wl6QgZEWCShWuvrsz 95 | /lgvK2lI8f6B50GI0vAobQ9EXnVbjhJUGbq18MAjlIxHppudJKfZfp1l6/z1J90U2x1+3ygtKH1I 96 | 5uc2Oadrmq/z3TJZ8RBZcmW/gxQmKbUiHmLyhkXLApgSfMcNK/QSPJuQZm3V/sJksJu+As9FLU2F 97 | 3N+vRDYKOE1hczydf202oqxf8gDRXWi+nbF9yjQbmU5Jfpm4KOnL7IEtM0kfmkLJ21u2z3f0NXt5 98 | bBwXUf7BtkefAP9M6W1TXitNCtFqNjStU7EDUTDDNQxgCQoPQcWinIL/UrQ/6b/Kd3mguVShowRn 99 | B6LRYLhxSJK2zzA2jgzQqnh+U878nzkeT3ewce7Tm8NJOg0mYr6ocThYPw6PUSnq5FjTnEVsVOZp 100 | NF7cEvwEWZ2Wt3QwS0beY7IyqMVhVCHoAL0OAdUVeDjhTpJhBH+g8dEXjQfSYQYxSrMRZhpCaB+D 101 | yY4oo4JHK7VOQwq9MLR3qpYK2OjCkJyzHrs20FTcVKk9v/vHmn4n3GBraB6CEpwH0Vi9maUTiNpZ 102 | aeJQWDoE4eUBb52We0enflnO/JGrAIMVnLdahomdZm26u3rSpr7Zyor+gZvBU/eN9XPRyjNO40N4 103 | bsBF+Ml4LHLwXV5gzobIFese+odYY6pZqfdIHNHbx+32FyJiU6ExBgAA 104 | headers: 105 | Access-Control-Allow-Credentials: 106 | - 'true' 107 | Access-Control-Allow-Headers: 108 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key 109 | Access-Control-Allow-Methods: 110 | - GET,OPTIONS 111 | Access-Control-Allow-Origin: 112 | - '*' 113 | Cache-Control: 114 | - no-store, no-cache, must-revalidate, proxy-revalidate 115 | Connection: 116 | - keep-alive 117 | Content-Encoding: 118 | - gzip 119 | Content-Type: 120 | - application/json; charset=utf-8 121 | Date: 122 | - Wed, 26 Feb 2020 03:56:56 GMT 123 | Expires: 124 | - '0' 125 | Pragma: 126 | - no-cache 127 | Server: 128 | - nginx 129 | Surrogate-Control: 130 | - no-store 131 | Vary: 132 | - Accept-Encoding 133 | X-RateLimit-Limit: 134 | - '10000' 135 | X-RateLimit-Remaining: 136 | - '9992' 137 | X-RateLimit-Reset: 138 | - '1582689439' 139 | X-Response-Time: 140 | - 244.104ms 141 | p3p: 142 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 143 | transfer-encoding: 144 | - chunked 145 | status: 146 | code: 200 147 | message: OK 148 | version: 1 149 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/TrackingTestCase.test_retrack.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | Content-Length: 12 | - '0' 13 | User-Agent: 14 | - python-requests/2.23.0 15 | aftership-api-key: 16 | - YOUR_API_KEY_IS_HERE 17 | method: POST 18 | uri: https://api.aftership.com/v4/trackings/k5lh7dy7vvqeck71p5loe011/retrack 19 | response: 20 | body: 21 | string: !!binary | 22 | H4sIAAAAAAAAA3WQUQrDIBBE77LfKWigtc1lglVJRKOproEQvHtNS0NI2995M7PLLDAo5NAsILxU 23 | 0NSE5Aokf2sYuDDadSvXEhowZ9szObNpeihhGB3P1itCKVTw8bYuDXcVipne6gu5UlZgtKmUgOi1 24 | 46fRRywaF6inchJDUrs4F8Inh1uNS9busA+60659ecIMzQFLFbHcQO3/e4z6zq0/cVtq1xEOnbHX 25 | Y1sm+UFwU3POT4W14KRMAQAA 26 | headers: 27 | Access-Control-Allow-Credentials: 28 | - 'true' 29 | Access-Control-Allow-Headers: 30 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key 31 | Access-Control-Allow-Methods: 32 | - GET,OPTIONS 33 | Access-Control-Allow-Origin: 34 | - '*' 35 | Cache-Control: 36 | - no-store, no-cache, must-revalidate, proxy-revalidate 37 | Connection: 38 | - keep-alive 39 | Content-Encoding: 40 | - gzip 41 | Content-Length: 42 | - '189' 43 | Content-Type: 44 | - application/json; charset=utf-8 45 | Date: 46 | - Wed, 26 Feb 2020 03:56:58 GMT 47 | Expires: 48 | - '0' 49 | Pragma: 50 | - no-cache 51 | Server: 52 | - nginx 53 | Surrogate-Control: 54 | - no-store 55 | Vary: 56 | - Accept-Encoding 57 | - X-HTTP-Method-Override, Accept-Encoding 58 | X-RateLimit-Limit: 59 | - '10000' 60 | X-RateLimit-Remaining: 61 | - '9991' 62 | X-RateLimit-Reset: 63 | - '1582689439' 64 | X-Response-Time: 65 | - 316.225ms 66 | p3p: 67 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 68 | status: 69 | code: 200 70 | message: OK 71 | version: 1 72 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/TrackingTestCase.test_update_tracking.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: '{"tracking": {"title": "new title"}}' 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | Content-Length: 12 | - '36' 13 | Content-Type: 14 | - application/json 15 | User-Agent: 16 | - python-requests/2.23.0 17 | aftership-api-key: 18 | - YOUR_API_KEY_IS_HERE 19 | method: PUT 20 | uri: https://api.aftership.com/v4/trackings/k5lh7dy7vvqeck71p5loe011 21 | response: 22 | body: 23 | string: !!binary | 24 | H4sIAAAAAAAAA41Uy27bMBD8lYLXxgElw1ajUz+hh9yCgqDJtcSKIhk+nLqB/71Ly5Ity0B7E2eW 25 | 3J3dWX2SHiIn9ScRVgKpS0pPT0TyAYuei06ZJn8rSWrSbXRbyWN1OLyD6KrCbbQFWhTkiQgPPIJk 26 | PGJcSUu6ouWq3LzSl3pd1ZvtV0prSjEwOfkgcPtK1/WmwpApUPMQ2X9Hj7Uyk/odeIwuXsot/VZU 27 | SAadUAQRrTJ85WyIiHER1QElR58AT0Z6mzW+/UQtKUTbs70CLQOpTdJ6BMEzw3sYQQkaH/FHFtUt 28 | GCImisoaJmwyEXkV7Hp6ySav8KF/xUHPlcb8b+RX9/yn5ab5zvcRfGiVexa2J1gq/HYgcoPGSsbL 29 | yoZBjLFxqsx6iXmzzPmZOR7bK6ga9biinLkHEzFedLyBIWjJKtElx/LkFtzUsYdsPLol+AGqaZdZ 30 | Bpglo66cagz2Yjd1IfQBLn0I2HWBjxPuVPYLz474AUZmgyOddjOIUVpMMOshBNQ7uxFV1Bkx8PFl 31 | +L64ECu49IVeXNwrDWxyaEjOWY9DG6vUONp0fn44o6T3hBdsBwYTSHAeRF6DvGctbp6zysRRV9oF 32 | 4dUOs96qvaKTjRD2EJM3+DILqCOvyZ7rAKMTnLe9Cjdumk3pavabKV1mra04G/kOvjXfpJ+Lc3um 33 | Tb2j5/5b0A+2ZhHTwRLLa881G/5zd1z21EzqlYkTejqd/gKxUyAlLwUAAA== 34 | headers: 35 | Access-Control-Allow-Credentials: 36 | - 'true' 37 | Access-Control-Allow-Headers: 38 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key 39 | Access-Control-Allow-Methods: 40 | - GET,OPTIONS 41 | Access-Control-Allow-Origin: 42 | - '*' 43 | Cache-Control: 44 | - no-store, no-cache, must-revalidate, proxy-revalidate 45 | Connection: 46 | - keep-alive 47 | Content-Encoding: 48 | - gzip 49 | Content-Type: 50 | - application/json; charset=utf-8 51 | Date: 52 | - Wed, 26 Feb 2020 03:57:00 GMT 53 | Expires: 54 | - '0' 55 | Pragma: 56 | - no-cache 57 | Server: 58 | - nginx 59 | Surrogate-Control: 60 | - no-store 61 | Vary: 62 | - Accept-Encoding 63 | X-RateLimit-Limit: 64 | - '10000' 65 | X-RateLimit-Remaining: 66 | - '9990' 67 | X-RateLimit-Reset: 68 | - '1582689439' 69 | X-Response-Time: 70 | - 238.152ms 71 | p3p: 72 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 73 | transfer-encoding: 74 | - chunked 75 | status: 76 | code: 200 77 | message: OK 78 | version: 1 79 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/TrackingWithAdditionalFieldsTestCase.test_create_tracking.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: '{"tracking": {"slug": "postnl-3s", "tracking_number": "3SKAAG5995399", 4 | "tracking_destination_country": "ESP", "tracking_postal_code": "46970"}}' 5 | headers: 6 | Accept: 7 | - '*/*' 8 | Accept-Encoding: 9 | - gzip, deflate 10 | Connection: 11 | - keep-alive 12 | Content-Length: 13 | - '143' 14 | Content-Type: 15 | - application/json 16 | User-Agent: 17 | - python-requests/2.25.1 18 | aftership-api-key: 19 | - YOUR_API_KEY_IS_HERE 20 | method: POST 21 | uri: https://api.aftership.com/v4/trackings 22 | response: 23 | body: 24 | string: !!binary | 25 | H4sIAAAAAAAAA41UwW7bMAz9F1/XNkrSNIhvPQw77FKguw2DoMhszFmWNIlqGhT591Fx7MRNgPZm 26 | PdIk39MT34sWSBXle6FdBUU5E9P9TVGpDqOgdIN2k7+xKspim9Lbbr109d+3xaJpPS3Cciemy+Km 27 | 0AEUQSUVcd5MzKa3Yn47e/gl7sv5rBSLb0KUQnBi8tXXEo2KJL+c3c8qbWrXEDh7/vzz8fHHYrVa 28 | zFcrzogmMZPCu0jW3M4jQ0oTvjJtCgn4ZKvgMs/ff5hPiuRa+YJgqliUNhnTgxCkVS30YAWGi4Sd 29 | JMygyEgktIrQWaldssRBjG4+lHEpIFf5LA9ahSZ288CbB52V6Nv1SeiOGdbRMJMLFdfPXMZn6RXV 30 | YzDre0Jwg9dniTX6FixxBd2oDXRJl1HUTfKjokNsEOpqlHb+EtwCburLLh0sk8VTDDeW1VkPusQ2 31 | wlGZyHprLl4oj9kqKvvgCWyVvc3htB5BUojpAMsWYmS+oz8IycAVix1MyFMctRFHE7doQA4Gjcl7 32 | F/gq+0mNspt0aNGdmda/xD+4Biw3qcAH0PkV5GdWg268Q0s9t7SOOuCau54zPqHnJgpAKViuLCNz 33 | ya/kRZkIvRV8cC3GM4+Nburk87ObOt63cfpg4w/wuSV70w86GLQN06uJfDmZbLfbu+5p3lkzeXWs 34 | UJ0wTpjzCwYWUREBb5zjLhjXDFAha0THml1waKT04T6GzfAhPDb9RfjKI+Wpvz8/nS+dBi5/zGyU 35 | kd1iLe4fVsvRnspmHul7itCA7vf7/xt4+56jBQAA 36 | headers: 37 | Access-Control-Allow-Credentials: 38 | - 'true' 39 | Access-Control-Allow-Headers: 40 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key,aftership-agent,request-id 41 | Access-Control-Allow-Methods: 42 | - GET,OPTIONS 43 | Access-Control-Allow-Origin: 44 | - '*' 45 | CF-Cache-Status: 46 | - DYNAMIC 47 | CF-RAY: 48 | - 635da729cd0ad18f-HKG 49 | Cache-Control: 50 | - no-store, no-cache, must-revalidate, proxy-revalidate 51 | Connection: 52 | - keep-alive 53 | Content-Encoding: 54 | - gzip 55 | Content-Type: 56 | - application/json; charset=utf-8 57 | Date: 58 | - Fri, 26 Mar 2021 04:32:05 GMT 59 | Expect-CT: 60 | - max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" 61 | Expires: 62 | - '0' 63 | Pragma: 64 | - no-cache 65 | Server: 66 | - cloudflare 67 | Set-Cookie: 68 | - __cfduid=d9f376ca82fb83154c7631b2c2731cf871616733124; expires=Sun, 25-Apr-21 69 | 04:32:04 GMT; path=/; domain=.aftership.com; HttpOnly; SameSite=Lax 70 | Strict-Transport-Security: 71 | - max-age=15552000; includeSubDomains 72 | Surrogate-Control: 73 | - no-store 74 | Transfer-Encoding: 75 | - chunked 76 | Vary: 77 | - X-HTTP-Method-Override, Accept-Encoding 78 | X-RateLimit-Limit: 79 | - '10' 80 | X-RateLimit-Remaining: 81 | - '9' 82 | X-RateLimit-Reset: 83 | - '1616733126' 84 | X-Response-Time: 85 | - 216.710ms 86 | cf-request-id: 87 | - 090e66ce1a0000d18f901db000000001 88 | p3p: 89 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 90 | status: 91 | code: 201 92 | message: Created 93 | version: 1 94 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/TrackingWithAdditionalFieldsTestCase.test_get_last_checkpoint.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | User-Agent: 12 | - python-requests/2.25.1 13 | aftership-api-key: 14 | - YOUR_API_KEY_IS_HERE 15 | method: GET 16 | uri: https://api.aftership.com/v4/last_checkpoint/wuuxyb7ohjx55kmpt5r7y017 17 | response: 18 | body: 19 | string: !!binary | 20 | H4sIAAAAAAAAA7WQu27CMBSGXyXyCkgnCQbFG0NVVV0qwVZVkbFd4pLYkX3ckqK8e22g9KKuXX9/ 21 | /i/nSDqFnLAjEVYqwgqAcUokP2taEkbeQjgM26VtXg6U7rseqVsOkC/JlKDjYq/Nrjah2yoX4XJ9 22 | v1rd0qqiZVVFwrdhF+XeejTtrPTpE0/Kndk4brzGBIXtL7EGmF8f6k55z3exHVk5p1+VzDhmUnnU 23 | hqO2JhM2GHRD/CEaJfa91QbTpj/ShVMclax5BEgBRT6DclYsNjBnZcFgMQFgAD+catRdCr/SdJMD 24 | o1XkJpBfaI0DYSa0bexgrZOpmvKEPT4l4VSv1t6W0edm/ZD8L6LhJ/Oz+LV03ei+UwYzp4Q6bdbX 25 | nZl9/j4/HQpj2mf+vx74XffnnHEcPwAGhsMqPQIAAA== 26 | headers: 27 | CF-Cache-Status: 28 | - DYNAMIC 29 | CF-RAY: 30 | - 635da879bd12247f-HKG 31 | Cache-Control: 32 | - no-store, no-cache, must-revalidate, proxy-revalidate 33 | Connection: 34 | - keep-alive 35 | Content-Encoding: 36 | - gzip 37 | Content-Length: 38 | - '316' 39 | Content-Type: 40 | - application/json; charset=utf-8 41 | Date: 42 | - Fri, 26 Mar 2021 04:32:58 GMT 43 | Expect-CT: 44 | - max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" 45 | Expires: 46 | - '0' 47 | Pragma: 48 | - no-cache 49 | Server: 50 | - cloudflare 51 | Set-Cookie: 52 | - __cfduid=d705b665db8b8650ce80f8cc52b8655711616733177; expires=Sun, 25-Apr-21 53 | 04:32:57 GMT; path=/; domain=.aftership.com; HttpOnly; SameSite=Lax 54 | Strict-Transport-Security: 55 | - max-age=15552000; includeSubDomains 56 | Surrogate-Control: 57 | - no-store 58 | Vary: 59 | - Accept-Encoding 60 | - Accept-Encoding 61 | X-RateLimit-Limit: 62 | - '10' 63 | X-RateLimit-Remaining: 64 | - '9' 65 | X-RateLimit-Reset: 66 | - '1616733179' 67 | X-Response-Time: 68 | - 116.402ms 69 | cf-request-id: 70 | - 090e67a0160000247ffea72000000001 71 | p3p: 72 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 73 | status: 74 | code: 200 75 | message: OK 76 | version: 1 77 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/TrackingWithAdditionalFieldsTestCase.test_get_tracking.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | User-Agent: 12 | - python-requests/2.25.1 13 | aftership-api-key: 14 | - YOUR_API_KEY_IS_HERE 15 | method: GET 16 | uri: https://api.aftership.com/v4/trackings/postnl-3s/3SKAAG5995399?tracking_destination_country=ESP&tracking_postal_code=46970 17 | response: 18 | body: 19 | string: !!binary | 20 | H4sIAAAAAAAAA+1X227TQBD9FcuvpK0vuTR+qwRCCFRVJG+osjbrSbLY3l320jRU+Xdm42sutCCE 21 | QIg3e3ZmdubMWfvsk1+CIX7y5FORgZ9EQbAb+BmpbEYRmjO+cs8s8xNfXavPXzf5Y7YtlcpLqSaP 22 | iyCIMn/gUwXEQJYSg35REIUXQXwRjedBnMSTZDh5FQRJEKCjldlzjtetY0G0SX/Yu6k15bZcgELv 23 | ePb+5ubtaDodxdMpeujCYie+FNrw4iLWaCLUsAds2ygL+MYzJVyfn+6xH6uNKNMlgyLTfsJtUTRG 24 | UCknJTTGDApMorapYc44chZtGCeGCZ5SYbnBRaZFjLu/md05sIRVDNO86AglYYWuKoJHCdRh0WzY 25 | FMBE7cGFaasSKsMNXDeH76kkZn1odAh3FrZiJ8XcfnjtAFwzWQI3mILmZAWVVxPZrTKaW1ln7WYW 26 | zcPrJI6TEVIhrGbWhrQQ9ktpV81Wnho3wFZr3Dy8DMcn5tRy5giTr9wubMURtUWLly411IhpHAR1 27 | ZRLJHImIY8g7PleEa8yADnZxZEyDYNgupCVojVCgw41S2EPmEeP1xurVSLrkzBRwhpd75mKBNZph 28 | zfySFZC2rNZWSqFw+g1ZC8JXdr9z1RR2/MVigMiB4yYZSAXUHR1HtzXQXArGjWv76dxJoMy0+Lxw 29 | lHsnVNB9k21gzZr+6egAmtUz8hoiD7yFNR6S1tuC8UiH3x0WdvvB7xJWNKwSNuNYio9AwYUcjqmz 30 | 46TCc5NyPl4vuIOnPsJd08E8HCXRNIk60lKBp8ZNt+WQ6ZH2K5PNoyKbdF+Ue90N/sP+87CPxn8l 31 | 7Pg9HHi3YNag8Bhm2j+eQf3BPDMEVffvLbbfw7sO/sFv0Xeg9rqwl3COI2z0P86/E+cz/75/BOc1 32 | 0d4CgHu6+jv9cZDHSTD8O0F+Mxt4M0kYP4W3EnvP0Zi1SsITy77AOEW8SvZbpcwzUxjNwyAZTbH7 33 | X53C/b4yTRVbINJ90dZZ+/pYgbGKowJKNfDMXQGWpNDQqFypRMl0Tz4fiM1OxPfEZq1kj/+3tbmv 34 | thtB3+q1gvEcYVkbI5Orq81mc1lR6ZIXVw+Ih1lbpq8QnCVTKPaIMVDKhlGHORVkDHlg6pz177jZ 35 | iND9WNprz9HyoZ4/WT5zAekY1DjlcBrouiFFWt0a/eF4Ojm4hDk9foBvt9LNfrfbfQNYDkmqgA4A 36 | AA== 37 | headers: 38 | Access-Control-Allow-Credentials: 39 | - 'true' 40 | Access-Control-Allow-Headers: 41 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key,aftership-agent,request-id 42 | Access-Control-Allow-Methods: 43 | - GET,OPTIONS 44 | Access-Control-Allow-Origin: 45 | - '*' 46 | CF-Cache-Status: 47 | - DYNAMIC 48 | CF-RAY: 49 | - 635d9ffb4f242332-HKG 50 | Cache-Control: 51 | - no-store, no-cache, must-revalidate, proxy-revalidate 52 | Connection: 53 | - keep-alive 54 | Content-Encoding: 55 | - gzip 56 | Content-Type: 57 | - application/json; charset=utf-8 58 | Date: 59 | - Fri, 26 Mar 2021 04:27:11 GMT 60 | Expect-CT: 61 | - max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" 62 | Expires: 63 | - '0' 64 | Pragma: 65 | - no-cache 66 | Server: 67 | - cloudflare 68 | Set-Cookie: 69 | - __cfduid=d23e64993e919582375d48b3f96b13e6a1616732829; expires=Sun, 25-Apr-21 70 | 04:27:09 GMT; path=/; domain=.aftership.com; HttpOnly; SameSite=Lax 71 | Strict-Transport-Security: 72 | - max-age=15552000; includeSubDomains 73 | Surrogate-Control: 74 | - no-store 75 | Transfer-Encoding: 76 | - chunked 77 | Vary: 78 | - Accept-Encoding 79 | X-RateLimit-Limit: 80 | - '10' 81 | X-RateLimit-Remaining: 82 | - '9' 83 | X-RateLimit-Reset: 84 | - '1616732831' 85 | X-Response-Time: 86 | - 247.861ms 87 | cf-request-id: 88 | - 090e62510f0000233235b12000000001 89 | p3p: 90 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 91 | status: 92 | code: 200 93 | message: OK 94 | - request: 95 | body: null 96 | headers: 97 | Accept: 98 | - '*/*' 99 | Accept-Encoding: 100 | - gzip, deflate 101 | Connection: 102 | - keep-alive 103 | User-Agent: 104 | - python-requests/2.25.1 105 | aftership-api-key: 106 | - YOUR_API_KEY_IS_HERE 107 | method: GET 108 | uri: https://api.aftership.com/v4/trackings/postnl-3s/3SKAAG5995399?tracking_postal_code=46970&tracking_destination_country=ESP 109 | response: 110 | body: 111 | string: !!binary | 112 | H4sIAAAAAAAAA+1X227TQBD9FcuvpK0vuTR+qwRCCFRVJG+osjbrSbLY3l320jRU+Xdm42sutCCE 113 | QIg3e3ZmdubMWfvsk1+CIX7y5FORgZ9EQbAb+BmpbEYRmjO+cs8s8xNfXavPXzf5Y7YtlcpLqSaP 114 | iyCIMn/gUwXEQJYSg35REIUXQXwRjedBnMSTZDh5FQRJEKCjldlzjtetY0G0SX/Yu6k15bZcgELv 115 | ePb+5ubtaDodxdMpeujCYie+FNrw4iLWaCLUsAds2ygL+MYzJVyfn+6xH6uNKNMlgyLTfsJtUTRG 116 | UCknJTTGDApMorapYc44chZtGCeGCZ5SYbnBRaZFjLu/md05sIRVDNO86AglYYWuKoJHCdRh0WzY 117 | FMBE7cGFaasSKsMNXDeH76kkZn1odAh3FrZiJ8XcfnjtAFwzWQI3mILmZAWVVxPZrTKaW1ln7WYW 118 | zcPrJI6TEVIhrGbWhrQQ9ktpV81Wnho3wFZr3Dy8DMcn5tRy5giTr9wubMURtUWLly411IhpHAR1 119 | ZRLJHImIY8g7PleEa8yADnZxZEyDYNgupCVojVCgw41S2EPmEeP1xurVSLrkzBRwhpd75mKBNZph 120 | zfySFZC2rNZWSqFw+g1ZC8JXdr9z1RR2/MVigMiB4yYZSAXUHR1HtzXQXArGjWv76dxJoMy0+Lxw 121 | lHsnVNB9k21gzZr+6egAmtUz8hoiD7yFNR6S1tuC8UiH3x0WdvvB7xJWNKwSNuNYio9AwYUcjqmz 122 | 46TCc5NyPl4vuIOnPsJd08E8HCXRNIk60lKBp8ZNt+WQ6ZH2K5PNoyKbdF+Ue90N/sP+87CPxn8l 123 | 7Pg9HHi3YNag8Bhm2j+eQf3BPDMEVffvLbbfw7sO/sFv0Xeg9rqwl3COI2z0P86/E+cz/75/BOc1 124 | 0d4CgHu6+jv9cZDHSTD8O0F+Mxt4M0kYP4W3EnvP0Zi1SsITy77AOEW8SvZbpcwzUxjNwyAZTbH7 125 | X53C/b4yTRVbINJ90dZZ+/pYgbGKowJKNfDMXQGWpNDQqFypRMl0Tz4fiM1OxPfEZq1kj/+3tbmv 126 | thtB3+q1gvEcYVkbI5Orq81mc1lR6ZIXVw+Ih1lbpq8QnCVTKPaIMVDKhlGHORVkDHlg6pz177jZ 127 | iND9WNprz9HyoZ4/WT5zAekY1DjlcBrouiFFWt0a/eF4Ojm4hDk9foBvt9LNfrfbfQNYDkmqgA4A 128 | AA== 129 | headers: 130 | Access-Control-Allow-Credentials: 131 | - 'true' 132 | Access-Control-Allow-Headers: 133 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key,aftership-agent,request-id 134 | Access-Control-Allow-Methods: 135 | - GET,OPTIONS 136 | Access-Control-Allow-Origin: 137 | - '*' 138 | CF-Cache-Status: 139 | - DYNAMIC 140 | CF-RAY: 141 | - 635d9ffb4f242332-HKG 142 | Cache-Control: 143 | - no-store, no-cache, must-revalidate, proxy-revalidate 144 | Connection: 145 | - keep-alive 146 | Content-Encoding: 147 | - gzip 148 | Content-Type: 149 | - application/json; charset=utf-8 150 | Date: 151 | - Fri, 26 Mar 2021 04:27:11 GMT 152 | Expect-CT: 153 | - max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" 154 | Expires: 155 | - '0' 156 | Pragma: 157 | - no-cache 158 | Server: 159 | - cloudflare 160 | Set-Cookie: 161 | - __cfduid=d23e64993e919582375d48b3f96b13e6a1616732829; expires=Sun, 25-Apr-21 162 | 04:27:09 GMT; path=/; domain=.aftership.com; HttpOnly; SameSite=Lax 163 | Strict-Transport-Security: 164 | - max-age=15552000; includeSubDomains 165 | Surrogate-Control: 166 | - no-store 167 | Transfer-Encoding: 168 | - chunked 169 | Vary: 170 | - Accept-Encoding 171 | X-RateLimit-Limit: 172 | - '10' 173 | X-RateLimit-Remaining: 174 | - '9' 175 | X-RateLimit-Reset: 176 | - '1616732831' 177 | X-Response-Time: 178 | - 247.861ms 179 | cf-request-id: 180 | - 090e62510f0000233235b12000000001 181 | p3p: 182 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 183 | status: 184 | code: 200 185 | message: OK 186 | version: 1 187 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/TrackingWithAdditionalFieldsTestCase.test_get_tracking_by_id.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | User-Agent: 12 | - python-requests/2.25.1 13 | aftership-api-key: 14 | - YOUR_API_KEY_IS_HERE 15 | method: GET 16 | uri: https://api.aftership.com/v4/trackings/wuuxyb7ohjx55kmpt5r7y017 17 | response: 18 | body: 19 | string: !!binary | 20 | H4sIAAAAAAAAA+1X227bOBD9FUGvdRLKiuxabwG2WCy2CIrab4tCoKWxxZVEcnmp4wb+9x1a1MWx 21 | m7Qoig2KfZOGM8OZM4fS4WPYgKFh+hjmooAwnRJymIQFbW1G0bxifOueWRGm4c7ah/16Lsq/H5Kk 22 | aqRJ1HxPonk4CXMF1ECRUYN+UzKNrkh8NZ2tyG0aT1OSvCEkJQQdrSyec5z1jjXVJvtm767WjNtm 23 | DQq94+Wfd3e/J4tFEi8W6KFri52EUmjD66tYo4nmhn3Gto2ygG+8UML1+dcn7MdqI5psw6AudJhy 24 | W9edEVTGaQOdsYAak6h9ZpgzJs6iDePUMMGzXFhucJFpEePu75YfHFjCKoZpXnSEhrJatxXBg4Tc 25 | YdFt2BXAhPfgwvRVCVXgBq6b0/dMUlOeGh3Cg4Vt2Vkx9+9/cwCWTDbADabIK7qF1quLHFZZXlnp 26 | sw4zm66it2kcp8n8DYnamfUhPYTjUvpVs5fnxh2wbYmbR9fR7MycWc4cYaqt24VtOaK27vHSjQaP 27 | mMZB5K5MKpkjEXUM+YOvFOUaM6CDXT8xZoTc9gtZA1ojFOhwpxT2UATUBKOxBh5Jl5yZGi7w8shc 28 | LNCjGXnmN6yGrGe1tlIKhdPvyFpTvrXHndumsON/LAaICjhuUoBUkLuj4+hWQl5JwbhxbT9eOgk5 29 | Mz0+Lxzl0QkV+bHJPtCzZnw6BoCWfkZBR+RJsLYmQNIGezABHfD7gIXdvw+HhC0N24TdODbiI+Tg 30 | Qk7HNNhxUtGlSTmfYBQ8wOOP8NA0WUVJOl2k04G0ucBT46bbc8iMSPuFye5R0V12LMq9Hib/w/79 31 | sCezVwk7fg8nwT2YEhQew0KHT2fgP5gXhqB8/8F6/zW8ffA3fou+AnUwhL2EM3YZv056/zI4X/j3 32 | /SI4l1QHawAe6Pbv9J+DPEvJ7esE+d1yEiwlZfwc3lbsPUdj1iuJQGzGAuMc8TbZT5Uyz0whWUUk 33 | TRbY/Y9O4dOxMp0rtkakx6JtsI71sQJjFUcFlGnghbsCbGitoVO5UomG6ZF8PhGbg4gfiU2vZJ/+ 34 | b715rLY7Qd/rtZrxCmEpjZHpzc1ut7tuqXTN65vPiIcpLdM3CM6GKRR71BjA65Rn1GlOBQVDHhif 35 | 0/+Ou41ofhxLf+15snyq58+WL1xABgZ1ThWcB7puaJ21t8bwdraYn1zCnB4/wXdYGWZ/OBz+Bet+ 36 | EHmADgAA 37 | headers: 38 | Access-Control-Allow-Credentials: 39 | - 'true' 40 | Access-Control-Allow-Headers: 41 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key,aftership-agent,request-id 42 | Access-Control-Allow-Methods: 43 | - GET,OPTIONS 44 | Access-Control-Allow-Origin: 45 | - '*' 46 | CF-Cache-Status: 47 | - DYNAMIC 48 | CF-RAY: 49 | - 635da88b58ed21a6-HKG 50 | Cache-Control: 51 | - no-store, no-cache, must-revalidate, proxy-revalidate 52 | Connection: 53 | - keep-alive 54 | Content-Encoding: 55 | - gzip 56 | Content-Type: 57 | - application/json; charset=utf-8 58 | Date: 59 | - Fri, 26 Mar 2021 04:33:01 GMT 60 | Expect-CT: 61 | - max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" 62 | Expires: 63 | - '0' 64 | Pragma: 65 | - no-cache 66 | Server: 67 | - cloudflare 68 | Set-Cookie: 69 | - __cfduid=dfd10e88724e9d675d90bf9ddfc1289841616733180; expires=Sun, 25-Apr-21 70 | 04:33:00 GMT; path=/; domain=.aftership.com; HttpOnly; SameSite=Lax 71 | Strict-Transport-Security: 72 | - max-age=15552000; includeSubDomains 73 | Surrogate-Control: 74 | - no-store 75 | Transfer-Encoding: 76 | - chunked 77 | Vary: 78 | - Accept-Encoding 79 | X-RateLimit-Limit: 80 | - '10' 81 | X-RateLimit-Remaining: 82 | - '9' 83 | X-RateLimit-Reset: 84 | - '1616733182' 85 | X-Response-Time: 86 | - 81.675ms 87 | cf-request-id: 88 | - 090e67ab19000021a659b34000000001 89 | p3p: 90 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 91 | status: 92 | code: 200 93 | message: OK 94 | version: 1 95 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/TrackingWithAdditionalFieldsTestCase.test_get_tracking_with_internal_error.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | User-Agent: 12 | - python-requests/2.25.1 13 | aftership-api-key: 14 | - YOUR_API_KEY_IS_HERE 15 | method: GET 16 | uri: https://api.aftership.com/v4/trackings/postnl-3s/3SKAAG5995399?tracking_postal_code=46970&tracking_destination_country=ESP 17 | response: 18 | body: 19 | string: 20 | Interal Error 21 | headers: 22 | Access-Control-Allow-Credentials: 23 | - 'true' 24 | Access-Control-Allow-Headers: 25 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key,aftership-agent,request-id 26 | Access-Control-Allow-Methods: 27 | - GET,OPTIONS 28 | Access-Control-Allow-Origin: 29 | - '*' 30 | CF-Cache-Status: 31 | - DYNAMIC 32 | CF-RAY: 33 | - 66e02f79fd00197f-HKG 34 | Cache-Control: 35 | - no-store, no-cache, must-revalidate, proxy-revalidate 36 | Connection: 37 | - keep-alive 38 | Content-Type: 39 | - text/plain; charset=utf-8 40 | Date: 41 | - Tue, 13 Jul 2021 05:42:00 GMT 42 | Expect-CT: 43 | - max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" 44 | Expires: 45 | - '0' 46 | Pragma: 47 | - no-cache 48 | Server: 49 | - cloudflare 50 | Strict-Transport-Security: 51 | - max-age=15552000; includeSubDomains 52 | Surrogate-Control: 53 | - no-store 54 | Transfer-Encoding: 55 | - chunked 56 | Vary: 57 | - Accept-Encoding 58 | Via: 59 | - 1.1 google 60 | X-RateLimit-Limit: 61 | - '10' 62 | X-RateLimit-Remaining: 63 | - '9' 64 | X-RateLimit-Reset: 65 | - '1626154921' 66 | X-Response-Time: 67 | - 120.323ms 68 | p3p: 69 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 70 | status: 71 | code: 502 72 | message: InternalError 73 | version: 1 74 | -------------------------------------------------------------------------------- /tests/fixtures/cassettes/TrackingWithAdditionalFieldsTestCase.test_update_tracking.yaml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: '{"tracking": {"title": "new title"}}' 4 | headers: 5 | Accept: 6 | - '*/*' 7 | Accept-Encoding: 8 | - gzip, deflate 9 | Connection: 10 | - keep-alive 11 | Content-Length: 12 | - '36' 13 | Content-Type: 14 | - application/json 15 | User-Agent: 16 | - python-requests/2.25.1 17 | aftership-api-key: 18 | - YOUR_API_KEY_IS_HERE 19 | method: PUT 20 | uri: https://api.aftership.com/v4/trackings/wuuxyb7ohjx55kmpt5r7y017 21 | response: 22 | body: 23 | string: !!binary | 24 | H4sIAAAAAAAAA+1XbW/bNhD+K4S+1kkoy7JnfQvQoihWBMXsTysKgZbOFieJ1PhSxwv833e0qBfH 25 | SdNhGBoU+yYdj8e75x6SDx+CGgwLkocgkzkEyZTS4yTIWWszimUlFzv3zfMgCfbW3h82C1n8cR/H 26 | Zd2YWC0ONFwEkyBTwAzkKTPoN6XT8IpGV9P5ms6SaJrQ+A2lCaXoaJv8WccooVHvWDFt0u/27nJN 27 | ha03oNA7Wv16e/s+Xi7jaLlED11ZrCRopDaiuoo0mlhm+Fcs2ygL+CdyJV2dn79gPVYbWadbDlWu 28 | g0TYquqMoFLBauiMOVQYRB1Sw50xdhZtuGCGS5Fm0gqDg1zLCFd/t/rkwJJWcQzzoiPUjFe6zQju 29 | G8gcFt2CXQJceg8hTZ+VVDku4Ko5/08bZopzo0N4sPAdv0jm7uNbB2DBmxqEwRBZyXbQenUzh1Ge 30 | lbbxUYeeTdfhL65n8eINDdue9VN6CMep9KPm0Fwa98B3BS4eXofzC3NqBXeEKXduFb4TiNqmx0vX 31 | GjxiGhuRuTRZwx2JmGPIB7FWTGiMgA5288iYUjrrB9IatEYo0OFWKawhJ8yQUVuJR9IF56ZyjgL2 32 | pP32rMXkPJKhZ33NK0h7RmvbNFJh5zuiVkzs7GnVtiCs9k+LE2QJAhfIoVGQuW3jqFZAVjaSC+NK 33 | fnhqF2Tc9Ni8sI3nw+6U2anAfqJnzHhnDOCsfH9IR+IJ2VhDkLDkAIawAbtPmNjdx2AI2FKwDdi1 34 | Yit/gwzclPMWDXbsUvhUl5wPGU0e4PHbdyiarsNZMl0m08U1pfT3U0q4YVxje/qYEV//4k33qdg+ 35 | PeXkfo+T/1H/56jH89eIOp6EE3IHpgCFmzDXweMW+KPyiR4oXz7ZHJ6D20/+zlPoGaTJMO0lmLHK 36 | 6FWS+6eBGS+9RXvp/WQwF0yTDYAgur2ZfjjG84TOXiXG71YTsmoYF5fothrvWyTmvYAgcjvWFZeA 37 | t8H+UwXzjSbEa4pn9hKr/5dN+HJKTGeKbxDosVQbrGNVrMBYJVD7pBpE7oT/llUaOm3bKFlzPRLN 38 | ZxJzkO4jien16+Or1pvHGruT8b1Sq7goEZXCmCa5udnv99ctk65FdfMV8TCF5foGwdlyhTKPGQP4 39 | iPKEOo+pIOdIA+Nj+pu4W4hlp670j51Hw+cq/mL4iWfHQKDOqYTLia4aVqXtWzGYzZeLs6eXU+Fn 40 | +A4jQ++Px+PfCc2LVHYOAAA= 41 | headers: 42 | Access-Control-Allow-Credentials: 43 | - 'true' 44 | Access-Control-Allow-Headers: 45 | - Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,aftership-api-key,aftership-agent,request-id 46 | Access-Control-Allow-Methods: 47 | - GET,OPTIONS 48 | Access-Control-Allow-Origin: 49 | - '*' 50 | CF-Cache-Status: 51 | - DYNAMIC 52 | CF-RAY: 53 | - 635da8928975d19b-HKG 54 | Cache-Control: 55 | - no-store, no-cache, must-revalidate, proxy-revalidate 56 | Connection: 57 | - keep-alive 58 | Content-Encoding: 59 | - gzip 60 | Content-Type: 61 | - application/json; charset=utf-8 62 | Date: 63 | - Fri, 26 Mar 2021 04:33:04 GMT 64 | Expect-CT: 65 | - max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" 66 | Expires: 67 | - '0' 68 | Pragma: 69 | - no-cache 70 | Server: 71 | - cloudflare 72 | Set-Cookie: 73 | - __cfduid=d0f5cc2c337e4fb83b09422d5ba225b6f1616733181; expires=Sun, 25-Apr-21 74 | 04:33:01 GMT; path=/; domain=.aftership.com; HttpOnly; SameSite=Lax 75 | Strict-Transport-Security: 76 | - max-age=15552000; includeSubDomains 77 | Surrogate-Control: 78 | - no-store 79 | Transfer-Encoding: 80 | - chunked 81 | Vary: 82 | - Accept-Encoding 83 | X-RateLimit-Limit: 84 | - '10' 85 | X-RateLimit-Remaining: 86 | - '9' 87 | X-RateLimit-Reset: 88 | - '1616733184' 89 | X-Response-Time: 90 | - 222.650ms 91 | cf-request-id: 92 | - 090e67afc70000d19b2ab50000000001 93 | p3p: 94 | - 'CP="AfterShip does not have a P3P policy. Learn why here: https://www.aftership.com/p3p"' 95 | status: 96 | code: 200 97 | message: OK 98 | version: 1 99 | -------------------------------------------------------------------------------- /tests/test_couriers.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import pytest 4 | 5 | from aftership import courier 6 | 7 | 8 | class CourierTestCase(TestCase): 9 | @pytest.mark.vcr() 10 | def test_get_couriers(self): 11 | resp = courier.list_couriers() 12 | self.assertIn('total', resp) 13 | self.assertIn('couriers', resp) 14 | 15 | @pytest.mark.vcr() 16 | def test_get_all_couriers(self): 17 | resp = courier.list_all_couriers() 18 | self.assertIn('total', resp) 19 | self.assertIn('couriers', resp) 20 | 21 | @pytest.mark.vcr() 22 | def test_detect_courier(self): 23 | resp = courier.detect_courier(tracking={'tracking_number': '1234567890'}) 24 | self.assertIn('total', resp) 25 | self.assertIn('couriers', resp) 26 | -------------------------------------------------------------------------------- /tests/test_estimated_delivery_date.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import pytest 4 | 5 | from aftership import estimated_delivery_date 6 | 7 | 8 | class EstimatedDeliveryDateTestCase(TestCase): 9 | @pytest.mark.vcr() 10 | def test_batch_predict_estimated_delivery_date(self): 11 | resp = estimated_delivery_date.batch_predict_estimated_delivery_date( 12 | estimated_delivery_dates=[ 13 | { 14 | "slug": "fedex", 15 | "service_type_name": "FEDEX HOME DELIVERY", 16 | "origin_address": { 17 | "country": "USA", 18 | "state": "WA", 19 | "postal_code": "98108", 20 | "raw_location": "Seattle, Washington, 98108, USA, United States" 21 | }, 22 | "destination_address": { 23 | "country": "USA", 24 | "state": "CA", 25 | "postal_code": "92019", 26 | "raw_location": "El Cajon, California, 92019, USA, United States" 27 | }, 28 | "weight": { 29 | "unit": "kg", 30 | "value": 11 31 | }, 32 | "package_count": 1, 33 | "pickup_time": "2021-07-01 15:00:00", 34 | "estimated_pickup": { 35 | "order_processing_time": {}, 36 | "pickup_time": "" 37 | } 38 | } 39 | ]) 40 | print(resp) 41 | -------------------------------------------------------------------------------- /tests/test_notifications.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import pytest 4 | 5 | import aftership 6 | 7 | 8 | class NotificationTestCase(TestCase): 9 | @pytest.mark.vcr() 10 | def test_list_notification(self): 11 | response = aftership.notification.list_notifications(tracking_id='k5lh7dy7vvqeck71p5loe011') 12 | 13 | @pytest.mark.vcr() 14 | def test_add_notification(self): 15 | response = aftership.notification.add_notification(tracking_id='k5lh7dy7vvqeck71p5loe011', 16 | notification={'emails': ['jk.zhang@aftership.com']}) 17 | 18 | @pytest.mark.vcr() 19 | def test_remove_notification(self): 20 | response = aftership.notification.remove_notification(tracking_id='k5lh7dy7vvqeck71p5loe011', 21 | notification={'emails': ['support@aftership.com']}) 22 | -------------------------------------------------------------------------------- /tests/test_trackings.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase, mock 2 | 3 | import pytest 4 | 5 | import aftership 6 | from requests import Response 7 | 8 | 9 | class TrackingTestCase(TestCase): 10 | def setUp(self): 11 | self.slug = '4px' 12 | self.tracking_number = 'HH19260817' 13 | self.tracking_id = 'k5lh7dy7vvqeck71p5loe011' 14 | 15 | @pytest.mark.vcr() 16 | def test_create_tracking(self): 17 | response = aftership.tracking.create_tracking(tracking={'slug': self.slug, 18 | 'tracking_number': self.tracking_number}) 19 | 20 | @pytest.mark.vcr() 21 | def test_get_tracking(self): 22 | response = aftership.tracking.get_tracking(slug=self.slug, 23 | tracking_number=self.tracking_number) 24 | 25 | # @pytest.mark.vcr() 26 | # def test_delete_tracking(self): 27 | # response = aftership.tracking.delete_tracking(slug='china-ems',tracking_number='1234567890') 28 | 29 | @pytest.mark.vcr() 30 | def test_list_trackings(self): 31 | response = aftership.tracking.list_trackings(slug=self.slug, limit=1) 32 | 33 | @pytest.mark.vcr() 34 | def test_update_tracking(self): 35 | response = aftership.tracking.update_tracking(tracking_id=self.tracking_id, 36 | tracking={'title': 'new title'}) 37 | 38 | @pytest.mark.vcr() 39 | def test_retrack(self): 40 | response = aftership.tracking.retrack(tracking_id=self.tracking_id) 41 | 42 | @pytest.mark.vcr() 43 | def test_get_last_checkpoint(self): 44 | response = aftership.tracking.get_last_checkpoint(tracking_id=self.tracking_id) 45 | 46 | 47 | class TrackingWithAdditionalFieldsTestCase(TestCase): 48 | def setUp(self): 49 | self.tracking_id = 'wuuxyb7ohjx55kmpt5r7y017' 50 | self.slug = 'postnl-3s' 51 | self.tracking_number = '3SKAAG5995399' 52 | self.destination_country = 'ESP' 53 | self.postal_code = '46970' 54 | 55 | @pytest.mark.vcr() 56 | def test_create_tracking(self): 57 | response = aftership.tracking.create_tracking(tracking={'slug': self.slug, 58 | 'tracking_number': self.tracking_number, 59 | 'tracking_destination_country': self.destination_country, 60 | 'tracking_postal_code': self.postal_code, 61 | }) 62 | 63 | @pytest.mark.vcr() 64 | def test_get_tracking(self): 65 | response = aftership.tracking.get_tracking(slug=self.slug, 66 | tracking_number=self.tracking_number, 67 | tracking_destination_country=self.destination_country, 68 | tracking_postal_code=self.postal_code) 69 | 70 | @pytest.mark.vcr() 71 | def test_get_tracking_by_id(self): 72 | response = aftership.tracking.get_tracking(tracking_id=self.tracking_id) 73 | 74 | @pytest.mark.vcr() 75 | def test_update_tracking(self): 76 | response = aftership.tracking.update_tracking(tracking_id=self.tracking_id, 77 | tracking={'title': 'new title'}) 78 | 79 | @pytest.mark.vcr() 80 | def test_get_last_checkpoint(self): 81 | response = aftership.tracking.get_last_checkpoint(tracking_id=self.tracking_id) 82 | 83 | @pytest.mark.vcr() 84 | def test_get_tracking_with_internal_error(self): 85 | with self.assertRaises(aftership.exception.InternalError): 86 | response = aftership.tracking.get_tracking(slug=self.slug, 87 | tracking_number=self.tracking_number, 88 | tracking_destination_country=self.destination_country, 89 | tracking_postal_code=self.postal_code) 90 | -------------------------------------------------------------------------------- /tests/test_util.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import aftership 4 | from aftership.util import get_api_key 5 | 6 | 7 | class UtilsTestCase(TestCase): 8 | def test_get_key(self): 9 | api_key = '12345678' 10 | aftership.api_key = api_key 11 | self.assertEqual(aftership.api_key, api_key) 12 | self.assertEqual(aftership.api_key, get_api_key()) 13 | --------------------------------------------------------------------------------