making a whole bunch of changes preparing for documentation autoupdating
Some checks failed
Pylint / Pylint (3.12) (push) Failing after 37s

This commit is contained in:
Seaswimmer 2023-12-20 17:53:00 -05:00
parent 1cbe895c3e
commit b774ecdc0a
Signed by: cswimr
GPG key ID: 1EBC234EEDA901AE
9 changed files with 204 additions and 172 deletions

View file

@ -1,3 +1,3 @@
# API Reference # API Reference
::: pyzipline.zipline ::: pyzipline.zipline.ZiplineApi

View file

@ -21,11 +21,14 @@ plugins:
- git-authors - git-authors
- search - search
- social - social
# - mkdocstrings: - mkdocstrings:
# default_handler: python default_handler: python
# handlers: handlers:
# python: python:
# paths: [pyzipline] paths: [pyzipline]
options:
docstring_options:
ignore_imit_summary: true
markdown_extensions: markdown_extensions:
- abbr - abbr

32
poetry.lock generated
View file

@ -598,6 +598,20 @@ gitdb = ">=4.0.1,<5"
[package.extras] [package.extras]
test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-instafail", "pytest-subtests", "pytest-sugar"] test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-instafail", "pytest-subtests", "pytest-sugar"]
[[package]]
name = "griffe"
version = "0.38.1"
description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API."
optional = false
python-versions = ">=3.8"
files = [
{file = "griffe-0.38.1-py3-none-any.whl", hash = "sha256:334c79d3b5964ade65c05dfcaf53518c576dedd387aaba5c9fd71212f34f1483"},
{file = "griffe-0.38.1.tar.gz", hash = "sha256:bd68d7da7f3d87bc57eb9962b250db123efd9bbcc06c11c1a91b6e583b2a9361"},
]
[package.dependencies]
colorama = ">=0.4"
[[package]] [[package]]
name = "idna" name = "idna"
version = "3.6" version = "3.6"
@ -882,6 +896,7 @@ Markdown = ">=3.3"
MarkupSafe = ">=1.1" MarkupSafe = ">=1.1"
mkdocs = ">=1.4" mkdocs = ">=1.4"
mkdocs-autorefs = ">=0.3.1" mkdocs-autorefs = ">=0.3.1"
mkdocstrings-python = {version = ">=0.5.2", optional = true, markers = "extra == \"python\""}
platformdirs = ">=2.2.0" platformdirs = ">=2.2.0"
pymdown-extensions = ">=6.3" pymdown-extensions = ">=6.3"
@ -890,6 +905,21 @@ crystal = ["mkdocstrings-crystal (>=0.3.4)"]
python = ["mkdocstrings-python (>=0.5.2)"] python = ["mkdocstrings-python (>=0.5.2)"]
python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"]
[[package]]
name = "mkdocstrings-python"
version = "1.7.5"
description = "A Python handler for mkdocstrings."
optional = false
python-versions = ">=3.8"
files = [
{file = "mkdocstrings_python-1.7.5-py3-none-any.whl", hash = "sha256:5f6246026353f0c0785135db70c3fe9a5d9318990fc7ceb11d62097b8ffdd704"},
{file = "mkdocstrings_python-1.7.5.tar.gz", hash = "sha256:c7d143728257dbf1aa550446555a554b760dcd40a763f077189d298502b800be"},
]
[package.dependencies]
griffe = ">=0.37"
mkdocstrings = ">=0.20"
[[package]] [[package]]
name = "multidict" name = "multidict"
version = "6.0.4" version = "6.0.4"
@ -1633,4 +1663,4 @@ multidict = ">=4.0"
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.10 || ^3.11 || ^3.12" python-versions = "^3.10 || ^3.11 || ^3.12"
content-hash = "4a37211d89e134df27183ed799df55662694232bcc6aef27f99f47c131186940" content-hash = "3f27e66de6ea095d7574340c1233c4c5ff13409f22d3dcb2a43829acd676be30"

View file

