Skip to content

Commit a6ea003

Browse files
authored
Merge pull request #1905 from cmu-delphi/ds/lint
feat: unify linter settings across indicators and add incremental formatting
2 parents f011857 + 3794513 commit a6ea003

File tree

48 files changed

+237
-334
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+237
-334
lines changed

.git-blame-ignore-revs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# Format geomap.py
22
d4b056e7a4c11982324e9224c9f9f6fd5d5ec65c
33
# Format test_geomap.py
4-
79072dcdec3faca9aaeeea65de83f7fa5c00d53f
4+
79072dcdec3faca9aaeeea65de83f7fa5c00d53f
5+
# Sort setup.py dependencies
6+
6912077acba97e835aff7d0cd3d64309a1a9241d

.github/workflows/python-ci.yml

+33-16
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,40 @@ jobs:
1616
if: github.event.pull_request.draft == false
1717
strategy:
1818
matrix:
19-
packages:
20-
[
21-
_delphi_utils_python,
22-
changehc,
23-
claims_hosp,
24-
doctor_visits,
25-
google_symptoms,
26-
hhs_hosp,
27-
nchs_mortality,
28-
nwss_wastewater,
29-
quidel_covidtest,
30-
sir_complainsalot,
31-
]
19+
include:
20+
- package: "_delphi_utils_python"
21+
dir: "delphi_utils"
22+
- package: "changehc"
23+
dir: "delphi_changehc"
24+
- package: "claims_hosp"
25+
dir: "delphi_claims_hosp"
26+
- package: "doctor_visits"
27+
dir: "delphi_doctor_visits"
28+
- package: "google_symptoms"
29+
dir: "delphi_google_symptoms"
30+
- package: "hhs_hosp"
31+
dir: "delphi_hhs"
32+
- package: "nchs_mortality"
33+
dir: "delphi_nchs_mortality"
34+
- package: "nwss_wastewater"
35+
dir: "delphi_nwss"
36+
- package: "quidel_covidtest"
37+
dir: "delphi_quidel_covidtest"
38+
- package: "sir_complainsalot"
39+
dir: "delphi_sir_complainsalot"
3240
defaults:
3341
run:
34-
working-directory: ${{ matrix.packages }}
42+
working-directory: ${{ matrix.package }}
3543
steps:
36-
- uses: actions/checkout@v2
44+
- uses: actions/checkout@v4
45+
with:
46+
fetch-depth: 0
3747
- name: Set up Python 3.8
38-
uses: actions/setup-python@v2
48+
uses: actions/setup-python@v5
3949
with:
4050
python-version: 3.8
51+
cache: "pip"
52+
cache-dependency-path: "setup.py"
4153
- name: Install testing dependencies
4254
run: |
4355
python -m pip install --upgrade pip
@@ -51,3 +63,8 @@ jobs:
5163
- name: Test
5264
run: |
5365
make test
66+
- uses: akaihola/[email protected]
67+
with:
68+
options: "--check --diff --isort --color"
69+
src: "${{ matrix.package }}/${{ matrix.dir }}"
70+
version: "~=2.1.1"

README.md

