Skip to content

Commit

Permalink
rewrite to use pdm and updated ruff (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
AbstractUmbra authored Dec 28, 2024
1 parent 42036aa commit 8705e88
Show file tree
Hide file tree
Showing 10 changed files with 1,735 additions and 1,532 deletions.
70 changes: 24 additions & 46 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,58 +27,36 @@ jobs:
with:
fetch-depth: 0

- name: "Load cached poetry installation @ ${{ matrix.python-version }}"
id: cached-poetry
uses: actions/cache@v4
- name: "Setup PDM @ ${{ matrix.python-version }}"
uses: pdm-project/setup-pdm@v4
with:
path: ~/.local
key: poetry-0
python-version: ${{matrix.python-version}}
cache: true

- name: "Setup Poetry @ ${{ matrix.python-version }}"
if: steps.cached-poetry.outputs.cache-hit != 'true'
uses: snok/install-poetry@v1
with:
version: latest
virtualenvs-create: true
virtualenvs-in-project: true
virtualenvs-path: ~/.venv

- name: "Setup Python @ ${{ matrix.python-version }}"
id: setup-python
uses: actions/setup-python@v5
with:
python-version: "${{ matrix.python-version }}"
cache: "poetry"

- name: "Load cached venv @ ${{ matrix.python-version }}"
id: cached-pip-wheels
uses: actions/cache@v4
with:
path: .venv/
key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}

- name: "Install Python deps @ ${{ matrix.python-version }}"
if: ${{ steps.cached-pip-wheels.outputs.cache-hit != 'true' }}
id: install-deps
- name: "Install deps @ ${{ matrix.python-version }}"
run: |
poetry install --no-interaction
pdm install --prod --check --no-editable
- name: Activate venv @ ${{ matrix.python-version }}
- name: "Activate venv @ ${{ matrix.python-version }}"
run: |
echo "$(poetry env info --path)/bin" >> $GITHUB_PATH
echo "$(pdm info --where)/.venv/bin" >> $GITHUB_PATH
- name: "Check it imports @ ${{ matrix.python-version }}"
run: |
poetry run python -c 'import mystbin'
pdm run python -c 'import hondana'
- name: "Test Suite @ ${{ matrix.python-version }}"
run: |
pdm run tests
- name: "Build wheels @ ${{ matrix.python-version}}"
run: |
poetry build
pdm build
- name: "Build docs @ ${{ matrix.python-version}}"
working-directory: docs/
run: |
cd docs/
poetry run sphinx-build -aETW --keep-going . build
pdm run docs
- name: "Upload artifacts @ ${{ matrix.python-version}}"
if: ${{ matrix.python-version != '3.x' }}
Expand All @@ -94,6 +72,9 @@ jobs:
needs: [build]
runs-on: ubuntu-latest
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/')
permissions:
contents: read
id-token: write

steps:
- uses: actions/checkout@v4
Expand All @@ -120,15 +101,12 @@ jobs:
tag_name="${GITHUB_REF##*/}"
gh release create "$tag_name" -F "CHANGELOG.md" "${assets[@]}"
- name: "Set up Poetry"
uses: snok/install-poetry@v1
- name: Set up PDM
uses: pdm-project/setup-pdm@v4
with:
virtualenvs-create: true
virtualenvs-in-project: false
python-version: 3.8
cache: true

- name: Publish to PyPI
env:
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
run: |
poetry config pypi-token.pypi $PYPI_TOKEN
poetry publish
pdm publish
54 changes: 16 additions & 38 deletions .github/workflows/coverage_and_lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,54 +24,32 @@ jobs:
with:
fetch-depth: 0

- name: "Load cached poetry installation @ ${{ matrix.python-version }}"
id: cached-poetry
uses: actions/cache@v4
- name: Setup PDM @ ${{ matrix.python-version }}
uses: pdm-project/setup-pdm@v4
with:
path: ~/.local
key: poetry-0
python-version: ${{ matrix.python-version }}
cache: true

- name: "Setup Poetry @ ${{ matrix.python-version }}"
if: steps.cached-poetry.outputs.cache-hit != 'true'
uses: snok/install-poetry@v1
with:
version: latest
virtualenvs-create: true
virtualenvs-in-project: true
virtualenvs-path: .venv