@ -23,7 +23,7 @@ optional = true
[tool.poetry.group.docs.dependencies] [tool.poetry.group.docs.dependencies]
mkdocs = "1.5.3" mkdocs = "1.5.3"
mkdocstrings = "0.24.0" mkdocstrings = {extras = ["python"], version = "0.24.0"}
mkdocs-git-authors-plugin = "0.7.2" mkdocs-git-authors-plugin = "0.7.2"
mkdocs-git-revision-date-localized-plugin = "1.2.2" mkdocs-git-revision-date-localized-plugin = "1.2.2"
mkdocs-material = {extras = ["imaging"], version = "^9.5.2"} mkdocs-material = {extras = ["imaging"], version = "^9.5.2"}

View file

@ -1,9 +1,3 @@
class KwargConflict(Exception):
"""
Raised when the keyword arguments passed to a function conflict.
"""
pass
class HTTPFailure(Exception): class HTTPFailure(Exception):
""" """
Raised when an HTTP request fails. Raised when an HTTP request fails.
@ -15,3 +9,9 @@ class PyZiplineError(Exception):
Raised when an error occurs in the PyZipline library. Raised when an error occurs in the PyZipline library.
""" """
pass pass
class FeatureDisabledError(Exception):
"""
Raised when a feature is disabled on the Zipline instance.
"""
pass

View file

