From a821496a57d7cf9e328c05978e3a90bae85603c3 Mon Sep 17 00:00:00 2001
From: Serj Zavadsky
Date: Tue, 12 Apr 2022 12:44:50 +0200
Subject: [PATCH] chore: docs updated
---
README.md | 36 ++++-
docs/api/base.html | 50 ++++---
docs/api/common.html | 47 ++++---
docs/api/my_profile.html | 94 ++++++-------
docs/api/user_panel.html | 205 +++++++++++++++++++++++-----
docs/exceptions.html | 38 +++++-
docs/index.html | 24 +---
docs/main.html | 62 ++++++++-
docs/types.html | 67 ++++++++-
push_to_3yourmind/__init__.py | 11 --
push_to_3yourmind/api/base.py | 19 +--
push_to_3yourmind/api/common.py | 10 +-
push_to_3yourmind/api/my_profile.py | 18 +--
push_to_3yourmind/api/user_panel.py | 47 +++++--
push_to_3yourmind/exceptions.py | 8 +-
push_to_3yourmind/main.py | 17 +++
push_to_3yourmind/types.py | 27 +++-
17 files changed, 568 insertions(+), 212 deletions(-)
diff --git a/README.md b/README.md
index 0080a19..c90bfdc 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
# push-to-3yourmind
+
A Python SDK library to work with 3YOURMIND's platform API. It enables you to manage user profile
information, push 3D Files, manipulate baskets, lines, get pricing information, place Orders
and Catalog Items.
@@ -19,13 +20,19 @@ Open `/admin/auth/user/`, and click "Create token" in the user list.
## Usage
+### First, initialize API class
+
```python
from push_to_3yourmind import PushTo3YourmindAPI
client = PushTo3YourmindAPI(
access_token="QWERTY123456789",
base_url="http://",
)
+```
+### Get or set current user's info
+
+```python
profile_info = client.my_profile.get_profile()
my_preferences = client.my_profile.get_preferences()
client.my_profile.set_preferences(currency="USD", language="de")
@@ -33,17 +40,44 @@ client.my_profile.set_preferences(currency="USD", language="de")
client.my_profile.set_preferences(language="en")
# or
client.my_profile.set_preferences(unit="inch")
+```
+
+### Explore User Panel's API
+```python
# get current user's basket list
baskets = client.user_panel.get_baskets()
# or
basket = client.user_panel.get_basket(basket_id=6)
+```
+### Do more with a single API call
+
+```python
+client.user_panel.create_line_with_cad_file_and_product(
+ basket_id=4,
+ cad_file="/path/to/the/cad_file.stl",
+ product_id=3,
+ quantity=1,
+)
```
# Usage Guide
-[link](https://3yourmind.github.io/push-to-3yourmind/)
+[Creating a basket, placing an order](https://3yourmind.github.io/push-to-3yourmind/api/user_panel.html)
+
+[User profile management](https://3yourmind.github.io/push-to-3yourmind/api/my_profile.html)
+
+[Common API](https://3yourmind.github.io/push-to-3yourmind/api/common.html)
+
+[there is more](https://3yourmind.github.io/push-to-3yourmind/)
+
+
+# Documentation generation
+
+ poetry install
+ poetry shell
+ make documentation
# @
diff --git a/docs/api/base.html b/docs/api/base.html
index 535863a..13c5a1d 100644
--- a/docs/api/base.html
+++ b/docs/api/base.html
@@ -41,14 +41,15 @@
Module push_to_3yourmind.api.base
class BaseAPI:
"""
- Base class for all namespaced API methods.
+ Base class for all namespaced API methods. Not to be instantiated directly.
"""
def __init__(self, access_token: str, base_url: str):
"""
-
- :param access_token:
- :param base_url:
+ Args:
+ access_token: to create a token, open `/admin/auth/user/`, and click
+ "Create token" in the user list.
+ base_url: application URL, ex. https://app.3yourmind.com
"""
self._api_prefix = "api/v2.0"
self._access_token = access_token
@@ -109,12 +110,14 @@
class BaseAPI:
"""
- Base class for all namespaced API methods.
+ Base class for all namespaced API methods. Not to be instantiated directly.
"""
def __init__(self, access_token: str, base_url: str):
"""
-
- :param access_token:
- :param base_url:
+ Args:
+ access_token: to create a token, open `/admin/auth/user/`, and click
+ "Create token" in the user list.
+ base_url: application URL, ex. https://app.3yourmind.com
"""
self._api_prefix = "api/v2.0"
self._access_token = access_token
@@ -219,12 +229,14 @@
class CommonAPI(BaseAPI):
+ """
+ API methods common to all panels.
+
+ Accessible via namespace `common`, for example:
+ >>> response = client.common.get_colors()
+ """
+
def get_colors(self) -> t.List[types.ResponseDict]:
return self._request("GET", "colors/")
@@ -43,21 +50,18 @@
Module push_to_3yourmind.api.common
"""
Get list of units of measure available on the platform.
Currently, "mm" and "inch".
- :return:
"""
return self._request("GET", "units/")
def get_countries(self) -> t.List[types.ResponseDict]:
"""
Get list of countries with codes and full names
- :return:
"""
return self._request("GET", "countries/")
def get_currencies(self) -> t.List[str]:
"""
Get list of currencies available on the platform
- :return:
"""
return self._request("GET", "currencies/")
@@ -82,14 +86,30 @@
Classes
(access_token: str, base_url: str)
-
Base class for all namespaced API methods.
-
:param access_token:
-:param base_url:
+
API methods common to all panels.
+
Accessible via namespace common, for example:
+
>>> response = client.common.get_colors()
+
+
Args
+
+
access_token
+
to create a token, open /admin/auth/user/, and click
+"Create token" in the user list.
class CommonAPI(BaseAPI):
+ """
+ API methods common to all panels.
+
+ Accessible via namespace `common`, for example:
+ >>> response = client.common.get_colors()
+ """
+
def get_colors(self) -> t.List[types.ResponseDict]:
return self._request("GET", "colors/")
@@ -97,21 +117,18 @@
Classes
"""
Get list of units of measure available on the platform.
Currently, "mm" and "inch".
- :return:
"""
return self._request("GET", "units/")
def get_countries(self) -> t.List[types.ResponseDict]:
"""
Get list of countries with codes and full names
- :return:
"""
return self._request("GET", "countries/")
def get_currencies(self) -> t.List[str]:
"""
Get list of currencies available on the platform
- :return:
"""
return self._request("GET", "currencies/")
@@ -145,8 +162,7 @@
Methods
Get list of units of measure available on the platform.
-Currently, "mm" and "inch".
-:return:
+Currently, "mm" and "inch".
Expand source code
@@ -155,7 +171,6 @@
Methods
"""
Get list of units of measure available on the platform.
Currently, "mm" and "inch".
- :return:
"""
return self._request("GET", "units/")
@@ -164,8 +179,7 @@
Methods
def get_countries(self) ‑> List[Dict[str, Any]]
-
Get list of countries with codes and full names
-:return:
+
Get list of countries with codes and full names
Expand source code
@@ -173,7 +187,6 @@
Methods
def get_countries(self) -> t.List[types.ResponseDict]:
"""
Get list of countries with codes and full names
- :return:
"""
return self._request("GET", "countries/")
@@ -182,8 +195,7 @@
Methods
def get_currencies(self) ‑> List[str]
-
Get list of currencies available on the platform
-:return:
+
Get list of currencies available on the platform
Expand source code
@@ -191,7 +203,6 @@
Methods
def get_currencies(self) -> t.List[str]:
"""
Get list of currencies available on the platform
- :return:
"""
return self._request("GET", "currencies/")
def get_preferences(self) -> types.ResponseDict:
"""
Get preferences of the current user: country, currency, language, unit
-
- :return:
"""
return self._request("GET", "my-profile/preferences/")
@@ -57,11 +55,11 @@
Module push_to_3yourmind.api.my_profile
Update profile of the current user. All arguments are optional, only passed
values will be saved to the profile.
- :param country: 2-letter country code, ex. US, FR, GB
- :param currency: 3-letter currency code, ex. USD, EUR
- :param language: 2-letter language code, ex. en, de, fr, es
- :param unit: mm or inch
- :return:
+ Args:
+ country: 2-letter country code, ex. US, FR, GB
+ currency: 3-letter currency code, ex. USD, EUR
+ language: 2-letter language code, ex. en, de, fr, es
+ unit: mm or inch
"""
json = self._get_parameters(
@@ -72,8 +70,6 @@
Module push_to_3yourmind.api.my_profile
def get_profile(self) -> types.ResponseDict:
"""
Get profile of the current user: name, default address, access roles etc.
-
- :return:
"""
return self._request("GET", "my-profile/profile/")
@@ -81,8 +77,6 @@
Module push_to_3yourmind.api.my_profile
def get_addresses(self) -> t.List[types.ResponseDict]:
"""
Get a list of current user's addresses
-
- :return:
"""
return self._request("GET", "my-profile/addresses/")
@@ -90,8 +84,6 @@
Module push_to_3yourmind.api.my_profile
def get_address(self, *, address_id: int) -> types.ResponseDict:
"""
Get specific address of the current user
-
- :return:
"""
return self._request("GET", f"my-profile/addresses/{address_id}/")
@@ -111,9 +103,15 @@
Classes
(access_token: str, base_url: str)
-
Base class for all namespaced API methods.
-
:param access_token:
-:param base_url:
+
Base class for all namespaced API methods. Not to be instantiated directly.
+
Args
+
+
access_token
+
to create a token, open /admin/auth/user/, and click
+"Create token" in the user list.
def get_preferences(self) -> types.ResponseDict:
"""
Get preferences of the current user: country, currency, language, unit
-
- :return:
"""
return self._request("GET", "my-profile/preferences/")
@@ -140,11 +136,11 @@
Classes
Update profile of the current user. All arguments are optional, only passed
values will be saved to the profile.
- :param country: 2-letter country code, ex. US, FR, GB
- :param currency: 3-letter currency code, ex. USD, EUR
- :param language: 2-letter language code, ex. en, de, fr, es
- :param unit: mm or inch
- :return:
+ Args:
+ country: 2-letter country code, ex. US, FR, GB
+ currency: 3-letter currency code, ex. USD, EUR
+ language: 2-letter language code, ex. en, de, fr, es
+ unit: mm or inch
"""
json = self._get_parameters(
@@ -155,8 +151,6 @@
Classes
def get_profile(self) -> types.ResponseDict:
"""
Get profile of the current user: name, default address, access roles etc.
-
- :return:
"""
return self._request("GET", "my-profile/profile/")
@@ -164,8 +158,6 @@
Classes
def get_addresses(self) -> t.List[types.ResponseDict]:
"""
Get a list of current user's addresses
-
- :return:
"""
return self._request("GET", "my-profile/addresses/")
@@ -173,8 +165,6 @@
Classes
def get_address(self, *, address_id: int) -> types.ResponseDict:
"""
Get specific address of the current user
-
- :return:
"""
return self._request("GET", f"my-profile/addresses/{address_id}/")
@@ -189,8 +179,7 @@
Methods
def get_preferences(self) ‑> Dict[str, Any]
-
Get preferences of the current user: country, currency, language, unit
-
:return:
+
Get preferences of the current user: country, currency, language, unit
Expand source code
@@ -198,8 +187,6 @@
Methods
def get_preferences(self) -> types.ResponseDict:
"""
Get preferences of the current user: country, currency, language, unit
-
- :return:
"""
return self._request("GET", "my-profile/preferences/")
@@ -211,11 +198,17 @@
Methods
Update profile of the current user. All arguments are optional, only passed
values will be saved to the profile.
-
:param country: 2-letter country code, ex. US, FR, GB
-:param currency: 3-letter currency code, ex. USD, EUR
-:param language: 2-letter language code, ex. en, de, fr, es
-:param unit: mm or inch
-:return:
+
Args
+
+
country
+
2-letter country code, ex. US, FR, GB
+
currency
+
3-letter currency code, ex. USD, EUR
+
language
+
2-letter language code, ex. en, de, fr, es
+
unit
+
mm or inch
+
Expand source code
@@ -232,11 +225,11 @@
Methods
Update profile of the current user. All arguments are optional, only passed
values will be saved to the profile.
- :param country: 2-letter country code, ex. US, FR, GB
- :param currency: 3-letter currency code, ex. USD, EUR
- :param language: 2-letter language code, ex. en, de, fr, es
- :param unit: mm or inch
- :return:
+ Args:
+ country: 2-letter country code, ex. US, FR, GB
+ currency: 3-letter currency code, ex. USD, EUR
+ language: 2-letter language code, ex. en, de, fr, es
+ unit: mm or inch
"""
json = self._get_parameters(
@@ -249,8 +242,7 @@
Methods
def get_profile(self) ‑> Dict[str, Any]
-
Get profile of the current user: name, default address, access roles etc.
-
:return:
+
Get profile of the current user: name, default address, access roles etc.
Expand source code
@@ -258,8 +250,6 @@
Methods
def get_profile(self) -> types.ResponseDict:
"""
Get profile of the current user: name, default address, access roles etc.
-
- :return:
"""
return self._request("GET", "my-profile/profile/")
@@ -269,8 +259,7 @@
Methods
def get_addresses(self) ‑> List[Dict[str, Any]]
-
Get a list of current user's addresses
-
:return:
+
Get a list of current user's addresses
Expand source code
@@ -278,8 +267,6 @@
Methods
def get_addresses(self) -> t.List[types.ResponseDict]:
"""
Get a list of current user's addresses
-
- :return:
"""
return self._request("GET", "my-profile/addresses/")
def get_address(self, *, address_id: int) -> types.ResponseDict:
"""
Get specific address of the current user
-
- :return:
"""
return self._request("GET", f"my-profile/addresses/{address_id}/")
"""
Groups API functionality from the User Panel, such as creating/updating baskets,
placing orders, making requests for quotes, ordering quotes etc.
+
+ Accessible via namespace `user_panel`, for example:
+ >>> response = client.user_panel.get_baskets()
+
+ Attributes:
+ CHECK_FILE_STATUS_MAX_ATTEMPTS: How many times to check for the uploaded CAD file analysis status
+ CHECK_FILE_STATUS_DELAY: Delay between status check requests, in seconds
"""
CHECK_FILE_STATUS_MAX_ATTEMPTS = 60
@@ -61,20 +68,30 @@
Module push_to_3yourmind.api.user_panel
"""
Get all baskets of the current user. Returns paginated list.
- :param page: int, optional
- :param page_size: int, optional
- :return: dictionary with the following keys:
- count: total number of baskets
- currentPage:
- totalPages:
- pageSize: baskets per page
- results: list of basket details
+ Args:
+ page: int, optional
+ page_size: int, optional
+ Returns:
+ dictionary with the following keys:
+
+ - count: total number of baskets, int
+ - currentPage: page number, int
+ - totalPages: total number of pages, int
+ - pageSize: baskets per page, int
+ - results: list of basket details
"""
query = self._get_parameters(page=page, pageSize=page_size)
return self._request("GET", "user-panel/baskets/", params=query)
def get_basket(self, *, basket_id: int) -> types.ResponseDict:
+ """
+ Args:
+ basket_id: int
+
+ Returns:
+ Basket details dict
+ """
return self._request("GET", f"user-panel/baskets/{basket_id}/")
def get_basket_price(
@@ -87,6 +104,20 @@
"""
Groups API functionality from the User Panel, such as creating/updating baskets,
placing orders, making requests for quotes, ordering quotes etc.
+
+ Accessible via namespace `user_panel`, for example:
+ >>> response = client.user_panel.get_baskets()
+
+ Attributes:
+ CHECK_FILE_STATUS_MAX_ATTEMPTS: How many times to check for the uploaded CAD file analysis status
+ CHECK_FILE_STATUS_DELAY: Delay between status check requests, in seconds
"""
CHECK_FILE_STATUS_MAX_ATTEMPTS = 60
@@ -444,20 +498,30 @@
Classes
"""
Get all baskets of the current user. Returns paginated list.
- :param page: int, optional
- :param page_size: int, optional
- :return: dictionary with the following keys:
- count: total number of baskets
- currentPage:
- totalPages:
- pageSize: baskets per page
- results: list of basket details
+ Args:
+ page: int, optional
+ page_size: int, optional
+ Returns:
+ dictionary with the following keys:
+
+ - count: total number of baskets, int
+ - currentPage: page number, int
+ - totalPages: total number of pages, int
+ - pageSize: baskets per page, int
+ - results: list of basket details
"""
query = self._get_parameters(page=page, pageSize=page_size)
return self._request("GET", "user-panel/baskets/", params=query)
def get_basket(self, *, basket_id: int) -> types.ResponseDict:
+ """
+ Args:
+ basket_id: int
+
+ Returns:
+ Basket details dict
+ """
return self._request("GET", f"user-panel/baskets/{basket_id}/")
def get_basket_price(
@@ -470,6 +534,20 @@
Get all baskets of the current user. Returns paginated list.
-
:param page: int, optional
-:param page_size: int, optional
-:return: dictionary with the following keys:
-count: total number of baskets
-currentPage:
-totalPages:
-pageSize: baskets per page
-results: list of basket details
+
Args
+
+
page
+
int, optional
+
page_size
+
int, optional
+
+
Returns
+
dictionary with the following keys:
+
+
count: total number of baskets, int
+
currentPage: page number, int
+
totalPages: total number of pages, int
+
pageSize: baskets per page, int
+
results: list of basket details
+
Expand source code
@@ -829,14 +915,17 @@
Methods
"""
Get all baskets of the current user. Returns paginated list.
- :param page: int, optional
- :param page_size: int, optional
- :return: dictionary with the following keys:
- count: total number of baskets
- currentPage:
- totalPages:
- pageSize: baskets per page
- results: list of basket details
+ Args:
+ page: int, optional
+ page_size: int, optional
+ Returns:
+ dictionary with the following keys:
+
+ - count: total number of baskets, int
+ - currentPage: page number, int
+ - totalPages: total number of pages, int
+ - pageSize: baskets per page, int
+ - results: list of basket details
"""
query = self._get_parameters(page=page, pageSize=page_size)
@@ -847,12 +936,25 @@
class ObjectNotFound(BasePushTo3YourmindAPIException):
- """
- Is raised when an API endpoint response is 404 - Object Not Found
- """
+ pass
class Unauthorized(BasePushTo3YourmindAPIException):
pass
+class AccessDenied(BasePushTo3YourmindAPIException):
+ pass
+
+
class BadRequest(BasePushTo3YourmindAPIException):
pass
@@ -109,6 +111,7 @@
Structurally client API is a class that is initialized with user's API token and the
-base URL.
-
from push_to_3yourmind import PushTo3YourmindAPI
-client = PushTo3YourmindAPI(access_token="QWERTY123456789", base_url="http://<domain-name>")
-
-
Functionality is divided into namespaces, for example my_profile, user_panel etc.
Expand source code
-
"""
-Structurally client API is a class that is initialized with user's API token and the
-base URL.
-
-```python
-from push_to_3yourmind import PushTo3YourmindAPI
-client = PushTo3YourmindAPI(access_token="QWERTY123456789", base_url="http://<domain-name>")
-```
-
-Functionality is divided into namespaces, for example `my_profile`, `user_panel` etc.
-"""
-from .main import PushTo3YourmindAPI
class PushTo3YourmindAPI(BaseAPI):
+ """
+ The main class and the entrypoint for API
+
+ >>> from push_to_3yourmind import PushTo3YourmindAPI
+ >>> client = PushTo3YourmindAPI(access_token="QWERTY123456789", base_url="http://<domain-name>")
+
+ Functionality is divided into namespaces, for example `my_profile`, `user_panel` etc. Some
+ API endpoints require proper user permissions, in case when an API can't be reached, an exception
+ AccessDenied is raised.
+
+ Attributes:
+ user_panel: order management-related API: create/update basket lines,
+ upload CAD files, pricing
+ common: common API: country, unit, material lists
+ my_profile: API to manage user's preferences, profile, address list etc
+ """
+
def __init__(self, access_token: str, base_url: str):
super().__init__(access_token, base_url)
self.user_panel = UserPanelAPI(access_token, base_url)
@@ -57,14 +74,53 @@
Functionality is divided into namespaces, for example my_profile, user_panel etc. Some
+API endpoints require proper user permissions, in case when an API can't be reached, an exception
+AccessDenied is raised.
+
Attributes
+
+
user_panel
+
order management-related API: create/update basket lines,
+upload CAD files, pricing
+
common
+
common API: country, unit, material lists
+
my_profile
+
API to manage user's preferences, profile, address list etc
+
+
Args
+
+
access_token
+
to create a token, open /admin/auth/user/, and click
+"Create token" in the user list.
class PushTo3YourmindAPI(BaseAPI):
+ """
+ The main class and the entrypoint for API
+
+ >>> from push_to_3yourmind import PushTo3YourmindAPI
+ >>> client = PushTo3YourmindAPI(access_token="QWERTY123456789", base_url="http://<domain-name>")
+
+ Functionality is divided into namespaces, for example `my_profile`, `user_panel` etc. Some
+ API endpoints require proper user permissions, in case when an API can't be reached, an exception
+ AccessDenied is raised.
+
+ Attributes:
+ user_panel: order management-related API: create/update basket lines,
+ upload CAD files, pricing
+ common: common API: country, unit, material lists
+ my_profile: API to manage user's preferences, profile, address list etc
+ """
+
def __init__(self, access_token: str, base_url: str):
super().__init__(access_token, base_url)
self.user_panel = UserPanelAPI(access_token, base_url)
diff --git a/docs/types.html b/docs/types.html
index 29eb125..86a1e16 100644
--- a/docs/types.html
+++ b/docs/types.html
@@ -5,7 +5,7 @@
push_to_3yourmind.types API documentation
-
+
@@ -22,17 +22,43 @@
Module push_to_3yourmind.types
+
This module contains NoValue class and type aliases for type annotations
Expand source code
-
import datetime
+
"""
+This module contains NoValue class and type aliases for type annotations
+"""
+
+import datetime
import decimal
import typing as t
+__all__ = ["NoValue"]
+
+
class NoValue:
- pass
+ """
+ Some class methods accept arguments that are optional. Skipping them means
+ "no data changed" and will lead to not sending them to the 3YD API. To skip such an
+ argument give it a `NoValue` value.
+
+ For example, `client.my_profile.set_preferences` can accept 4 arguments:
+ country, currency, language, unit. If you need to update user's unit but leave other
+ settings unchanged:
+
+ >>> client.my_profile.set_preferences(unit="inch", country=NoValue, currency=NoValue, language=NoValue)
+ # or shorter
+ >>> client.my_profile.set_preferences(unit="inch")
+
+ The following:
+
+ >>> client.my_profile.set_preferences(unit="inch", country=None, currency=None, language=None)
+
+ ... it will mean that you want to set user's country, currency and language setting to NULL.
+ """
ResponseDict = t.Dict[str, t.Any]
@@ -61,13 +87,44 @@
Classes
class NoValue
-
+
Some class methods accept arguments that are optional. Skipping them means
+"no data changed" and will lead to not sending them to the 3YD API. To skip such an
+argument give it a NoValue value.
+
For example, client.my_profile.set_preferences can accept 4 arguments:
+country, currency, language, unit. If you need to update user's unit but leave other
+settings unchanged:
… it will mean that you want to set user's country, currency and language setting to NULL.
Expand source code
class NoValue:
- pass
+ """
+ Some class methods accept arguments that are optional. Skipping them means
+ "no data changed" and will lead to not sending them to the 3YD API. To skip such an
+ argument give it a `NoValue` value.
+
+ For example, `client.my_profile.set_preferences` can accept 4 arguments:
+ country, currency, language, unit. If you need to update user's unit but leave other
+ settings unchanged:
+
+ >>> client.my_profile.set_preferences(unit="inch", country=NoValue, currency=NoValue, language=NoValue)
+ # or shorter
+ >>> client.my_profile.set_preferences(unit="inch")
+
+ The following:
+
+ >>> client.my_profile.set_preferences(unit="inch", country=None, currency=None, language=None)
+
+ ... it will mean that you want to set user's country, currency and language setting to NULL.
+ """
diff --git a/push_to_3yourmind/__init__.py b/push_to_3yourmind/__init__.py
index fd5d9d9..bdc4712 100644
--- a/push_to_3yourmind/__init__.py
+++ b/push_to_3yourmind/__init__.py
@@ -1,12 +1 @@
-"""
-Structurally client API is a class that is initialized with user's API token and the
-base URL.
-
-```python
-from push_to_3yourmind import PushTo3YourmindAPI
-client = PushTo3YourmindAPI(access_token="QWERTY123456789", base_url="http://")
-```
-
-Functionality is divided into namespaces, for example `my_profile`, `user_panel` etc.
-"""
from .main import PushTo3YourmindAPI
diff --git a/push_to_3yourmind/api/base.py b/push_to_3yourmind/api/base.py
index 080cbd5..974709d 100644
--- a/push_to_3yourmind/api/base.py
+++ b/push_to_3yourmind/api/base.py
@@ -13,14 +13,15 @@
class BaseAPI:
"""
- Base class for all namespaced API methods.
+ Base class for all namespaced API methods. Not to be instantiated directly.
"""
def __init__(self, access_token: str, base_url: str):
"""
-
- :param access_token:
- :param base_url:
+ Args:
+ access_token: to create a token, open `/admin/auth/user/`, and click
+ "Create token" in the user list.
+ base_url: application URL, ex. https://app.3yourmind.com
"""
self._api_prefix = "api/v2.0"
self._access_token = access_token
@@ -81,12 +82,14 @@ def _request(
else:
response_payload = ""
- if response.status_code == 404:
- raise exceptions.ObjectNotFound(response_payload)
+ if response.status_code == 400:
+ raise exceptions.BadRequest(response_payload)
elif response.status_code == 401:
raise exceptions.Unauthorized(response_payload)
- elif response.status_code == 400:
- raise exceptions.BadRequest(response_payload)
+ elif response.status_code == 403:
+ raise exceptions.AccessDenied(response_payload)
+ elif response.status_code == 404:
+ raise exceptions.ObjectNotFound(response_payload)
elif response.status_code == 405:
raise exceptions.MethodNotAllowed(response_payload)
return response_payload
diff --git a/push_to_3yourmind/api/common.py b/push_to_3yourmind/api/common.py
index 677c80c..46c2f76 100644
--- a/push_to_3yourmind/api/common.py
+++ b/push_to_3yourmind/api/common.py
@@ -8,6 +8,13 @@
class CommonAPI(BaseAPI):
+ """
+ API methods common to all panels.
+
+ Accessible via namespace `common`, for example:
+ >>> response = client.common.get_colors()
+ """
+
def get_colors(self) -> t.List[types.ResponseDict]:
return self._request("GET", "colors/")
@@ -15,21 +22,18 @@ def get_units(self) -> t.List[types.ResponseDict]:
"""
Get list of units of measure available on the platform.
Currently, "mm" and "inch".
- :return:
"""
return self._request("GET", "units/")
def get_countries(self) -> t.List[types.ResponseDict]:
"""
Get list of countries with codes and full names
- :return:
"""
return self._request("GET", "countries/")
def get_currencies(self) -> t.List[str]:
"""
Get list of currencies available on the platform
- :return:
"""
return self._request("GET", "currencies/")
diff --git a/push_to_3yourmind/api/my_profile.py b/push_to_3yourmind/api/my_profile.py
index cce2c11..bcaad7e 100644
--- a/push_to_3yourmind/api/my_profile.py
+++ b/push_to_3yourmind/api/my_profile.py
@@ -11,8 +11,6 @@ class MyProfileAPI(BaseAPI):
def get_preferences(self) -> types.ResponseDict:
"""
Get preferences of the current user: country, currency, language, unit
-
- :return:
"""
return self._request("GET", "my-profile/preferences/")
@@ -29,11 +27,11 @@ def set_preferences(
Update profile of the current user. All arguments are optional, only passed
values will be saved to the profile.
- :param country: 2-letter country code, ex. US, FR, GB
- :param currency: 3-letter currency code, ex. USD, EUR
- :param language: 2-letter language code, ex. en, de, fr, es
- :param unit: mm or inch
- :return:
+ Args:
+ country: 2-letter country code, ex. US, FR, GB
+ currency: 3-letter currency code, ex. USD, EUR
+ language: 2-letter language code, ex. en, de, fr, es
+ unit: mm or inch
"""
json = self._get_parameters(
@@ -44,8 +42,6 @@ def set_preferences(
def get_profile(self) -> types.ResponseDict:
"""
Get profile of the current user: name, default address, access roles etc.
-
- :return:
"""
return self._request("GET", "my-profile/profile/")
@@ -53,8 +49,6 @@ def get_profile(self) -> types.ResponseDict:
def get_addresses(self) -> t.List[types.ResponseDict]:
"""
Get a list of current user's addresses
-
- :return:
"""
return self._request("GET", "my-profile/addresses/")
@@ -62,8 +56,6 @@ def get_addresses(self) -> t.List[types.ResponseDict]:
def get_address(self, *, address_id: int) -> types.ResponseDict:
"""
Get specific address of the current user
-
- :return:
"""
return self._request("GET", f"my-profile/addresses/{address_id}/")
diff --git a/push_to_3yourmind/api/user_panel.py b/push_to_3yourmind/api/user_panel.py
index e81dcfa..7176147 100644
--- a/push_to_3yourmind/api/user_panel.py
+++ b/push_to_3yourmind/api/user_panel.py
@@ -19,6 +19,13 @@ class UserPanelAPI(BaseAPI):
"""
Groups API functionality from the User Panel, such as creating/updating baskets,
placing orders, making requests for quotes, ordering quotes etc.
+
+ Accessible via namespace `user_panel`, for example:
+ >>> response = client.user_panel.get_baskets()
+
+ Attributes:
+ CHECK_FILE_STATUS_MAX_ATTEMPTS: How many times to check for the uploaded CAD file analysis status
+ CHECK_FILE_STATUS_DELAY: Delay between status check requests, in seconds
"""
CHECK_FILE_STATUS_MAX_ATTEMPTS = 60
@@ -33,20 +40,30 @@ def get_baskets(
"""
Get all baskets of the current user. Returns paginated list.
- :param page: int, optional
- :param page_size: int, optional
- :return: dictionary with the following keys:
- count: total number of baskets
- currentPage:
- totalPages:
- pageSize: baskets per page
- results: list of basket details
+ Args:
+ page: int, optional
+ page_size: int, optional
+ Returns:
+ dictionary with the following keys:
+
+ - count: total number of baskets, int
+ - currentPage: page number, int
+ - totalPages: total number of pages, int
+ - pageSize: baskets per page, int
+ - results: list of basket details
"""
query = self._get_parameters(page=page, pageSize=page_size)
return self._request("GET", "user-panel/baskets/", params=query)
def get_basket(self, *, basket_id: int) -> types.ResponseDict:
+ """
+ Args:
+ basket_id: int
+
+ Returns:
+ Basket details dict
+ """
return self._request("GET", f"user-panel/baskets/{basket_id}/")
def get_basket_price(
@@ -59,6 +76,20 @@ def get_basket_price(
shipping_method_id: types.OptionalNumber = types.NoValue,
voucher_code: types.OptionalString = types.NoValue,
) -> types.ResponseDict:
+ """
+ Calculate basket's price, given additional optional shipping, billing information
+
+ Args:
+ basket_id: int
+ currency: str
+ shipping_address_id: int, optional
+ billing_address_id: int, optional
+ shipping_method_id: int, optional
+ voucher_code: str, optional
+
+ Returns:
+ Dict containing basket prices
+ """
query = self._get_parameters(
currency=currency,
shippingAddressId=shipping_address_id,
diff --git a/push_to_3yourmind/exceptions.py b/push_to_3yourmind/exceptions.py
index 3322a7f..23d1cba 100644
--- a/push_to_3yourmind/exceptions.py
+++ b/push_to_3yourmind/exceptions.py
@@ -5,15 +5,17 @@ class BasePushTo3YourmindAPIException(Exception):
class ObjectNotFound(BasePushTo3YourmindAPIException):
- """
- Is raised when an API endpoint response is 404 - Object Not Found
- """
+ pass
class Unauthorized(BasePushTo3YourmindAPIException):
pass
+class AccessDenied(BasePushTo3YourmindAPIException):
+ pass
+
+
class BadRequest(BasePushTo3YourmindAPIException):
pass
diff --git a/push_to_3yourmind/main.py b/push_to_3yourmind/main.py
index 7dcb3e5..36f4839 100644
--- a/push_to_3yourmind/main.py
+++ b/push_to_3yourmind/main.py
@@ -8,6 +8,23 @@
class PushTo3YourmindAPI(BaseAPI):
+ """
+ The main class and the entrypoint for API
+
+ >>> from push_to_3yourmind import PushTo3YourmindAPI
+ >>> client = PushTo3YourmindAPI(access_token="QWERTY123456789", base_url="http://")
+
+ Functionality is divided into namespaces, for example `my_profile`, `user_panel` etc. Some
+ API endpoints require proper user permissions, in case when an API can't be reached, an exception
+ AccessDenied is raised.
+
+ Attributes:
+ user_panel: order management-related API: create/update basket lines,
+ upload CAD files, pricing
+ common: common API: country, unit, material lists
+ my_profile: API to manage user's preferences, profile, address list etc
+ """
+
def __init__(self, access_token: str, base_url: str):
super().__init__(access_token, base_url)
self.user_panel = UserPanelAPI(access_token, base_url)
diff --git a/push_to_3yourmind/types.py b/push_to_3yourmind/types.py
index 4abae6b..a4099e5 100644
--- a/push_to_3yourmind/types.py
+++ b/push_to_3yourmind/types.py
@@ -1,10 +1,35 @@
+"""
+This module contains NoValue class and type aliases for type annotations
+"""
+
import datetime
import decimal
import typing as t
+__all__ = ["NoValue"]
+
+
class NoValue:
- pass
+ """
+ Some class methods accept arguments that are optional. Skipping them means
+ "no data changed" and will lead to not sending them to the 3YD API. To skip such an
+ argument give it a `NoValue` value.
+
+ For example, `client.my_profile.set_preferences` can accept 4 arguments:
+ country, currency, language, unit. If you need to update user's unit but leave other
+ settings unchanged:
+
+ >>> client.my_profile.set_preferences(unit="inch", country=NoValue, currency=NoValue, language=NoValue)
+ # or shorter
+ >>> client.my_profile.set_preferences(unit="inch")
+
+ The following:
+
+ >>> client.my_profile.set_preferences(unit="inch", country=None, currency=None, language=None)
+
+ ... it will mean that you want to set user's country, currency and language setting to NULL.
+ """
ResponseDict = t.Dict[str, t.Any]