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__ __pycache__
.cache .cache
.zipline .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"}, {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]] [[package]]
name = "astroid" name = "astroid"
version = "3.1.0" version = "3.1.0"
@ -191,6 +205,52 @@ files = [
[package.extras] [package.extras]
dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] 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]] [[package]]
name = "cairocffi" name = "cairocffi"
version = "1.6.1" version = "1.6.1"
@ -450,6 +510,39 @@ webencodings = "*"
doc = ["sphinx", "sphinx_rtd_theme"] doc = ["sphinx", "sphinx_rtd_theme"]
test = ["flake8", "isort", "pytest"] 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]] [[package]]
name = "defusedxml" name = "defusedxml"
version = "0.7.1" version = "0.7.1"
@ -475,6 +568,41 @@ files = [
[package.extras] [package.extras]
graph = ["objgraph (>=1.7.2)"] 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]] [[package]]
name = "frozenlist" name = "frozenlist"
version = "1.4.1" version = "1.4.1"
@ -561,6 +689,16 @@ files = [
{file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, {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]] [[package]]
name = "ghp-import" name = "ghp-import"
version = "2.1.0" version = "2.1.0"
@ -634,6 +772,21 @@ files = [
{file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, {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]] [[package]]
name = "isort" name = "isort"
version = "5.13.2" version = "5.13.2"
@ -1032,6 +1185,17 @@ files = [
{file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, {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]] [[package]]
name = "packaging" name = "packaging"
version = "23.2" version = "23.2"
@ -1182,6 +1346,7 @@ files = [
[package.dependencies] [package.dependencies]
annotated-types = ">=0.4.0" annotated-types = ">=0.4.0"
email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""}
pydantic-core = "2.16.3" pydantic-core = "2.16.3"
typing-extensions = ">=4.6.1" typing-extensions = ">=4.6.1"
@ -1309,9 +1474,9 @@ files = [
astroid = ">=3.1.0,<=3.2.0-dev0" astroid = ">=3.1.0,<=3.2.0-dev0"
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
dill = [ dill = [
{version = ">=0.2", markers = "python_version < \"3.11\""},
{version = ">=0.3.7", markers = "python_version >= \"3.12\""}, {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.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" isort = ">=4.2.5,<5.13.0 || >5.13.0,<6"
mccabe = ">=0.6,<0.8" mccabe = ">=0.6,<0.8"
@ -1624,6 +1789,17 @@ webencodings = ">=0.4"
doc = ["sphinx", "sphinx_rtd_theme"] doc = ["sphinx", "sphinx_rtd_theme"]
test = ["flake8", "isort", "pytest"] 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]] [[package]]
name = "tomli" name = "tomli"
version = "2.0.1" version = "2.0.1"
@ -1829,4 +2005,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 = "81bf41a2234efa4a9682bf29ea427b0e090c72c72134b7296cc135c4952199eb" content-hash = "3cd54cc2b740040bab9d9bae7bc04645893711c141516a9182f6c68fcf6b128b"

View file

@ -19,6 +19,7 @@ optional = true
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pylint = "^3.0.3" pylint = "^3.0.3"
ruff = "^0.3.4" ruff = "^0.3.4"
datamodel-code-generator = "^0.25.5"
[tool.poetry.group.docs] [tool.poetry.group.docs]
optional = true 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.""" """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 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 """File object used for uploading files to Zipline
Attributes: 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 id (int): ID of the file
mimetype (str): String of the file's mimetype mimetype (str): String of the file's mimetype
views (int): Integer of the number of views the file has views (int): Integer of the number of views the file has
name (str): String of the file's name name (str): String of the file's name
size (int): Integer of the file's size in bytes size (int): Integer of the file's size in bytes
favorite (bool): Boolean of whether the file is favorited 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 url (Optional[str]): String of the file's URL
max_views (Optional[int]): Integer of the file's maximum number of views maxViews (Optional[int]): Integer of the file's maximum number of views
expired_at (Optional[datetime]): Datetime object of when the file will expire expiredAt (Optional[datetime]): Datetime object of when the file will expire
thumbnail (Optional[str]): String of the file's thumbnail URL 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__( createdAt: datetime
self, id: int
createdAt: datetime, mimetype: str
id: int, # pylint: disable=redefined-builtin views: int
mimetype: str, name: str
views: int, size: int
name: str, favorite: bool
size: int, originalName: Optional[str] = None
favorite: bool, url: Optional[str] = None
originalName: str = None, maxViews: Optional[int] = None
url: str = None, expiredAt: Optional[datetime] = None
maxViews: int = None, thumbnail: Optional[str] = None
expiredAt: datetime = None, folderId: Optional[int] = 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)
def __str__(self): def __str__(self):
return self.name 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 """Result returned from low-level RestAdapter
Attributes: Attributes:
@ -67,50 +70,44 @@ class Result:
message (str = ''): Human readable result message (str = ''): Human readable result
data (Union[List[Dict], Dict]): Python List of Dictionaries (or maybe just a single Dictionary on error) 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): success: bool
self.success = success status_code: int
self.status_code = status_code message: str = ''
self.message = message data: Union[List[Dict], Dict] = {}
self.data = data if data else {}
def __str__(self): def __str__(self):
return f"{self.status_code}: {self.message}\n{self.data}" return f"{self.status_code}: {self.message}"
class TypesCountItem(BaseModel):
class Invite: """Model used in [StatsData](.#pyzipline.models.StatsData) for storing the number of files with a specific mimetype
"""Invite object used for managing invites
Attributes: Attributes:
id (int): Integer ID of the invite mimetype (str): String of the mimetype
code (str): String of the invite's code count (int): Integer of the number of files with this mimetype
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
""" """
def __init__( count: int
self, mimetype: str
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)
def __str__(self): 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: Attributes:
id (int): Integer ID of the stats id (int): Integer ID of the stats
@ -124,225 +121,64 @@ class Stats:
types_count (Optional[List[Mimetype]]): List of Mimetype objects types_count (Optional[List[Mimetype]]): List of Mimetype objects
count_by_user (Optional[List[CountByUser]]): List of CountByUser objects count_by_user (Optional[List[CountByUser]]): List of CountByUser objects
""" """
def __init__( size: str
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
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 count: int
): size_num: int
self.mimetype = mimetype count_users: int
self.count = count types_count: List[TypesCountItem]
views_count: int
count_by_user: List[CountByUserItem]
def __str__(self):
return f"{self.mimetype}: {self.count}"
class CountByUser: class Stats(BaseModel):
"""Object used in [Stats](.#pyzipline.models.Stats) for storing the number of files uploaded by a user """Stats model
Attributes: Attributes:
username (str): String of the username id (int): Integer ID of the stats
count (int): Integer of the number of files uploaded by this user""" createdAt (datetime): Datetime object of when the stats were created
def __init__( data (StatsData): StatsData object of the stats data
self, max_timestamp (Optional[datetime]): Datetime object of the maximum timestamp of the stats
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
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
""" """
def __init__( id: int
self, createdAt: datetime
id: int, # pylint: disable=redefined-builtin data: StatsData
provider: str, max_timestamp: str = Field(default=None)
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
class User: class Embed(BaseModel):
"""Object containing user information 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: class User(BaseModel):
id (int): Integer ID of the user id: int
uuid (str): String of the user's UUID uuid: str
username (str): String of the user's username username: str
avatar (Optional[str]): String of the user's avatar, base64 encoded avatar: Optional[str]
token (str): String of the user's token token: str
administrator (bool): Boolean of whether the user is an administrator administrator: bool
super_admin (bool): Boolean of whether the user is a super administrator superAdmin: bool
system_theme (str): String of the user's system theme systemTheme: str
embed (Embed): Embed object of the user's embed embed: Embed
totp_secret (Optional[str]): String of the user's TOTP secret ratelimit: None
domains (List[str]): List of Strings of the user's domains totpSecret: Optional[str]
oauth (Optional[List[OAuth]]): List of [OAuth](.#pyzipline.models.OAuth) objects domains: List[str]
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)
def __str__(self): def __str__(self):
return self.username return self.username
class Embed: class Versions(BaseModel):
"""Object containing a user's embed settings stable: str
upstream: str
current: str
Attributes:
color (Optional[str]): String of the embed's color class Version(BaseModel):
title (Optional[str]): String of the embed's title isUpstream: bool
site_name (Optional[str]): String of the embed's site name updateToType: str
description (Optional[str]): String of the embed's description versions: Versions
"""
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): def __str__(self):
if self.title is None: return self.versions.current
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']
def __str__(self):
return self.current

View file

@ -8,6 +8,7 @@ from urllib3 import disable_warnings
from pyzipline.exceptions import HTTPFailure, PyZiplineError from pyzipline.exceptions import HTTPFailure, PyZiplineError
from pyzipline.models import Result from pyzipline.models import Result
class RestAdapter: class RestAdapter:
"""Constructor for 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.""" """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 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.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 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: Args:
hostname (str): The hostname of your Zipline instance, WITHOUT https or http. 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. 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. 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__( def __init__(
self, self,
hostname: str, config: ZiplineApiConfig
token: str = '',
ssl: bool = True,
enforced_signing: bool = True,
logger: logging.Logger = None
): ):
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]]: def create_invite(self, expiry: timedelta = timedelta(days=1), count: int = 1) -> Union[Invite, List[Invite]]:
"""Create an invite code """Create an invite code
@ -302,11 +316,7 @@ class ZiplineApi:
""" """
result = self._rest_adapter.get(endpoint="auth/invite") result = self._rest_adapter.get(endpoint="auth/invite")
if result.status_code == 200: if result.status_code == 200:
invites = [] return [Invite(**invite) for invite in result.data]
for invite in result.data:
i = Invite(**invite)
invites.append(i)
return invites
if result.status_code == 401: if result.status_code == 401:
raise Forbidden(result.message) raise Forbidden(result.message)
if result.message == 'invites are disabled': if result.message == 'invites are disabled':
@ -417,11 +427,7 @@ class ZiplineApi:
""" """
result = self._rest_adapter.get(endpoint="users") result = self._rest_adapter.get(endpoint="users")
if result.status_code == 200: if result.status_code == 200:
users = [] return [User(**user) for user in result.data]
for user in result.data:
u = User(**user)
users.append(u)
return users
if result.status_code == 403: if result.status_code == 403:
raise Forbidden(result.message) raise Forbidden(result.message)
raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}") raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")
@ -445,7 +451,7 @@ class ZiplineApi:
/// ///
Args: 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 force_update (bool): Force the Zipline instance to update its statistics before returning them, requires administrator
Raises: Raises:
@ -463,14 +469,7 @@ class ZiplineApi:
else: else:
result = self._rest_adapter.get(endpoint="stats", params={'amount': amount}) result = self._rest_adapter.get(endpoint="stats", params={'amount': amount})
if result.status_code == 200: if result.status_code == 200:
if amount > 1: return [Stats(**stats) for stats in result.data]
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)
if result.status_code in (401, 403): if result.status_code in (401, 403):
raise Forbidden(result.message) raise Forbidden(result.message)
raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}") raise PyZiplineError(f"{result.status_code}: {result.message}\n{result.data}")