@ -13,10 +13,11 @@ class Embed:
): ):
"""Embed object used for checking embeds """Embed object used for checking embeds
:param color: String of the embed's color Args:
:param title: String of the embed's title color (str): String of the embed's color
:param siteName: String of the embed's site name title (str): String of the embed's title
:param description: String of the embed's description siteName (str): String of the embed's site name
description (str): String of the embed's description
""" """
self.color = color self.color = color
@ -46,19 +47,20 @@ class File:
): ):
"""File object used for uploading files to Zipline """File object used for uploading files to Zipline
:param createdAt: Datetime object of when the file was created Args:
:param id: Integer ID of the file createdAt (datetime.datetime): Datetime object of when the file was created
:param mimetype: String of the file's mimetype id (int): ID of the file
:param views: Integer of the number of views the file has mimetype (str): String of the file's mimetype
:param name: String of the file's name views (int): Integer of the number of views the file has
:param size: Integer of the file's size in bytes name (str): String of the file's name
:param favorite: Boolean of whether the file is favorited size (int): Integer of the file's size in bytes
:param originalName: (optional) String of the file's original name favorite (bool): Boolean of whether the file is favorited
:param url: (optional) String of the file's URL originalName (str = None): (optional) String of the file's original name
:param maxViews: (optional) Integer of the file's maximum number of views url (str = None): (optional) String of the file's URL
:param expiredAt: (optional) Datetime object of when the file will expire maxViews (int = None): (optional) Integer of the file's maximum number of views
:param thumbnail: (optional) String of the file's thumbnail URL expiredAt (datetime.datetime = None): (optional) Datetime object of when the file will expire
:param folderId: (optional) Integer of the file's folder ID thumbnail (str = None): (optional) String of the file's thumbnail URL
folderId (int = None): (optional) Integer of the file's folder ID
""" """
self.createdAt = createdAt self.createdAt = createdAt
@ -78,19 +80,18 @@ class File:
class Result: class Result:
def __init__(self, status_code: int, message: str = '', data: List[Dict] = None): def __init__(self, success: bool, status_code: int, message: str = '', data: List[Dict] = None):
"""Result returned from low-level RestAdapter """Result returned from low-level RestAdapter
:param status_code: Standard HTTP Status code Args:
:type status_code: int success (bool): Boolean of whether the request was successful
:param message: Human readable result status_code (int): Standard HTTP Status code
:type message: str message (str = ''): Human readable result
:param data: Python List of Dictionaries (or maybe just a single Dictionary on error) data (List[Dict] = None): Python List of Dictionaries (or maybe just a single Dictionary on error)
:type data: Union[List[Dict], Dict]
""" """
self.success = success
self.status_code = int(status_code) self.status_code = status_code
self.message = str(message) self.message = message
self.data = data if data else [] self.data = data if data else []
@ -107,20 +108,14 @@ class Invite:
): ):
"""Invite object used for managing invites """Invite object used for managing invites
:param id: Integer ID of the invite Args:
:type id: int id (int): Integer ID of the invite
:param code: String of the invite's code code (str): String of the invite's code
:type code: str createdAt (datetime): Datetime object of when the invite was created
:param createdAt: Datetime object of when the invite was created expiredAt (datetime): Datetime object of when the invite will expire
:type createdAt: datetime used (bool): Boolean of whether the invite has been used
:param expiredAt: Datetime object of when the invite will expire createdById (int): Integer ID of the user who created the invite
:type expiredAt: datetime
:param used: Boolean of whether the invite has been used
:type used: bool
:param createdById: Integer ID of the user who created the invite
:type createdById: int
""" """
self.id = id self.id = id
self.code = code self.code = code
self.createdAt = createdAt self.createdAt = createdAt
@ -144,22 +139,15 @@ class OAuth:
): ):
"""OAuth object used for managing OAuth """OAuth object used for managing OAuth
:param id: Integer ID of the OAuth Args:
:type id: int id (int): Integer ID of the OAuth
:param provider: String of the OAuth's provider, one of 'DISCORD', 'GITHUB', 'GOOGLE' provider (str): String of the OAuth's provider, one of 'DISCORD', 'GITHUB', 'GOOGLE'
:type provider: str userId (int): Integer ID of the user who owns the OAuth
:param userId: Integer ID of the user who owns the OAuth providerId (str): String of the OAuth's provider ID
:type userId: int username (str): String of the OAuth's connected account's username
:param providerId: String of the OAuth's provider ID token (str): String of the OAuth's access token
:type providerId: str refresh (str): String of the OAuth's refresh token
:param username: String of the OAuth's connected account's username
:type username: str
:param token: String of the OAuth's access token
:type token: str
:param refresh: String of the OAuth's refresh token
:type refresh: str
""" """
self.id = id self.id = id
self.provider = provider self.provider = provider
self.userId = userId self.userId = userId
@ -190,34 +178,21 @@ class User:
): ):
"""User object used for managing users """User object used for managing users
:param id: Integer ID of the user Args:
:type id: int id (int): Integer ID of the user
:param uuid: String of the user's UUID uuid (str): String of the user's UUID
:type uuid: str username (str): String of the user's username
:param username: String of the user's username avatar (str): String of the user's avatar, base64 encoded
:type username: str token (str): String of the user's token
:param avatar: String of the user's avatar, base64 encoded administrator (bool): Boolean of whether the user is an administrator
:type avatar: str superAdmin (bool): Boolean of whether the user is a super administrator
:param token: String of the user's token systemTheme (str): String of the user's system theme
:type token: str embed (Embed): Embed object of the user's embed
:param administrator: Boolean of whether the user is an administrator totpSecret (str): String of the user's TOTP secret
:type administrator: bool domains (List[str]): List of Strings of the user's domains
:param superAdmin: Boolean of whether the user is a super administrator oauth (List[OAuth] = None): (optional) List of OAuth objects
:type superAdmin: bool ratelimit (datetime = None): (optional) Datetime object of when the user's ratelimit expires
:param systemTheme: String of the user's system theme
:type systemTheme: str
:param embed: Embed object of the user's embed
:type embed: Embed
:param totpSecret: String of the user's TOTP secret
:type totpSecret: str
:param domains: List of Strings of the user's domains
:type domains: List[str]
:param oauth: (optional) List of OAuth objects
:type oauth: Union[List[OAuth], None]
:param ratelimit: (optional) Datetime object of when the user's ratelimit expires
:type ratelimit: Union[datetime, None]
""" """
self.id = id self.id = id
self.uuid = uuid self.uuid = uuid
self.username = username self.username = username

View file