- name: "Setup Python @ ${{ matrix.python-version }}"
id: setup-python
uses: actions/setup-python@v5
with:
python-version: "${{ matrix.python-version }}"
cache: "poetry"

- name: "Load cached venv @ ${{ matrix.python-version }}"
id: cached-pip-wheels
uses: actions/cache@v4
with:
path: ~/.venv/
key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}

- name: "Install Python deps @ ${{ matrix.python-version }}"
if: ${{ steps.cached-pip-wheels.outputs.cache-hit != 'true' }}
id: install-deps
- name: Install deps @ ${{ matrix.python-version }}
run: |
poetry install --all-extras -n --no-cache --no-interaction
pdm install --check --no-editable
- name: Activate venv @ ${{ matrix.python-version }}
run: |
echo "$(poetry env info --path)/bin" >> $GITHUB_PATH
echo "$(pdm info --where)/.venv/bin" >> $GITHUB_PATH
- name: "Run Pyright @ ${{ matrix.python-version }}"
uses: jakebailey/pyright-action@v2
with:
warnings: false
verify-types: "mystbin"
ignore-external: true
no-comments: ${{ matrix.python-version != '3.x' }}
annotate: "${{ matrix.python-version != '3.x' }}"

- name: Lint check
uses: astral-sh/ruff-action@v2
with:
args: check .

- name: Lint
if: ${{ always() && steps.install-deps.outcome == 'success' }}
- name: Formatting check
uses: chartboost/ruff-action@v1
with:
args: format --check
10 changes: 8 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
.vscode/
*.py[cod]
.venv/
.env
venv/
.ruff_cache/
.pdm-python

.vscode/
.idea/

docs/build
dist/
.ruff_cache/
.pdm-build/
4 changes: 2 additions & 2 deletions mystbin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
DEALINGS IN THE SOFTWARE.
"""

__version__ = "7.0.2"
__version__ = "7.1.0"

from typing import Literal, NamedTuple

Expand All @@ -39,6 +39,6 @@ class VersionInfo(NamedTuple):
serial: int


version_info: VersionInfo = VersionInfo(major=7, minor=0, micro=2, releaselevel="final", serial=0)
version_info: VersionInfo = VersionInfo(major=7, minor=1, micro=0, releaselevel="final", serial=0)

del NamedTuple, Literal, VersionInfo
11 changes: 7 additions & 4 deletions mystbin/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,22 @@ class Client:
If not provided, a new session will be created.
api_base: :class:`str`
The base URL for the mystbin instance.
Defaults to ``https://mystb.in/``.
This should begin with ``https://`` and should be the root URL of the mystbin instance.
Defaults to ``mystb.in``.
"""

__slots__ = ("http",)

def __init__(self, *, session: ClientSession | None = None, api_base: str = "https://mystb.in/") -> None:
def __init__(self, *, session: ClientSession | None = None, api_base: str = "mystb.in") -> None:
self.http: HTTPClient = HTTPClient(session=session, api_base=api_base)

async def __aenter__(self) -> Self:
return self

async def __aexit__(
self, exc_cls: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None
self,
exc_cls: type[BaseException] | None,
exc_value: BaseException | None,
traceback: TracebackType | None,
) -> None:
await self.close()

Expand Down
43 changes: 22 additions & 21 deletions mystbin/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
"""
""" # noqa: A005 # we access this via namespace

from __future__ import annotations

Expand Down Expand Up @@ -52,7 +52,6 @@
T = TypeVar("T")
Response = Coroutine[None, None, T]
MU = TypeVar("MU", bound="MaybeUnlock")
BE = TypeVar("BE", bound=BaseException)
from .types.responses import CreatePasteResponse, GetPasteResponse


Expand All @@ -69,8 +68,14 @@ def _clean_dt(dt: datetime.datetime) -> str:
return dt.isoformat()


async def json_or_text(response: aiohttp.ClientResponse, /) -> dict[str, Any] | str:
"""A quick method to parse a `aiohttp.ClientResponse` and test if it's json or text."""
async def _json_or_text(response: aiohttp.ClientResponse, /) -> dict[str, Any] | str:
"""A quick method to parse a `aiohttp.ClientResponse` and test if it's json or text.
Returns
--------
Union[Dict[:class:`str`, Any], :class:`str`]
The JSON object, or request text.
"""
text = await response.text(encoding="utf-8")
try:
if response.headers["content-type"] == "application/json":
Expand All @@ -97,8 +102,8 @@ def defer(self) -> None:

