From eeff8e5871b54f737def8b27af5c03a1c643e568 Mon Sep 17 00:00:00 2001 From: leonardodalinky Date: Tue, 26 Sep 2023 02:15:46 +0800 Subject: [PATCH 1/2] chore(linter): add isort & black Configs for `isort` and `black` are placed in `pyproject.toml` Pre-commit hooks are set. Github action workflow `lint` is also added. Only checked push are permitted to trigger a release. --- .github/workflows/release.yml | 21 ++++++++++++ .pre-commit-config.yaml | 20 ++++++++++++ CONTRIBUTE.md | 39 +++++++++++++++++++++++ README.rst | 6 +++- TODO.md | 2 ++ pyproject.toml | 12 ++++++- warframe/worldstate/models/__init__.py | 16 +++++----- warframe/worldstate/models/event.py | 5 ++- warframe/worldstate/models/sortie.py | 2 +- warframe/worldstate/models/void_trader.py | 2 +- 10 files changed, 110 insertions(+), 15 deletions(-) create mode 100644 .pre-commit-config.yaml create mode 100644 CONTRIBUTE.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e7cc058..9a6bfb0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,10 +3,31 @@ on: push: branches: - main + pull_request: + branches: + - main + jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: 3.8 + - run: pip install -r requirements.txt + - uses: isort/isort-action@master + with: + isortVersion: '5.12.0' + - uses: psf/black@stable + with: + version: '23.9.0' + semantic-release: runs-on: ubuntu-latest + if: ${{ github.event_name == 'push' }} # wait until test & lint complete + needs: ['lint'] # needs: ['lint', 'test'] steps: - uses: actions/checkout@v3 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..39c0907 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,20 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-case-conflict + - id: trailing-whitespace + - id: end-of-file-fixer + - id: name-tests-test + - id: requirements-txt-fixer + - id: detect-private-key +- repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort + args: ["--profile", "black", "--line-length=100", "--python-version=38"] +- repo: https://github.com/psf/black + rev: 23.9.0 + hooks: + - id: black + args: ["--line-length=100", "--target-version=py38"] diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md new file mode 100644 index 0000000..2148f46 --- /dev/null +++ b/CONTRIBUTE.md @@ -0,0 +1,39 @@ +# Contributing to the project + +This project is still under construction. We welcome any contributions. Please **carefully** read the following instructions before contributing. + +## Code style + +We use `isort` with `black` to enforce a consistent code style. +```shell +pip install isort==5.12.0 black==23.9.0 +``` + +Configs can be found in `pyproject.toml`. + +CI also checks code style before pushing to `main` branch. Try to run `isort` and `black` locally before pushing to avoid unnecessary CI failures: +```shell +isort . +black . +``` + +### Pre-commit hook + +To automatically run `isort` and `black` before each commit, install `pre-commit`: +```shell +pip install pre-commit +``` + +Then run `pre-commit install` to install the hook. + +## Commit message + +Check out [this article](https://www.conventionalcommits.org/en/v1.0.0/) for a detailed explanation of how to write a good commit message. + +Commit messages started with `feat` will trigger a major version bump, `fix` will trigger a minor version bump. + +Also check out [semantic-release](https://github.com/semantic-release/semantic-release) for details. + +## Test + +⚠ Under construction. ⚠ diff --git a/README.rst b/README.rst index 1ca6325..77aec56 100644 --- a/README.rst +++ b/README.rst @@ -22,7 +22,7 @@ Quickstart .. code-block:: python - + import asyncio import logging @@ -69,3 +69,7 @@ Supported python versions: - 3.11 - 3.10 - 3.9 + +Contributing +------------ +Contributions are always welcome! Please read the `contributing guidelines `__ first. diff --git a/TODO.md b/TODO.md index b35ff9b..f2a4f91 100644 --- a/TODO.md +++ b/TODO.md @@ -9,6 +9,8 @@ endpoints - Item class inherits from WorldstateObject and MultiQueryModel - Put all major infos in the Item class (split them later) +- Test compatibility with Python 3.8 + ## Version 2.0 - Remove `WorldstateClient.query_list_of(type)` as `WorldstateClient.query(type)` now does the same while keeping the type. diff --git a/pyproject.toml b/pyproject.toml index 7fd26b9..30fce2d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,13 @@ [build-system] requires = ["setuptools"] -build-backend = "setuptools.build_meta" \ No newline at end of file +build-backend = "setuptools.build_meta" + +[tool.isort] +profile = "black" +py_version = "38" +line_length = 100 + +[tool.black] +line-length = 100 +target-version = ["py38"] +include = '\.pyi?$' diff --git a/warframe/worldstate/models/__init__.py b/warframe/worldstate/models/__init__.py index 3ef99cb..dd70dc2 100644 --- a/warframe/worldstate/models/__init__.py +++ b/warframe/worldstate/models/__init__.py @@ -1,16 +1,16 @@ from .alert import * +from .arbitration import * +from .archon_hunt import * from .cambion_drift import * from .cetus import * +from .counted_item import * from .daily_deal import * +from .event import * +from .fissure import * from .flash_sale import * +from .invasion import * +from .mission import * from .orb_vallis import * -from .arbitration import * -from .counted_item import * from .reward import * -from .mission import * -from .invasion import * -from .void_trader import * -from .fissure import * -from .archon_hunt import * from .sortie import * -from .event import * +from .void_trader import * diff --git a/warframe/worldstate/models/event.py b/warframe/worldstate/models/event.py index 50a2e95..3280d46 100644 --- a/warframe/worldstate/models/event.py +++ b/warframe/worldstate/models/event.py @@ -3,10 +3,9 @@ from msgspec import field -from .reward import Reward - from ..common import MultiQueryModel, TimedEvent -from ..enums import MissionType, Faction, Syndicate +from ..enums import Faction, MissionType, Syndicate +from .reward import Reward __all__ = ["Event"] diff --git a/warframe/worldstate/models/sortie.py b/warframe/worldstate/models/sortie.py index 9170665..968afe0 100644 --- a/warframe/worldstate/models/sortie.py +++ b/warframe/worldstate/models/sortie.py @@ -3,7 +3,7 @@ from msgspec import field from ..common import SingleQueryModel, TimedEvent -from ..enums import MissionType, Faction +from ..enums import Faction, MissionType __all__ = ["Sortie"] diff --git a/warframe/worldstate/models/void_trader.py b/warframe/worldstate/models/void_trader.py index 2a67cc1..a6dae8e 100644 --- a/warframe/worldstate/models/void_trader.py +++ b/warframe/worldstate/models/void_trader.py @@ -3,7 +3,7 @@ from msgspec import field -from ..common import SingleQueryModel, WorldstateObject, TimedEvent +from ..common import SingleQueryModel, TimedEvent, WorldstateObject __all__ = ["VoidTrader"] From ebf82cdd4806358a91b97d22fde39fcf8858f023 Mon Sep 17 00:00:00 2001 From: leonardodalinky Date: Tue, 26 Sep 2023 13:37:59 +0800 Subject: [PATCH 2/2] chore(linter): updating exsiting files --- examples/worldstate/custom_models.py | 5 +--- examples/worldstate/listeners.py | 8 ++---- examples/worldstate/query.py | 8 ++++-- warframe/worldstate/client.py | 40 ++++++--------------------- warframe/worldstate/enums/__init__.py | 2 +- 5 files changed, 18 insertions(+), 45 deletions(-) diff --git a/examples/worldstate/custom_models.py b/examples/worldstate/custom_models.py index 4518ab3..6e24edf 100644 --- a/examples/worldstate/custom_models.py +++ b/examples/worldstate/custom_models.py @@ -2,10 +2,7 @@ from typing import Literal from warframe.worldstate import WorldstateClient -from warframe.worldstate.common.core import ( # this import might change - SingleQueryModel, - TimedEvent, -) +from warframe.worldstate.common.core import SingleQueryModel, TimedEvent # this import might change class CustomCambionDrift(SingleQueryModel, TimedEvent): diff --git a/examples/worldstate/listeners.py b/examples/worldstate/listeners.py index e6c4978..302728f 100644 --- a/examples/worldstate/listeners.py +++ b/examples/worldstate/listeners.py @@ -31,12 +31,8 @@ async def on_cetus_state_change(cetus: Cetus): async def main(): - print( - (await client.query(OrbVallis)) - ) # this is just to have a reference to the current state - print( - (await client.query(Cetus)) - ) # this is just to have a reference to the current state + print((await client.query(OrbVallis))) # this is just to have a reference to the current state + print((await client.query(Cetus))) # this is just to have a reference to the current state on_vallis_state_change.start() # start the listener on_cetus_state_change.start() await asyncio.sleep(3600) # for testing, we wait an hour here diff --git a/examples/worldstate/query.py b/examples/worldstate/query.py index ce1700f..b8e1c3a 100644 --- a/examples/worldstate/query.py +++ b/examples/worldstate/query.py @@ -10,8 +10,12 @@ async def main(): async with WorldstateClient() as client: # import from models and pass the type you want the object of - arbi = await client.query(Arbitration) # of Type SingleQuery - a single object of type `Arbitration` - fissures = await client.query(Fissure) # of Type MultiQuery - a list of objects of type `Fissure` + arbi = await client.query( + Arbitration + ) # of Type SingleQuery - a single object of type `Arbitration` + fissures = await client.query( + Fissure + ) # of Type MultiQuery - a list of objects of type `Fissure` print(arbi) for fissure in fissures: diff --git a/warframe/worldstate/client.py b/warframe/worldstate/client.py index e59e9de..2b9dc28 100644 --- a/warframe/worldstate/client.py +++ b/warframe/worldstate/client.py @@ -2,17 +2,7 @@ import logging from datetime import datetime, timezone from functools import wraps -from typing import ( - Any, - Callable, - Coroutine, - List, - Optional, - Type, - TypeVar, - Union, - overload, -) +from typing import Any, Callable, Coroutine, List, Optional, Type, TypeVar, Union, overload import aiohttp import msgspec @@ -113,21 +103,15 @@ async def _request( url = build_endpoint(type, language) - logging.getLogger(__name__).debug( - f"Sending request to the {type.__name__} endpoint" - ) + logging.getLogger(__name__).debug(f"Sending request to the {type.__name__} endpoint") async with self._session.get(url) as response: response_text = await response.text() if response.status != 200: - raise WorldstateAPIError( - msgspec.json.decode(response_text, type=ErrorMessage) - ) + raise WorldstateAPIError(msgspec.json.decode(response_text, type=ErrorMessage)) - logging.getLogger(__name__).debug( - f"Got request from the {type.__name__} endpoint" - ) + logging.getLogger(__name__).debug(f"Got request from the {type.__name__} endpoint") return response_text @@ -227,9 +211,7 @@ async def get_cetus(self, language: Optional[Language] = None) -> Cetus: json = await self._request(Cetus, language) return Cetus._from_json(json) - async def get_cambion_drift( - self, language: Optional[Language] = None - ) -> CambionDrift: + async def get_cambion_drift(self, language: Optional[Language] = None) -> CambionDrift: json = await self._request(CambionDrift, language) return CambionDrift._from_json(json) @@ -237,9 +219,7 @@ async def get_orb_vallis(self, language: Optional[Language] = None) -> OrbVallis json = await self._request(OrbVallis, language) return OrbVallis._from_json(json) - async def get_alerts( - self, language: Optional[Language] = None - ) -> Optional[List[Alert]]: + async def get_alerts(self, language: Optional[Language] = None) -> Optional[List[Alert]]: json = await self._request(OrbVallis, language) return Alert._from_json(json) @@ -273,12 +253,8 @@ def listen_to(self, type: Type[SingleQueryTimedEvent]): Returns: _TaskHelper: A helper class that wraps the callback function. Call `.start()` on it in order to start the listener. Same goes for `.stop()` """ - if not issubclass(type, SingleQueryModel) and not not issubclass( - type, TimedEvent - ): - raise TypeError( - f"{type.__name__} has to implement SingleQueryModel and TimedEvent" - ) + if not issubclass(type, SingleQueryModel) and not not issubclass(type, TimedEvent): + raise TypeError(f"{type.__name__} has to implement SingleQueryModel and TimedEvent") def decorator( func: Callable[[SingleQueryTimedEvent], Coroutine[Any, Any, None]] diff --git a/warframe/worldstate/enums/__init__.py b/warframe/worldstate/enums/__init__.py index 1271f6b..f9fcddf 100644 --- a/warframe/worldstate/enums/__init__.py +++ b/warframe/worldstate/enums/__init__.py @@ -1,4 +1,4 @@ from .faction import * -from .mission_type import * from .language import * +from .mission_type import * from .syndicate import Syndicate