Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a GHA workflow to run tests and pre-commit checks #2

Merged
merged 2 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
name: test

on:
pull_request:
types:
- opened
- reopened
- synchronize
push:
branches:
- main

jobs:
changed-files:
runs-on: ubuntu-latest
outputs:
should_run_pytest: ${{ steps.check-pytest.outputs.src }}
steps:
- name: Checkout repository
uses: actions/checkout@v4

- id: check-pytest
name: Should run pytest
uses: dorny/paths-filter@v3
with:
filters: |
src:
- "async_batcher/**"
- "tests/**"
- "poetry.lock"

pytest:
needs: changed-files
if: ${{ needs.changed-files.outputs.should_run_pytest == 'true' }}
strategy:
fail-fast: false
matrix:
os: [ "ubuntu-latest", "macos-latest" ]
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ]
runs-on: ${{ matrix.os }}
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up python ${{ matrix.python-version }}
id: setup-python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-create: true
virtualenvs-in-project: true

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

- name: Install dependencies
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
run: poetry install --no-interaction --no-root --all-extras

- name: Install library
run: poetry install --no-interaction --all-extras

- name: Run tests
run: |
source .venv/bin/activate
pytest tests/

linter:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up python 3.11
uses: actions/setup-python@v5
with:
python-version: 3.11

- name: Install pre-commit
run: pip install pre-commit

- name: Run pre-commit
run: pre-commit run --all-files
20 changes: 11 additions & 9 deletions async_batcher/batcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import asyncio
import logging
from collections import namedtuple
from typing import Generic, TypeVar, Union
from typing import Generic, TypeVar

T = TypeVar("T")
S = TypeVar("S")
Expand Down Expand Up @@ -38,7 +38,7 @@ def __init__(
self.max_batch_size = max_batch_size
self.max_queue_time = max_queue_time
self._queue = asyncio.Queue()
self._current_task: Union[asyncio.Task, None] = None
self._current_task: asyncio.Task | None = None
self._should_stop = False
self._force_stop = False
self._is_running = False
Expand Down Expand Up @@ -102,7 +102,9 @@ async def batch_run(self):
if asyncio.iscoroutinefunction(self.process_batch):
results = await self.process_batch(batch=batch_items)
else:
results = await asyncio.get_event_loop().run_in_executor(None, self.process_batch, batch_items)
results = await asyncio.get_event_loop().run_in_executor(
None, self.process_batch, batch_items
)
if results is None:
results = [None] * len(batch)
if len(results) != len(batch):
Expand All @@ -115,13 +117,9 @@ async def batch_run(self):
for q_item, result in zip(batch, results):
q_item.future.set_result(result)
elapsed_time = asyncio.get_event_loop().time() - started_at
self.logger.debug(
f"Processed batch of {len(batch)} elements"
f" in {elapsed_time} seconds."
)
self.logger.debug(f"Processed batch of {len(batch)} elements" f" in {elapsed_time} seconds.")
self._is_running = False


def stop(self, force: bool = False):
"""Stop the batcher asyncio task.

Expand All @@ -132,5 +130,9 @@ def stop(self, force: bool = False):
if force:
self._force_stop = True
self._should_stop = True
if self._current_task and not self._current_task.done() and not self._current_task.get_loop().is_closed():
if (
self._current_task
and not self._current_task.done()
and not self._current_task.get_loop().is_closed()
):
self._current_task.get_loop().run_until_complete(self._current_task)
3 changes: 1 addition & 2 deletions examples/dynamodb/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
import aioboto3
from async_batcher.aws.dynamodb.get import AsyncDynamoDbGetBatcher, GetItem
from async_batcher.aws.dynamodb.write import AsyncDynamoDbWriteBatcher, WriteOperation
from pydantic import BaseModel

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

Expand Down
8 changes: 6 additions & 2 deletions examples/keras/main.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from __future__ import annotations

import asyncio
import gc
from typing import TYPE_CHECKING

import keras.src.engine.sequential
import tensorflow as tf
from async_batcher.batcher import AsyncBatcher
from fastapi import FastAPI

if TYPE_CHECKING:
import keras.src.engine.sequential


class MlBatcher(AsyncBatcher[list[float], list[float]]):
def __init__(self, model, *args, **kwargs):
Expand All @@ -24,10 +26,12 @@ def process_batch(self, batch: list[list[float]]) -> list[float]:

batcher = MlBatcher(model=model, max_queue_time=0.001)


@app.on_event("startup")
async def startup_event():
gc.freeze()


@app.on_event("shutdown")
def shutdown_event():
batcher.stop()
Expand Down
Loading