feat(models): converted to pydantic for all data models
Some checks failed
Actions / Build Documentation (MkDocs) (push) Failing after 14s
Actions / Lint Code (Ruff & Pylint) (push) Failing after 22s

This commit is contained in:
Seaswimmer 2024-03-28 11:15:27 -04:00
parent 0dda9b46fa
commit c6b723a476
Signed by: cswimr
GPG key ID: B8953EC01E5C4063
6 changed files with 329 additions and 315 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
__pycache__
.cache
.zipline
dev.py

180
poetry.lock generated
View file

@ -121,6 +121,20 @@ files = [
{file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"},
]
[[package]]
name = "argcomplete"
version = "3.2.3"
description = "Bash tab completion for argparse"
optional = false
python-versions = ">=3.8"
files = [
{file = "argcomplete-3.2.3-py3-none-any.whl", hash = "sha256:c12355e0494c76a2a7b73e3a59b09024ca0ba1e279fb9ed6c1b82d5b74b6a70c"},
{file = "argcomplete-3.2.3.tar.gz", hash = "sha256:bf7900329262e481be5a15f56f19736b376df6f82ed27576fa893652c5de6c23"},
]
[package.extras]
test = ["coverage", "mypy", "pexpect", "ruff", "wheel"]
[[package]]
name = "astroid"
version = "3.1.0"
@ -191,6 +205,52 @@ files = [
[package.extras]
dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"]
[[package]]
name = "black"
version = "24.3.0"
description = "The uncompromising code formatter."
optional = false
python-versions = ">=3.8"
files = [
{file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"},
{file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"},
{file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"},
{file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"},
{file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"},
{file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"},
{file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"},
{file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"},
{file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"},
{file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"},
{file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"},
{file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"},
{file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"},
{file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"},
{file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"},
{file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"},
{file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"},
{file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"},
{file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"},
{file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"},
{file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"},
{file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"},
]
[package.dependencies]
click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
packaging = ">=22.0"
pathspec = ">=0.9.0"
platformdirs = ">=2"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
[package.extras]
colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "cairocffi"
version = "1.6.1"
@ -450,6 +510,39 @@ webencodings = "*"
doc = ["sphinx", "sphinx_rtd_theme"]
test = ["flake8", "isort", "pytest"]
[[package]]
name = "datamodel-code-generator"
version = "0.25.5"
description = "Datamodel Code Generator"
optional = false
python-versions = ">=3.7,<4.0"
files = [
{file = "datamodel_code_generator-0.25.5-py3-none-any.whl", hash = "sha256:3b62b42c8ebf2bb98cfbc24467b523c5b76780c585b72f4ac2fc1f1f576702ab"},
{file = "datamodel_code_generator-0.25.5.tar.gz", hash = "sha256:545f897481a94781e32b3c26a452ce049320b091310729f7fc6fa780f6a87898"},
]
[package.dependencies]
argcomplete = ">=1.10,<4.0"
black = ">=19.10b0"
genson = ">=1.2.1,<2.0"
inflect = ">=4.1.0,<6.0"
isort = ">=4.3.21,<6.0"
jinja2 = ">=2.10.1,<4.0"
packaging = "*"
pydantic = [
{version = ">=1.10.0,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.4.0 || >2.4.0,<3.0", extras = ["email"], markers = "python_version >= \"3.12\" and python_version < \"4.0\""},
{version = ">=1.10.0,<2.4.0 || >2.4.0,<3.0", extras = ["email"], markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
{version = ">=1.9.0,<2.4.0 || >2.4.0,<3.0", extras = ["email"], markers = "python_version >= \"3.10\" and python_version < \"3.11\""},
]
pyyaml = ">=6.0.1"
toml = {version = ">=0.10.0,<1.0.0", markers = "python_version < \"3.11\""}
[package.extras]
debug = ["PySnooper (>=0.4.1,<2.0.0)"]
graphql = ["graphql-core (>=3.2.3,<4.0.0)"]
http = ["httpx"]
validation = ["openapi-spec-validator (>=0.2.8,<0.7.0)", "prance (>=0.18.2)"]
[[package]]
name = "defusedxml"
version = "0.7.1"
@ -475,6 +568,41 @@ files = [
[package.extras]
graph = ["objgraph (>=1.7.2)"]
[[package]]
name = "dnspython"
version = "2.6.1"
description = "DNS toolkit"
optional = false
python-versions = ">=3.8"
files = [
{file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"},
{file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"},
]
[package.extras]
dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"]
dnssec = ["cryptography (>=41)"]
doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"]
doq = ["aioquic (>=0.9.25)"]
idna = ["idna (>=3.6)"]
trio = ["trio (>=0.23)"]
wmi = ["wmi (>=1.5.1)"]
[[package]]
name = "email-validator"
version = "2.1.1"
description = "A robust email address syntax and deliverability validation library."
optional = false
python-versions = ">=3.8"
files = [
{file = "email_validator-2.1.1-py3-none-any.whl", hash = "sha256:97d882d174e2a65732fb43bfce81a3a834cbc1bde8bf419e30ef5ea976370a05"},
{file = "email_validator-2.1.1.tar.gz", hash = "sha256:200a70680ba08904be6d1eef729205cc0d687634399a5924d842533efb824b84"},
]
[package.dependencies]
dnspython = ">=2.0.0"
idna = ">=2.0.0"
[[package]]
name = "frozenlist"
version = "1.4.1"
@ -561,6 +689,16 @@ files = [
{file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"},
]
[[package]]
name = "genson"
version = "1.2.2"
description = "GenSON is a powerful, user-friendly JSON Schema generator."
optional = false
python-versions = "*"
files = [
{file = "genson-1.2.2.tar.gz", hash = "sha256:8caf69aa10af7aee0e1a1351d1d06801f4696e005f06cedef438635384346a16"},
]
[[package]]
name = "ghp-import"
version = "2.1.0"
@ -634,6 +772,21 @@ files = [
{file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"},
]
[[package]]
name = "inflect"
version = "5.6.2"
description = "Correctly generate plurals, singular nouns, ordinals, indefinite articles; convert numbers to words"
optional = false
python-versions = ">=3.7"
files = [
{file = "inflect-5.6.2-py3-none-any.whl", hash = "sha256:b45d91a4a28a4e617ff1821117439b06eaa86e2a4573154af0149e9be6687238"},
{file = "inflect-5.6.2.tar.gz", hash = "sha256:aadc7ed73928f5e014129794bbac03058cca35d0a973a5fc4eb45c7fa26005f9"},
]
[package.extras]
docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"]
testing = ["pygments", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
[[package]]
name = "isort"
version = "5.13.2"
@ -1032,6 +1185,17 @@ files = [
{file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"},
]
[[package]]
name = "mypy-extensions"
version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker."
optional = false
python-versions = ">=3.5"
files = [
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
]
[[package]]
name = "packaging"
version = "23.2"
@ -1182,6 +1346,7 @@ files = [
[package.dependencies]
annotated-types = ">=0.4.0"
email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""}
pydantic-core = "2.16.3"
typing-extensions = ">=4.6.1"
@ -1309,9 +1474,9 @@ files = [
astroid = ">=3.1.0,<=3.2.0-dev0"
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
dill = [
{version = ">=0.2", markers = "python_version < \"3.11\""},
{version = ">=0.3.7", markers = "python_version >= \"3.12\""},
{version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
{version = ">=0.2", markers = "python_version < \"3.11\""},
]
isort = ">=4.2.5,<5.13.0 || >5.13.0,<6"
mccabe = ">=0.6,<0.8"
@ -1624,6 +1789,17 @@ webencodings = ">=0.4"
doc = ["sphinx", "sphinx_rtd_theme"]
test = ["flake8", "isort", "pytest"]
[[package]]
name = "toml"
version = "0.10.2"
description = "Python Library for Tom's Obvious, Minimal Language"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
files = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]
[[package]]
name = "tomli"
version = "2.0.1"
@ -1829,4 +2005,4 @@ multidict = ">=4.0"
[metadata]
lock-version = "2.0"
python-versions = "^3.10 || ^3.11 || ^3.12"
content-hash = "81bf41a2234efa4a9682bf29ea427b0e090c72c72134b7296cc135c4952199eb"
content-hash = "3cd54cc2b740040bab9d9bae7bc04645893711c141516a9182f6c68fcf6b128b"

View file

@ -19,6 +19,7 @@ optional = true
[tool.poetry.group.dev.dependencies]
pylint = "^3.0.3"
ruff = "^0.3.4"
datamodel-code-generator = "^0.25.5"
[tool.poetry.group.docs]
optional = true

View file

@ -1,64 +1,67 @@
"""This is a list of all the models used in PyZipline. They are used to represent the data returned from the Zipline API."""
from typing import List, Dict, Optional
from datetime import datetime
from pyzipline.utils import convert_str_to_datetime
from typing import Dict, List, Optional, Union
from pydantic import BaseModel, Field
class File:
class File(BaseModel):
"""File object used for uploading files to Zipline
Attributes:
created_at (datetime.datetime): Datetime object of when the file was created
createdAt (datetime.datetime): Datetime object of when the file was created
id (int): ID of the file
mimetype (str): String of the file's mimetype
views (int): Integer of the number of views the file has
name (str): String of the file's name
size (int): Integer of the file's size in bytes
favorite (bool): Boolean of whether the file is favorited
original_name (Optional[str]): String of the file's original name
originalName (Optional[str]): String of the file's original name
url (Optional[str]): String of the file's URL
max_views (Optional[int]): Integer of the file's maximum number of views
expired_at (Optional[datetime]): Datetime object of when the file will expire
maxViews (Optional[int]): Integer of the file's maximum number of views
expiredAt (Optional[datetime]): Datetime object of when the file will expire
thumbnail (Optional[str]): String of the file's thumbnail URL
folder_id (Optional[int]): Integer of the file's folder ID
folderId (Optional[int]): Integer of the file's folder ID
"""
def __init__(
self,
createdAt: datetime,
id: int, # pylint: disable=redefined-builtin
mimetype: str,
views: int,
name: str,
size: int,
favorite: bool,
originalName: str = None,
url: str = None,
maxViews: int = None,
expiredAt: datetime = None,
thumbnail: str = None,
folderId: int = None,
**kwargs
):
self.created_at = createdAt
self.id = id
self.mimetype = mimetype
self.views = views
self.name = name
self.size = size
self.favorite = favorite
self.original_name = originalName
self.url = url
self.max_views = maxViews
self.expired_at = expiredAt
self.thumbnail = thumbnail
self.folder_id = folderId
self.__dict__.update(kwargs)
createdAt: datetime
id: int
mimetype: str
views: int
name: str
size: int
favorite: bool
originalName: Optional[str] = None
url: Optional[str] = None
maxViews: Optional[int] = None
expiredAt: Optional[datetime] = None
thumbnail: Optional[str] = None
folderId: Optional[int] = None
def __str__(self):
return self.name
class Invite(BaseModel):
"""Invite object used for managing invites
class Result:
Attributes:
id (int): Integer ID of the invite
code (str): String of the invite's code
createdAt (datetime): Datetime object of when the invite was created
expiresAt (datetime): Datetime object of when the invite will expire
used (bool): Boolean of whether the invite has been used
createdById (int): Integer ID of the user who created the invite
"""
id: int
code: str
createdAt: datetime
expiresAt: datetime
used: bool
createdById: int
def __str__(self):
return self.code
class Result(BaseModel):
"""Result returned from low-level RestAdapter
Attributes:
@ -67,50 +70,44 @@ class Result:
message (str = ''): Human readable result
data (Union[List[Dict], Dict]): Python List of Dictionaries (or maybe just a single Dictionary on error)
"""
def __init__(self, success: bool, status_code: int, message: str = '', data: List[Dict] = None):
self.success = success
self.status_code = status_code
self.message = message
self.data = data if data else {}
success: bool
status_code: int
message: str = ''
data: Union[List[Dict], Dict] = {}
def __str__(self):
return f"{self.status_code}: {self.message}\n{self.data}"
return f"{self.status_code}: {self.message}"
class Invite:
"""Invite object used for managing invites
class TypesCountItem(BaseModel):
"""Model used in [StatsData](.#pyzipline.models.StatsData) for storing the number of files with a specific mimetype
Attributes:
id (int): Integer ID of the invite
code (str): String of the invite's code
created_at (datetime): Datetime object of when the invite was created
expires_at (datetime): Datetime object of when the invite will expire
used (bool): Boolean of whether the invite has been used
created_by_id (int): Integer ID of the user who created the invite
mimetype (str): String of the mimetype
count (int): Integer of the number of files with this mimetype
"""
def __init__(
self,
id: int, # pylint: disable=redefined-builtin
code: str,
createdAt: str,
expiresAt: str,
used: bool,
createdById: int,
**kwargs
):
self.id = id
self.code = code
self.created_at = convert_str_to_datetime(createdAt)
self.expires_at = convert_str_to_datetime(expiresAt)
self.used = used
self.created_by_id = createdById
self.__dict__.update(kwargs)
count: int
mimetype: str
def __str__(self):
return self.code
return f"{self.mimetype}: {self.count}"
class Stats:
"""Stats object used for retrieving stats
class CountByUserItem(BaseModel):
"""Model used in [StatsData](.#pyzipline.models.StatsData) for storing the number of files uploaded by a user
Attributes:
username (str): String of the username
count (int): Integer of the number of files uploaded by this user
"""
count: int
username: str
def __str__(self):
return f"{self.username}: {self.count}"
class StatsData(BaseModel):
"""Stats data model
Attributes:
id (int): Integer ID of the stats
@ -124,225 +121,64 @@ class Stats:
types_count (Optional[List[Mimetype]]): List of Mimetype objects
count_by_user (Optional[List[CountByUser]]): List of CountByUser objects
"""
def __init__(
self,
id: int, # pylint: disable=redefined-builtin
createdAt: datetime,
data: dict,
max_timestamp: Optional[datetime] = None
):
self.id = id
self.createdAt = createdAt
self._data = data
self.max_timestamp = max_timestamp
self.size = self._data['size']
self.size_num = self._data['size_num']
self.count = self._data['count']
self.count_users = self._data['count_users']
self.views_count = self._data['views_count']
self.types_count: list = self._data['types_count']
self.count_by_user: list = self._data['count_by_user']
if self.types_count is not None:
new_types_count = []
for mimetype_entry in self.types_count:
if isinstance(mimetype_entry, dict):
m = self.Mimetype(**mimetype_entry)
new_types_count.append(m)
self.types_count = new_types_count
if self.count_by_user is not None:
new_count_by_user = []
for count_by_user_entry in self.count_by_user:
if isinstance(count_by_user_entry, dict):
c = self.CountByUser(**count_by_user_entry)
new_count_by_user.append(c)
self.count_by_user = new_count_by_user
size: str
count: int
size_num: int
count_users: int
types_count: List[TypesCountItem]
views_count: int
count_by_user: List[CountByUserItem]
def __str__(self):
return str(self.id)
class Mimetype:
"""Object used in [Stats](.#pyzipline.models.Stats) for storing the number of files with a specific mimetype
Attributes:
mimetype (str): String of the mimetype
count (int): Integer of the number of files with this mimetype"""
def __init__(
self,
mimetype: str,
count: int
):
self.mimetype = mimetype
self.count = count
def __str__(self):
return f"{self.mimetype}: {self.count}"
class CountByUser:
"""Object used in [Stats](.#pyzipline.models.Stats) for storing the number of files uploaded by a user
Attributes:
username (str): String of the username
count (int): Integer of the number of files uploaded by this user"""
def __init__(
self,
username: str,
count: int
):
self.username = username
self.count = count
def __str__(self):
return f"{self.username}: {self.count}"
class OAuth:
"""OAuth object used for managing OAuth
class Stats(BaseModel):
"""Stats model
Attributes:
id (int): Integer ID of the OAuth
provider (str): String of the OAuth's provider, one of 'DISCORD', 'GITHUB', 'GOOGLE'
user_id (int): Integer ID of the user who owns the OAuth
oauth_id (str): String of the OAuth's provider ID
username (str): String of the OAuth's connected account's username
token (str): String of the OAuth's access token
refresh (Optional[str]): String of the OAuth's refresh token
id (int): Integer ID of the stats
createdAt (datetime): Datetime object of when the stats were created
data (StatsData): StatsData object of the stats data
max_timestamp (Optional[datetime]): Datetime object of the maximum timestamp of the stats
"""
def __init__(
self,
id: int, # pylint: disable=redefined-builtin
provider: str,
oauthId: int,
providerId: str,
username: str,
token: str,
refresh: Optional[str],
**kwargs
):
self.id = id
self.provider = provider
self.oauth_id = oauthId
self.provider_id = providerId
self.username = username
self.token = token
self.refresh = refresh
self.__dict__.update(kwargs)
def __str__(self):
return self.provider
id: int
createdAt: datetime
data: StatsData
max_timestamp: str = Field(default=None)
class User:
"""Object containing user information
class Embed(BaseModel):
color: Optional[str] = None
title: Optional[str] = None
siteName: Optional[str] = None
description: Optional[str] = None
/// admonition | Contains Sensitive Information
type: danger
Please be mindful of how you use/store this object, as it contains sensitive information such as the user's token and OAuth/TOTP information.
///
Attributes:
id (int): Integer ID of the user
uuid (str): String of the user's UUID
username (str): String of the user's username
avatar (Optional[str]): String of the user's avatar, base64 encoded
token (str): String of the user's token
administrator (bool): Boolean of whether the user is an administrator
super_admin (bool): Boolean of whether the user is a super administrator
system_theme (str): String of the user's system theme
embed (Embed): Embed object of the user's embed
totp_secret (Optional[str]): String of the user's TOTP secret
domains (List[str]): List of Strings of the user's domains
oauth (Optional[List[OAuth]]): List of [OAuth](.#pyzipline.models.OAuth) objects
ratelimit (Optional[datetime]): Datetime object of when the user's ratelimit expires
"""
def __init__(
self,
id: int, # pylint: disable=redefined-builtin
uuid: str,
username: str,
avatar: Optional[str],
token: str,
administrator: bool,
superAdmin: bool,
systemTheme: str,
embed: 'Embed',
totpSecret: Optional[str],
domains: List[str],
oauth: Optional[List['OAuth']] = None,
ratelimit: Optional[datetime] = None,
**kwargs
):
self.id = id
self.uuid = uuid
self.username = username
self.avatar = avatar
self.token = token
self.administrator = administrator
self.super_admin = superAdmin
self.system_theme = systemTheme
self.embed = self.Embed(**embed)
self.totp_secret = totpSecret
self.domains = domains
self.oauth = oauth
self.ratelimit = ratelimit
self.__dict__.update(kwargs)
if self.oauth is not None:
for oauth_entry in self.oauth:
self.oauth.remove(oauth_entry)
o = OAuth(**oauth_entry)
self.oauth.append(o)
class User(BaseModel):
id: int
uuid: str
username: str
avatar: Optional[str]
token: str
administrator: bool
superAdmin: bool
systemTheme: str
embed: Embed
ratelimit: None
totpSecret: Optional[str]
domains: List[str]
def __str__(self):
return self.username
class Embed:
"""Object containing a user's embed settings
class Versions(BaseModel):
stable: str
upstream: str
current: str
Attributes:
color (Optional[str]): String of the embed's color
title (Optional[str]): String of the embed's title
site_name (Optional[str]): String of the embed's site name
description (Optional[str]): String of the embed's description
"""
def __init__(
self,
color: str = None,
title: str = None,
siteName: str = None,
description: str = None,
**kwargs
):
self.color = color
self.title = title
self.site_name = siteName
self.description = description
self.__dict__.update(kwargs)
def __str__(self):
if self.title is None:
return "None"
return self.title
class Version:
"""Object containing the current, stable, and upstream versions of Zipline
Attributes:
is_upstream (bool): Boolean of whether the current version is upstream (`trunk` branch)
update_to_type (str): String of the type of update available, one of 'stable' or 'upstream'
stable (str): String of the stable version
upstream (str): String of the upstream version
current (str): String of the current version
"""
def __init__(
self,
isUpstream: bool,
updateToType: str,
versions: {dict}
):
self.is_upstream = isUpstream
self.update_to_type = updateToType
self._versions = versions
self.stable = self._versions['stable']
self.upstream = self._versions['upstream']
self.current = self._versions['upstream']
class Version(BaseModel):
isUpstream: bool
updateToType: str
versions: Versions
def __str__(self):
return self.current
return self.versions.current

View file

@ -8,6 +8,7 @@ from urllib3 import disable_warnings
from pyzipline.exceptions import HTTPFailure, PyZiplineError
from pyzipline.models import Result
class RestAdapter:
"""Constructor for RestAdapter

View file

@ -1,17 +1,19 @@
"""This module contains the ZiplineApi class, which is the main class used to interact with the Zipline API."""
from datetime import datetime, timedelta
from typing import Union, List
import logging
from datetime import datetime, timedelta
from typing import List, Union
from pydantic import BaseModel, ConfigDict
from pyzipline.exceptions import (FeatureDisabledError, Forbidden, NotFound,
PyZiplineError)
from pyzipline.models import File, Invite, Result, Stats, User, Version
from pyzipline.rest_adapter import RestAdapter
from pyzipline.exceptions import PyZiplineError, FeatureDisabledError, Forbidden, NotFound
from pyzipline.models import User, File, Result, Invite, Stats, Version
from pyzipline.utils import convert_datetime_to_str
# pylint: disable=not-a-mapping
class ZiplineApi:
"""Represents an instance of the Zipline API.
All API requests should be made through this class.
class ZiplineApiConfig(BaseModel):
"""Represents a configuration instance for the ZiplineApi class.
Args:
hostname (str): The hostname of your Zipline instance, WITHOUT https or http.
@ -20,15 +22,27 @@ class ZiplineApi:
enforced_signing (bool): Normally set to True, but if having SSL/TLS cert validation issues, can turn off with False.
logger (logging.Logger): If your app has a logger, pass it in here.
"""
model_config = ConfigDict(arbitrary_types_allowed=True)
hostname: str
token: str = ''
ssl: bool = True
enforced_signing: bool = True
logger: logging.Logger = logging.getLogger(__name__)
# pylint: disable=not-a-mapping
class ZiplineApi:
"""Represents an instance of the Zipline API.
All API requests should be made through this class.
Args:
config (ZiplineApiConfig): Configuration object for the ZiplineApi class
"""
def __init__(
self,
hostname: str,
token: str = '',
ssl: bool = True,
enforced_signing: bool = True,
logger: logging.Logger = None
config: ZiplineApiConfig
):
self._rest_adapter = RestAdapter(hostname=hostname, token=token, ssl=ssl, enforced_signing=enforced_signing, logger=logger)
self._rest_adapter = RestAdapter(hostname=config.hostname, token=config.token, ssl=config.ssl, enforced_signing=config.enforced_signing, logger=config.logger)
def create_invite(self, expiry: timedelta = timedelta(days=1), count: int = 1) -> Union[Invite, List[Invite]]:
"""Create an invite code
@ -302,11 +316,7 @@ class ZiplineApi:
"""
result = self._rest_adapter.get(endpoint="auth/invite")
if result.status_code == 200:
invites = []
for invite in result.data:
i = Invite(**invite)
invites.append(i)
return invites
return [Invite(**invite) for invite in result.data]
if result.status_code == 401:
raise Forbidden(result.message)
if result.message == 'invites are disabled':
@ -417,11 +427,7 @@ class ZiplineApi:
"""
result = self._rest_adapter.get(endpoint="users")
if result.status_code == 200:
users = []
for user in result.data:
u = User(**user)
users.append(u)
return users
return [User(**user) for user in result.data]
if result.status_code == 403:
raise Forbidden(result.message)
raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")
@ -445,7 +451,7 @@ class ZiplineApi:
///
Args:
amount (int ): Number of stats to retrieve
amount (int): Number of stats to retrieve
force_update (bool): Force the Zipline instance to update its statistics before returning them, requires administrator
Raises:
@ -463,14 +469,7 @@ class ZiplineApi:
else:
result = self._rest_adapter.get(endpoint="stats", params={'amount': amount})
if result.status_code == 200:
if amount > 1:
stats_list = []
for stats in result.data:
s = Stats(**stats)
stats_list.append(s)
return stats_list
data = result.data[0] if isinstance(result.data, list) else result.data
return Stats(**data)
return [Stats(**stats) for stats in result.data]
if result.status_code in (401, 403):
raise Forbidden(result.message)
raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")