Skip to content

Commit

Permalink
Merge pull request #183 from ASFHyP3/mypy
Browse files Browse the repository at this point in the history
Add mypy
  • Loading branch information
jtherrmann authored Jan 22, 2025
2 parents c8b60d4 + 1eb6b4c commit d8feac5
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 8 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ jobs:
# Docs: https://github.com/ASFHyP3/actions
uses: ASFHyP3/actions/.github/workflows/[email protected]

call-mypy-workflow:
uses: ASFHyP3/actions/.github/workflows/[email protected]

cfn-lint:
runs-on: ubuntu-latest
steps:
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [PEP 440](https://www.python.org/dev/peps/pep-0440/)
and uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.4]
### Added
- Add `mypy` to [`static-analysis`](.github/workflows/static-analysis.yml)

### Fixed
- Decimal values in our API responses have been incorrectly serialized as strings rather than numbers since at least [v0.1.0](https://github.com/ASFHyP3/hyp3-event-monitoring/pull/79), which broke our custom JSON encoder by pinning to `flask==3.0.3` (`flask` was previously unpinned). The `json_encoder` app attribute was removed in [Flask v2.3.0](https://github.com/pallets/flask/blob/main/CHANGES.rst#version-230). This release fixes this issue by subclassing `flask.json.provider.JSONProvider`. Also see https://github.com/pallets/flask/pull/4692 and [HyP3 v9.0.0](https://github.com/ASFHyP3/hyp3/releases/tag/v9.0.0).

## [0.1.3]
### Changed
- The [`static-analysis`](.github/workflows/static-analysis.yml) Github Actions workflow now uses `ruff` rather than `flake8` for linting.
Expand Down
13 changes: 12 additions & 1 deletion api/src/api.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import json
from datetime import datetime, timedelta, timezone
from decimal import Decimal
from json import JSONEncoder
from typing import Any

from flask import Flask, abort, jsonify
from flask.json.provider import JSONProvider
from flask_cors import CORS
from serverless_wsgi import handle_request

Expand All @@ -18,9 +21,17 @@ def default(self, o):
return super(DecimalEncoder, self).default(o)


class CustomJSONProvider(JSONProvider):
def dumps(self, obj: Any, **kwargs) -> str:
return json.dumps(obj, cls=DecimalEncoder)

def loads(self, s: str | bytes, **kwargs) -> Any:
return json.loads(s)


app = Flask(__name__)
CORS(app)
app.json_encoder = DecimalEncoder
app.json = CustomJSONProvider(app)


@app.route('/events')
Expand Down
4 changes: 2 additions & 2 deletions database/database/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def get_event(event_id: str) -> dict:
return response['Item']


def get_products_for_event(event_id: str, status_code: str = None) -> List[dict]:
def get_products_for_event(event_id: str, status_code: str | None = None) -> List[dict]:
key_expression = Key('event_id').eq(event_id)
if status_code:
filter_expression = Attr('status_code').eq(status_code)
Expand All @@ -61,7 +61,7 @@ def get_products_for_event(event_id: str, status_code: str = None) -> List[dict]
return query_table(PRODUCT_TABLE, key_expression)


def get_products_by_status(status_code: str, processed_since: datetime = None) -> List[dict]:
def get_products_by_status(status_code: str, processed_since: datetime | None = None) -> List[dict]:
key_expression = Key('status_code').eq(status_code)
if processed_since:
key_expression &= Key('processing_date').gte(processed_since.isoformat(timespec='seconds'))
Expand Down
9 changes: 9 additions & 0 deletions environment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: hyp3-event-monitoring
channels:
- conda-forge
- nodefaults
dependencies:
- python=3.12
- pip
- pip:
- -r requirements-all.txt
15 changes: 14 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "hyp3_event_monitoring"
requires-python = ">=3.10"
requires-python = "==3.12"

[tool.ruff]
line-length = 120
Expand Down Expand Up @@ -32,3 +32,16 @@ convention = "google"
[tool.ruff.lint.isort]
case-sensitive = true
lines-after-imports = 2

[tool.mypy]
python_version = "3.12"
warn_redundant_casts = true
warn_unused_ignores = true
warn_unreachable = true
strict_equality = true
check_untyped_defs = true
install_types = true
non_interactive = true
pretty = true
disable_error_code = ["import-untyped"]
exclude = ["/build/"]
1 change: 1 addition & 0 deletions requirements-all.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
boto3==1.35.82
cfn-lint==1.22.2
ruff
mypy
pytest==8.3.4
moto==5.0.23
responses==0.25.3
Expand Down
14 changes: 10 additions & 4 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@

def seed_data(tables):
events = [
{'event_id': 'event1', 'decimal_value': Decimal(1.0)},
{
'event_id': 'event2',
},
{'event_id': 'event1', 'int_decimal_value': Decimal('1.0'), 'float_decimal_value': Decimal('1.1')},
{'event_id': 'event2'},
]
for event in events:
tables.event_table.put_item(Item=event)
Expand Down Expand Up @@ -68,6 +66,14 @@ def test_event_by_id(api_client, tables):
assert response.get_json()['event_id'] == 'event1'
assert response.get_json()['products'] == []

int_decimal_value = response.get_json()['int_decimal_value']
assert isinstance(int_decimal_value, int)
assert int_decimal_value == 1

float_decimal_value = response.get_json()['float_decimal_value']
assert isinstance(float_decimal_value, float)
assert float_decimal_value == 1.1

response = api_client.get('/events/event2')
assert response.status_code == 200
assert response.get_json()['event_id'] == 'event2'
Expand Down

0 comments on commit d8feac5

Please sign in to comment.