@ -12,17 +12,15 @@ class RestAdapter:
def __init__(self, hostname: str, token: str = '', ssl: bool = True, enforced_signing: bool = True, logger: logging.Logger = None): def __init__(self, hostname: str, token: str = '', ssl: bool = True, enforced_signing: bool = True, logger: logging.Logger = None):
"""Constructor for RestAdapter """Constructor for RestAdapter
:param hostname: The hostname of your Zipline instance, WITHOUT https or http. Args:
:type hostname: str hostname (str): The hostname of your Zipline instance, WITHOUT https or http.
:param token: (optional) String used for authentication when making requests. token (str = None): String used for authentication when making requests.
:param token: str ssl (bool = True): Normally set to True, but if your Zipline instance doesn't use SSL/TLS, set this to False.
:param ssl: (optional) Normally set to True, but if your Zipline instance doesn't use SSL/TLS, set this to False. enforced_signing (bool = True): Normally set to True, but if having SSL/TLS cert validation issues, can turn off with False.
:type ssl: bool logger (logging.Logger = None) If your app has a logger, pass it in here.
:param enforced_signing: (optional) Normally set to True, but if having SSL/TLS cert validation issues, can turn off with False.
:type enforced_signing: bool Raises:
:param logger: (optional) If your app has a logger, pass it in here. ValueError: Raised when the keyword arguments passed to the class constructor conflict.
:type logger: logging.Logger
:raise KwargConflict: Raised when the keyword arguments passed to a function conflict.
""" """
self._url = f"http{'s' if ssl else ''}://{hostname}/api/" self._url = f"http{'s' if ssl else ''}://{hostname}/api/"
self._token = token self._token = token
@ -31,7 +29,7 @@ class RestAdapter:
self._logger = logger or logging.getLogger(__name__) self._logger = logger or logging.getLogger(__name__)
if ssl is False and enforced_signing is True: if ssl is False and enforced_signing is True:
raise KwargConflict("Cannot enforce signing without SSL") raise ValueError("Cannot enforce signing without SSL")
if not ssl and not enforced_signing: if not ssl and not enforced_signing:
disable_warnings() disable_warnings()
@ -39,18 +37,19 @@ class RestAdapter:
def _do(self, http_method: str, endpoint: str, params: Dict = None, data: Dict = None) -> Result: def _do(self, http_method: str, endpoint: str, params: Dict = None, data: Dict = None) -> Result:
"""Internal method to make a request to the Zipline server. You shouldn't use this directly. """Internal method to make a request to the Zipline server. You shouldn't use this directly.
:param http_method: The HTTP method to use (GET, POST, DELETE) Args:
:type http_method: str http_method (str): The HTTP method to use (GET, POST, DELETE)
:param endpoint: The endpoint to make the request to. endpoint (str): The endpoint to make the request to.
:type endpoint: str params (Dict = None): Python dictionary of query parameters to send with the request.
:param params: (optional) Python dictionary of query parameters to send with the request. data (Dict = None): Python dictionary of data to send with the request.
:type params: Dict
:param data: (optional) Python dictionary of data to send with the request. Returns:
:type data: Dict Result: A Result object containing the status code, message, and data from the request.
:raise HTTPFailure: Raised when an HTTP request fails.
:raise PyZiplineError: Raised when an error occurs in the PyZipline library. Raises:
:return: Result object HTTPError: Raised when an HTTP request fails.
:rtype: Result""" PyZiplineError: Raised when an error occurs in the PyZipline library.
"""
full_url = self._url + endpoint full_url = self._url + endpoint
headers = {'Authorization': self._token} headers = {'Authorization': self._token}
@ -71,51 +70,46 @@ class RestAdapter:
self._logger.error(msg=log_line_post.format(False, None, e)) self._logger.error(msg=log_line_post.format(False, None, e))
raise PyZiplineError("Could not decode response from Zipline server") from e raise PyZiplineError("Could not decode response from Zipline server") from e
# If status_code in 200-299 range, return success Result with data, otherwise raise exception # If status_code in 200-299 range, return success Result with data, otherwise return failed Result with message
is_success = 299 >= response.status_code >= 200 is_success = 299 >= response.status_code >= 200
log_line = log_line_post.format(is_success, response.status_code, response.reason)
if is_success: self._logger.debug(msg=log_line_post.format(is_success, response.status_code, response.reason))
self._logger.debug(msg=log_line_post.format(is_success, response.status_code, response.reason)) return Result(success=is_success, status_code=response.status_code, message=response.reason, data=data_out)
return Result(status_code=response.status_code, message=response.reason, data=data_out)
self._logger.error(msg=log_line)
raise PyZiplineError(f"{response.status_code}: {response.reason}")
def get(self, endpoint: str, params: Dict = None) -> Result: def get(self, endpoint: str, params: Dict = None) -> Result:
"""Make a GET request to the Zipline server. You should almost never have to use this directly. """Make a GET request to the Zipline server. You should almost never have to use this directly.
:param endpoint: The endpoint to make the request to. Args:
:type endpoint: str endpoint (str): The endpoint to make the request to.
:param params: (optional) Python dictionary of query parameters to send with the request. params (Dict = None): Python dictionary of query parameters to send with the request.
:type params: Dict
:return: Result object Returns:
:rtype: Result""" Result: A Result object containing the status code, message, and data from the request.
"""
return self._do(http_method='GET', endpoint=endpoint, params=params) return self._do(http_method='GET', endpoint=endpoint, params=params)
def post(self, endpoint: str, params: Dict = None, data: Dict = None) -> Result: def post(self, endpoint: str, params: Dict = None, data: Dict = None) -> Result:
"""Make a POST request to the Zipline server. You should almost never have to use this directly. """Make a POST request to the Zipline server. You should almost never have to use this directly.
:param endpoint: The endpoint to make the request to. Args:
:type endpoint: str endpoint (str): The endpoint to make the request to.
:param params: (optional) Python dictionary of query parameters to send with the request. params (Dict = None): Python dictionary of query parameters to send with the request.
:type params: Dict data (Dict = None): Python dictionary of data to send with the request.
:param data: (optional) Python dictionary of data to send with the request.
:type data: Dict Returns:
:return: Result object Result: A Result object containing the status code, message, and data from the request.
:rtype: Result""" """
return self._do(http_method='POST', endpoint=endpoint, params=params, data=data) return self._do(http_method='POST', endpoint=endpoint, params=params, data=data)
def delete(self, endpoint: str, params: Dict = None, data: Dict = None) -> Result: def delete(self, endpoint: str, params: Dict = None, data: Dict = None) -> Result:
"""Make a DELETE request to the Zipline server. You should almost never have to use this directly. """Make a DELETE request to the Zipline server. You should almost never have to use this directly.
:param endpoint: The endpoint to make the request to. Args:
:type endpoint: str endpoint (str): The endpoint to make the request to.
:param params: (optional) Python dictionary of query parameters to send with the request. params (Dict = None): Python dictionary of query parameters to send with the request.
:type params: Dict data (Dict = None): Python dictionary of data to send with the request.
:param data: (optional) Python dictionary of data to send with the request.
:type data: Dict Returns:
:return: Result object Result: A Result object containing the status code, message, and data from the request.
:rtype: Result""" """
return self._do(http_method='DELETE', endpoint=endpoint, params=params, data=data) return self._do(http_method='DELETE', endpoint=endpoint, params=params, data=data)