def __exit__(
self,
exc_type: type[BE] | None,
exc: BE | None,
exc_type: type[BaseException] | None,
exc: BaseException | None,
traceback: TracebackType | None,
) -> None:
if self._unlock:
Expand All @@ -115,14 +120,14 @@ class Route:
API_BASE: ClassVar[str] = "https://mystb.in/api"

def __init__(self, verb: SupportedHTTPVerb, path: str, **params: Any) -> None:

self.verb: SupportedHTTPVerb = verb
self.path: str = path
url = self.API_BASE + path
if params:
url = url.format_map({k: _uriquote(v) if isinstance(v, str) else v for k, v in params.items()})
self.url: str = url


class HTTPClient:
__slots__ = (
"_async",
Expand All @@ -131,7 +136,7 @@ class HTTPClient:
"_session",
"_token",
"api_base",
"user_agent"
"user_agent",
)

def __init__(self, *, session: aiohttp.ClientSession | None = None, api_base: str | None = None) -> None:
Expand All @@ -142,12 +147,9 @@ def __init__(self, *, session: aiohttp.ClientSession | None = None, api_base: st
self.user_agent: str = user_agent.format(__version__, sys.version_info, aiohttp.__version__)
self._resolve_api(api_base)

def _resolve_api(self, api: str | None) -> None:
if api:
Route.API_BASE = api + "api" if api.endswith("/") else api + "/api"
self.api_base = api + ("/" if not api.endswith("/") else "")
else:
self.api_base = "https://mystb.in/"
def _resolve_api(self, api_base: str | None, /) -> None:
if api_base:
Route.API_BASE = f"https://{api_base}/api"

async def close(self) -> None:
if self._session and self._owns_session:
Expand Down Expand Up @@ -194,28 +196,28 @@ async def request(self, route: Route, **kwargs: Any) -> Any:
retry = response.headers.get("x-ratelimit-retry-after", None)
LOGGER.debug("retry is: %s", retry)
if retry is not None:
retry = datetime.datetime.fromtimestamp(int(retry))
retry = datetime.datetime.fromtimestamp(int(retry), tz=datetime.timezone.utc)
# The total ratelimit session hits
limit = response.headers.get("x-ratelimit-limit", None)
LOGGER.debug("limit is: %s", limit)

if remaining == "0" and response.status != 429:
assert retry is not None
delta = retry - datetime.datetime.now()
delta = retry - datetime.datetime.now(datetime.timezone.utc)
sleep = delta.total_seconds() + 1
LOGGER.warning("A ratelimit has been exhausted, sleeping for: %d", sleep)
maybe_lock.defer()
loop = asyncio.get_running_loop()
loop.call_later(sleep, lock.release)

data = await json_or_text(response)
data = await _json_or_text(response)

if 300 > response.status >= 200:
return data

if response.status == 429:
assert retry is not None
delta = retry - datetime.datetime.now()
delta = retry - datetime.datetime.now(datetime.timezone.utc)
sleep = delta.total_seconds() + 1
LOGGER.warning("A ratelimit has been hit, sleeping for: %d", sleep)
await asyncio.sleep(sleep)
Expand All @@ -227,15 +229,14 @@ async def request(self, route: Route, **kwargs: Any) -> Any:
await asyncio.sleep(sleep_)
continue

print(data)
assert isinstance(data, dict)
LOGGER.exception("Unhandled HTTP error occurred: %s -> %s", response.status, data)
raise APIException(
response=response,
status_code=response.status,
)
except (aiohttp.ServerDisconnectedError, aiohttp.ServerTimeoutError) as error:
LOGGER.exception("Network error occurred: %s", error)
except (aiohttp.ServerDisconnectedError, aiohttp.ServerTimeoutError):
LOGGER.exception("Network error occurred:")
await asyncio.sleep(5)
continue

Expand Down
Loading

0 comments on commit 8705e88

Please sign in to comment.