+32-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
In early April 2020, Delphi developed a uniform data schema for [a new Epidata endpoint focused on COVID-19](https://cmu-delphi.github.io/delphi-epidata/api/covidcast.html). Our intent was to provide signals that would track in real-time and in fine geographic granularity all facets of the COVID-19 pandemic, aiding both nowcasting and forecasting. Delphi's long history in tracking and forecasting influenza made us uniquely situated to provide access to data streams not available anywhere else, including medical claims data, electronic medical records, lab test records, massive public surveys, and internet search trends. We also process commonly-used publicly-available data sources, both for user convenience and to provide data versioning for sources that do not track revisions themselves.
66

7-
Each data stream arrives in a different format using a different delivery technique, be it sftp, an access-controlled API, or an email attachment. The purpose of each pipeline in this repository is to fetch the raw source data, extract informative aggregate signals, and output those signals---which we call **COVID-19 indicators**---in a common format for upload to the [COVIDcast API](https://cmu-delphi.github.io/delphi-epidata/api/covidcast.html).
7+
Each data stream arrives in a different format using a different delivery technique, be it sftp, an access-controlled API, or an email attachment. The purpose of each pipeline in this repository is to fetch the raw source data, extract informative aggregate signals, and output those signals---which we call **COVID-19 indicators**---in a common format for upload to the [COVIDcast API](https://cmu-delphi.github.io/delphi-epidata/api/covidcast.html).
88

99
For client access to the API, along with a variety of other utilities, see our [R](https://cmu-delphi.github.io/covidcast/covidcastR/) and [Python](https://cmu-delphi.github.io/covidcast/covidcast-py/html/) packages.
1010

@@ -13,18 +13,19 @@ For interactive visualizations (of a subset of the available indicators), see ou
1313
## Organization
1414

1515
Utilities:
16-
* `_delphi_utils_python` - common behaviors
17-
* `_template_python` & `_template_r` - starting points for new data sources
18-
* `ansible` & `jenkins` - automated testing and deployment
19-
* `sir_complainsalot` - a Slack bot to check for missing data
16+
17+
- `_delphi_utils_python` - common behaviors
18+
- `_template_python` & `_template_r` - starting points for new data sources
19+
- `ansible` & `jenkins` - automated testing and deployment
20+
- `sir_complainsalot` - a Slack bot to check for missing data
2021

2122
Indicator pipelines: all remaining directories.
2223

23-
Each indicator pipeline includes its own documentation.
24+
Each indicator pipeline includes its own documentation.
2425

25-
* Consult README.md for directions to install, lint, test, and run the pipeline for that indicator.
26-
* Consult REVIEW.md for the checklist to use for code reviews.
27-
* Consult DETAILS.md (if present) for implementation details, including handling of corner cases.
26+
- Consult README.md for directions to install, lint, test, and run the pipeline for that indicator.
27+
- Consult REVIEW.md for the checklist to use for code reviews.
28+
- Consult DETAILS.md (if present) for implementation details, including handling of corner cases.
2829

2930
## Development
3031

@@ -35,6 +36,28 @@ Each indicator pipeline includes its own documentation.
3536
3. Add new commits to your branch in response to feedback.
3637
4. When approved, tag an admin to merge the PR. Let them know if this change should be released immediately, at a set future date, or if it can just go along for the ride whenever the next release happens.
3738

39+
### Linting and Formatting
40+
41+
Each indicator has a `make lint` command to check for linting errors and a `make
42+
format` command to incrementally format your code (using
43+
[darker](https://github.com/akaihola/darker)). These are both automated with a
44+
[Github Action](.github/workflows/python-ci.yml).
45+
46+
If you get the error `ERROR:darker.git:fatal: Not a valid commit name <hash>`,
47+
then it's likely because your local main branch is not up to date; either you
48+
need to rebase or merge. Note that `darker` reads from `pyproject.toml` for
49+
default settings.
50+
51+
If the lines you change are in a file that uses 2 space indentation, `darker`
52+
will indent the lines around your changes and not the rest, which will likely
53+
break the code; in that case, you should probably just pass the whole file
54+
through black. You can do that with the following command (using the same
55+
virtual environment as above):
56+
57+
```sh
58+
env/bin/black <file>
59+
```
60+
3861
## Release Process
3962

4063
The release process consists of multiple steps which can all be done via the GitHub website:

_delphi_utils_python/.pylintrc

-22
This file was deleted.

_delphi_utils_python/Makefile

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ install-ci: venv
1414
pip install .
1515

1616
lint:
17-
. env/bin/activate; pylint delphi_utils
17+
. env/bin/activate; pylint delphi_utils --rcfile=../pyproject.toml
1818
. env/bin/activate; pydocstyle delphi_utils
1919

20+
format:
21+
. env/bin/activate; darker delphi_utils
22+
2023
test:
2124
. env/bin/activate ;\
2225
(cd tests && ../env/bin/pytest --cov=delphi_utils --cov-report=term-missing)

_delphi_utils_python/delphi_utils/geomap.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
Authors: Dmitry Shemetov @dshemetov, James Sharpnack @jsharpna, Maria Jahja
44
"""
55

6-
# pylint: disable=too-many-lines
76
from os.path import join
87
from collections import defaultdict
98
from typing import Iterator, List, Literal, Optional, Set, Union
@@ -13,7 +12,7 @@
1312
from pandas.api.types import is_string_dtype
1413

1514

16-
class GeoMapper: # pylint: disable=too-many-public-methods
15+
class GeoMapper:
1716
"""Geo mapping tools commonly used in Delphi.
1817
1918
The GeoMapper class provides utility functions for translating between different
@@ -624,7 +623,7 @@ def get_geos_within(
624623
if contained_geocode_type == "state":
625624
if container_geocode_type == "nation" and container_geocode == "us":
626625
crosswalk = self._crosswalks["state"]["state"]
627-
return set(crosswalk["state_id"]) # pylint: disable=unsubscriptable-object
626+
return set(crosswalk["state_id"])
628627
if container_geocode_type == "hhs":
629628
crosswalk_hhs = self._crosswalks["fips"]["hhs"]
630629
crosswalk_state = self._crosswalks["fips"]["state"]

_delphi_utils_python/delphi_utils/logger.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
"""Structured logger utility for creating JSON logs."""
1+
"""Structured logger utility for creating JSON logs.
22
3-
# the Delphi group uses two ~identical versions of this file.
4-
# try to keep them in sync with edits, for sanity.
5-
# https://github.com/cmu-delphi/covidcast-indicators/blob/main/_delphi_utils_python/delphi_utils/logger.py # pylint: disable=line-too-long
6-
# https://github.com/cmu-delphi/delphi-epidata/blob/dev/src/common/logger.py
3+
The Delphi group uses two ~identical versions of this file.
4+
Try to keep them in sync with edits, for sanity.
5+
https://github.com/cmu-delphi/covidcast-indicators/blob/main/_delphi_utils_python/delphi_utils/logger.py
6+
https://github.com/cmu-delphi/delphi-epidata/blob/dev/src/common/logger.py
7+
"""
78

89
import contextlib
910
import logging

_delphi_utils_python/delphi_utils/smooth.py

+6-14
Original file line numberDiff line numberDiff line change
@@ -304,17 +304,11 @@ def left_gauss_linear_smoother(self, signal):
304304
n = len(signal)
305305
signal_smoothed = np.zeros_like(signal)
306306
# A is the regression design matrix
307-
A = np.vstack([np.ones(n), np.arange(n)]).T # pylint: disable=invalid-name
307+
A = np.vstack([np.ones(n), np.arange(n)]).T
308308
for idx in range(n):
309-
weights = np.exp(
310-
-((np.arange(idx + 1) - idx) ** 2) / self.gaussian_bandwidth
311-
)
312-
AwA = np.dot( # pylint: disable=invalid-name
313-
A[: (idx + 1), :].T * weights, A[: (idx + 1), :]
314-
)
315-
Awy = np.dot( # pylint: disable=invalid-name
316-
A[: (idx + 1), :].T * weights, signal[: (idx + 1)].reshape(-1, 1)
317-
)
309+
weights = np.exp(-((np.arange(idx + 1) - idx) ** 2) / self.gaussian_bandwidth)
310+
AwA = np.dot(A[: (idx + 1), :].T * weights, A[: (idx + 1), :])
311+
Awy = np.dot(A[: (idx + 1), :].T * weights, signal[: (idx + 1)].reshape(-1, 1))
318312
try:
319313
beta = np.linalg.solve(AwA, Awy)
320314
signal_smoothed[idx] = np.dot(A[: (idx + 1), :], beta)[-1]
@@ -389,9 +383,7 @@ def savgol_coeffs(self, nl, nr, poly_fit_degree):
389383
if nr > 0:
390384
warnings.warn("The filter is no longer causal.")
391385

392-
A = np.vstack( # pylint: disable=invalid-name
393-
[np.arange(nl, nr + 1) ** j for j in range(poly_fit_degree + 1)]
394-
).T
386+
A = np.vstack([np.arange(nl, nr + 1) ** j for j in range(poly_fit_degree + 1)]).T
395387

396388
if self.gaussian_bandwidth is None:
397389
mat_inverse = np.linalg.inv(A.T @ A) @ A.T
@@ -406,7 +398,7 @@ def savgol_coeffs(self, nl, nr, poly_fit_degree):
406398
coeffs[i] = (mat_inverse @ basis_vector)[0]
407399
return coeffs
408400

409-
def savgol_smoother(self, signal): # pylint: disable=inconsistent-return-statements
401+
def savgol_smoother(self, signal):
410402
"""Smooth signal with the savgol smoother.
411403
412404
Returns a convolution of the 1D signal with the Savitzky-Golay coefficients, respecting

_delphi_utils_python/delphi_utils/validator/dynamic.py

-2
Original file line numberDiff line numberDiff line change
@@ -320,15 +320,13 @@ def create_dfs(self, geo_sig_df, api_df_or_error, checking_date, geo_type, signa
320320
#
321321
# These variables are interpolated into the call to `api_df_or_error.query()`
322322
# below but pylint doesn't recognize that.
323-
# pylint: disable=unused-variable
324323
reference_start_date = recent_cutoff_date - self.params.max_check_lookbehind
325324
if signal_type in self.params.smoothed_signals:
326325
# Add an extra 7 days to the reference period.
327326
reference_start_date = reference_start_date - \
328327
timedelta(days=7)
329328

330329
reference_end_date = recent_cutoff_date - timedelta(days=1)
331-
# pylint: enable=unused-variable
332330

333331
# Subset API data to relevant range of dates.
334332
reference_api_df = api_df_or_error.query(

_delphi_utils_python/setup.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
from setuptools import find_packages
33

44
with open("README.md", "r") as f:
5-
long_description = f.read()
5+
long_description = f.read()
66

77
required = [
88
"boto3",
99
"covidcast",
1010
"cvxpy",
11+
"darker[isort]~=2.1.1",
1112
"epiweeks",
1213
"freezegun",
1314
"gitpython",
@@ -17,8 +18,8 @@
1718
"pandas>=1.1.0",
1819
"pydocstyle",
1920
"pylint==2.8.3",
20-
"pytest",
2121
"pytest-cov",
22+
"pytest",
2223
"requests-mock",
2324
"slackclient",
2425
"structlog",

_template_python/.pylintrc

-22
This file was deleted.

_template_python/Makefile

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ install-ci: venv
1717
pip install .
1818

1919
lint:
20-
. env/bin/activate; pylint $(dir)
20+
. env/bin/activate; pylint $(dir) --rcfile=../pyproject.toml
2121
. env/bin/activate; pydocstyle $(dir)
2222

23+
format:
24+
. env/bin/activate; darker $(dir)
25+
2326
test:
2427
. env/bin/activate ;\
2528
(cd tests && ../env/bin/pytest --cov=$(dir) --cov-report=term-missing)

_template_python/setup.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
from setuptools import find_packages
33

44
required = [
5+
"covidcast",
6+
"darker[isort]~=2.1.1",
7+
"delphi-utils",
58
"numpy",
69
"pandas",
710
"pydocstyle",
8-
"pytest",
9-
"pytest-cov",
1011
"pylint==2.8.3",
11-
"delphi-utils",
12-
"covidcast"
12+
"pytest-cov",
13+
"pytest",
1314
]
1415

1516
setup(

changehc/.pylintrc

-24
This file was deleted.

0 commit comments

Comments
 (0)