View file

@ -3,9 +3,10 @@ from datetime import datetime
def convert_str_to_datetime(date_string: str) -> datetime: def convert_str_to_datetime(date_string: str) -> datetime:
"""Converts a string to a datetime object """Converts a string to a datetime object
:param date_string: String to convert Args:
:type date_string: str date_string (str): String to convert
:return: Datetime object
:rtype: datetime Returns:
datetime.datetime: Datetime object
""" """
return datetime.strptime(date_string, '%Y-%m-%dT%H:%M:%S.%fZ') return datetime.strptime(date_string, '%Y-%m-%dT%H:%M:%S.%fZ')

View file

@ -1,9 +1,20 @@
import logging import logging
from pyzipline.rest_adapter import RestAdapter from pyzipline.rest_adapter import RestAdapter
from pyzipline.errors import PyZiplineError from pyzipline.errors import PyZiplineError, FeatureDisabledError
from pyzipline.models import * from pyzipline.models import *
class ZiplineApi: class ZiplineApi:
"""Represents an instance of the Zipline API.
All API requests should be made through this class.
Args:
hostname (str): The hostname of your Zipline instance, WITHOUT https or http.
token (str = None): String used for authentication when making requests.
ssl (bool = True): Normally set to True, but if your Zipline instance doesn't use SSL/TLS, set this to False.
enforced_signing (bool = True): Normally set to True, but if having SSL/TLS cert validation issues, can turn off with False.
logger (logging.Logger = None): If your app has a logger, pass it in here.
"""
def __init__( def __init__(
self, self,
hostname: str, hostname: str,
@ -12,25 +23,16 @@ class ZiplineApi:
enforced_signing: bool = True, enforced_signing: bool = True,
logger: logging.Logger = None logger: logging.Logger = None
): ):
"""Constructor for ZiplineApi.
All API requests should be made through this class.
Args:
hostname (str): The hostname of your Zipline instance, WITHOUT https or http.
token (str = None): String used for authentication when making requests.
ssl (bool = True): Normally set to True, but if your Zipline instance doesn't use SSL/TLS, set this to False.
enforced_signing (bool = True): Normally set to True, but if having SSL/TLS cert validation issues, can turn off with False.
logger (logging.Logger = None): If your app has a logger, pass it in here.
"""
self._rest_adapter = RestAdapter(hostname=hostname, token=token, ssl=ssl, enforced_signing=enforced_signing, logger=logger) self._rest_adapter = RestAdapter(hostname=hostname, token=token, ssl=ssl, enforced_signing=enforced_signing, logger=logger)
def get_user(self, user_id: int) -> User: def get_user(self, user_id: int) -> User:
"""Get a user by ID """Get a user by ID
user_id (int): Integer ID of the user to retrieve Args:
:return: The :class:`pyzipline.models.User` object matching the ID user_id (int): Integer ID of the user to retrieve
:rtype: :class:`pyzipline.models.User`
Returns:
:class:`pyzipline.models.User`: The user with the given ID
""" """
result = self._rest_adapter.get(endpoint=f"user/{user_id}") result = self._rest_adapter.get(endpoint=f"user/{user_id}")
return User(**result.data) return User(**result.data)
@ -38,8 +40,35 @@ class ZiplineApi:
def get_self(self) -> User: def get_self(self) -> User:
"""Get the currently authenticated user """Get the currently authenticated user
:return: `pyzipline.models.User`object matching the authenticated user Returns:
:rtype: `pyzipline.models.User` :class:`pyzipline.models.User`: The currently authenticated user
""" """
result = self._rest_adapter.get(endpoint=f"user") result = self._rest_adapter.get(endpoint=f"user")
return User(**result.data) return User(**result.data)
def check_user_exists(self, username: str, invite: str = None) -> bool:
"""Check if a user exists by username
Args:
username (str): Username to check
invite (str = None): Invite code to use, only required if registration without invites is disabled
Raises:
FeatureDisabledError: Raised when registration or invites are disabled on the Zipline instance
PyZiplineError: Raised
Returns:
bool: True if user exists, False if not
"""
params = {'username': username} if invite is None else {'username': username, 'code': invite}
result: Result = self._rest_adapter.get(endpoint=f"user/check", params=params)
if result.status_code == 200:
return bool(result.data['success'])
elif result.message == 'user resistration is disabled' or result.message == 'invites are disabled':
raise FeatureDisabledError(result.message)
elif result.message == 'username already exists':
return True
elif result.message == 'invalid invite code':
raise ValueError(result.message)
else:
raise PyZiplineError(result.message)