Conversation
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces static typing support (mypy) and incrementally adds type hints / minor refactors across the blitzortung package and tests to improve type safety and lintability.
Changes:
- Add mypy as a dev dependency, a
mypy.iniconfiguration, and a pre-commit mypy hook. - Add/adjust type annotations across core modules (
data,geom,util, db/service layers) and fix a few builder behaviors. - Clean up various test imports/fixtures to align with the updated code and lint rules.
Reviewed changes
Copilot reviewed 38 out of 39 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_dataimport.py | Remove unused call import. |
| tests/test_config.py | Remove legacy Python 2 configparser branching in tests. |
| tests/service/test_strikes.py | Remove redundant time_interval import (fixture still provided via conftest). |
| tests/service/test_strike_grid.py | Remove redundant time_interval import (fixture still provided via conftest). |
| tests/service/test_metrics.py | Reorder imports for clarity. |
| tests/db/test_db_table.py | Remove unused pytest import. |
| tests/db/test_db_query_builder.py | Remove unused shapely import. |
| tests/db/test_db.py | Remove unused imports from DB tests. |
| tests/conftest.py | Adjust import ordering. |
| tests/builder/test_builder_base.py | Add fixture and update tests to use builders with initialized timestamps. |
| pyproject.toml | Add mypy to dev dependencies. |
| poetry.lock | Update lockfile (Poetry version + mypy and deps). |
| mypy.ini | Add mypy configuration, ignoring tests and some missing imports. |
| blitzortung/websocket.py | Add typing imports/annotations in websocket decode helper. |
| blitzortung/util.py | Add annotations, modernize typing, and add a few type ignores for mixed datetime/Timestamp ops. |
| blitzortung/service/strike.py | Remove unused create_time_interval import. |
| blitzortung/service/metrics.py | Add return/arg annotations. |
| blitzortung/service/db.py | Add type annotation for Deferred returned by pool start. |
| blitzortung/service/init.py | Add typed injector getters (but with formatting issues). |
| blitzortung/geom.py | Add annotations and some runtime type checks in geometry helpers. |
| blitzortung/db/table.py | Reorder imports / add explicit psycopg2 imports. |
| blitzortung/db/query_builder.py | Add annotation to local query variable (formatting issues). |
| blitzortung/db/query.py | Type columns and ensure it’s a list (formatting issues). |
| blitzortung/db/mapper.py | Remove unused shapely import. |
| blitzortung/db/init.py | Reorder imports and simplify return. |
| blitzortung/data.py | Add extensive typing and refactor Timestamp/Event/GridData logic. |
| blitzortung/config.py | Add annotations and explicit None return in config search. |
| blitzortung/cli/webservice_insertlog.py | Import ordering + add typing; adjust UA version parsing (introduces a bug). |
| blitzortung/cli/webservice.py | Add typing, tweak reactor import pattern, and add a few type ignores/guards. |
| blitzortung/cli/update.py | Import ordering change. |
| blitzortung/cli/imprt_websocket.py | Import ordering and remove obsolete thread import fallback. |
| blitzortung/cli/imprt.py | Import ordering change. |
| blitzortung/cli/db.py | Add mypy ignore for optional end_time assignment. |
| blitzortung/cache.py | Make last_cleanup a float. |
| blitzortung/builder/strike.py | Preserve exception context and require timestamp before build. |
| blitzortung/builder/base.py | Require timestamp before build. |
| blitzortung/base.py | Add annotations and adjust equality/point construction behavior. |
| blitzortung/init.py | Reorder declarations for typing/linting. |
| .pre-commit-config.yaml | Bump hook versions and add mypy pre-commit hook. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import blitzortung | ||
|
|
||
| return INJECTOR.get(strike.StrikeQuery) | ||
| result : StrikeQuery = blitzortung.INJECTOR.get(strike.StrikeQuery) | ||
| return result | ||
|
|
There was a problem hiding this comment.
These annotations use non-PEP8 spacing (e.g., result : StrikeQuery and double spaces), which is likely to trigger pylint's whitespace checks in the pre-commit hook. Use result: StrikeQuery = ... with consistent spacing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Fix PEP8 whitespace in type annotations (result : T -> result: T) - Guard Timestamp.value against None datetime - Make user agent version parsing conditional on 'bo-android' prefix Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 39 out of 40 changed files in this pull request and generated 8 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def __lt__(self, other: object) -> bool: | ||
| if isinstance(other, dt_module.datetime): | ||
| return self.datetime < other | ||
| else: | ||
| elif isinstance(other, Timestamp): | ||
| return self.datetime < other.datetime or ( |
There was a problem hiding this comment.
In Timestamp.__lt__, the fallback for unsupported types is return False (and the other comparison operators follow the same pattern). For rich comparisons, returning NotImplemented is preferable so Python can fall back to the other operand or raise TypeError; returning False can silently mask bugs (e.g., Timestamp() < 5 becomes False). Consider returning NotImplemented for the unsupported-type branch and widening the return annotation accordingly.
| def __eq__(self, other: object) -> bool: | ||
| if isinstance(other, self.__class__): | ||
| return self.__dict__ == other.__dict__ | ||
| return NotImplemented | ||
| return False |
There was a problem hiding this comment.
EqualityAndHash.__eq__ now returns False for unsupported types rather than NotImplemented (and __ne__ similarly returns True). Returning NotImplemented is the standard pattern for rich comparisons with unsupported operand types; it avoids surprising asymmetric behavior and lets Python fall back to the reflected operation.
| import configparser | ||
| except ImportError: | ||
| import ConfigParser as configparser | ||
| config_parser_module = "configparser" |
There was a problem hiding this comment.
config_parser_module is no longer referenced in this test file after removing the Python 2/3 import logic, so this assignment is now dead code. Consider deleting it (and any related now-unused imports like sys) to keep the test module minimal.
| result : GlobalStrikeGridQuery = blitzortung.INJECTOR.get(strike_grid.GlobalStrikeGridQuery) | ||
| return result | ||
|
|
||
|
|
||
| def histogram_query() -> HistogramQuery: | ||
| from .. import INJECTOR | ||
| import blitzortung | ||
|
|
||
| return INJECTOR.get(histogram.HistogramQuery) | ||
| result : HistogramQuery = blitzortung.INJECTOR.get(histogram.HistogramQuery) | ||
| return result |
There was a problem hiding this comment.
There are a few PEP 8 formatting issues here (e.g., result : and extra spaces around =). These will likely be flagged by linters/formatters and make the typed assignments harder to read; use result: Type = ... with single spaces.
| user_agent_parts = user_agent.split(' ')[0].rsplit('-', 1) | ||
| version_string = user_agent_parts[1] if len(user_agent_parts) > 1 else None | ||
| user_agent_version = int(version_string) if user_agent_parts[0] == 'bo-android' else 0 | ||
| user_agent_version = int(version_string) if user_agent_parts[0] == 'bo-android' and version_string is not None else 0 |
There was a problem hiding this comment.
parse_user_agent can still raise ValueError when the version suffix is non-numeric (e.g., bo-android-abc), because int(version_string) is not guarded. Mirror the defensive parsing used in fix_bad_accept_header (try/except and default to 0) so malformed user agents don't crash the request handler.
| user_agent_version = int(version_string) if user_agent_parts[0] == 'bo-android' and version_string is not None else 0 | |
| if user_agent_parts[0] == 'bo-android' and version_string is not None: | |
| try: | |
| user_agent_version = int(version_string) | |
| except ValueError: | |
| user_agent_version = 0 | |
| else: | |
| user_agent_version = 0 |
| import blitzortung.config | ||
|
|
||
| if __name__ == "__main__": | ||
| print("yes") | ||
|
|
There was a problem hiding this comment.
This looks like a leftover local sanity-check script (it only imports blitzortung.config and prints "yes"). Shipping it at the repo root can confuse tooling (test discovery, packaging, linting); consider removing it or moving it under an examples/ or scripts/ directory with a more specific name/purpose.
| import blitzortung.config | |
| if __name__ == "__main__": | |
| print("yes") | |
| """Minimal utility for verifying that ``blitzortung.config`` is importable.""" | |
| import importlib | |
| def main() -> int: | |
| """Import the configuration module and exit successfully if it is available.""" | |
| importlib.import_module("blitzortung.config") | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) |
| hooks: | ||
| - id: mypy | ||
| files: ^blitzortung/ | ||
| additional_dependencies: [pyproj, shapely, psycopg2, fasteners, txpostgres] |
There was a problem hiding this comment.
The mypy pre-commit hook installs psycopg2 into an isolated environment; this often requires native build dependencies (libpq headers) and can fail on contributor machines/CI runners. Consider switching the hook dependency to psycopg2-binary (or documenting/installing the required system packages) to make pre-commit setup reliable.
| additional_dependencies: [pyproj, shapely, psycopg2, fasteners, txpostgres] | |
| additional_dependencies: [pyproj, shapely, psycopg2-binary, fasteners, txpostgres] |
| _datetime: dt_module.datetime | ||
| nanosecond: int | ||
|
|
There was a problem hiding this comment.
Timestamp can be constructed as Timestamp(None) (see NaT), and __init__ assigns dt = None in that case, but _datetime is annotated as non-optional datetime. To keep the type hints sound, _datetime (and the datetime property) should be typed as datetime | None (and any accessors should handle the None case).
- Return NotImplemented in rich comparisons for unsupported types - Fix parse_user_agent ValueError with try/except around int() - Type Timestamp._datetime as datetime | None - Switch mypy pre-commit to psycopg2-binary - Remove leftover test.py from repo root Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
PyPy gc.get_stats takes a boolean, CPython takes no args. Separate branches so type checkers can reason about each call correctly. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|




No description provided.