Skip to content

Commit ada4165

Browse files
authored
Merge pull request #2052 from cmu-delphi/release/indicators_v0.3.56_utils_v0.3.25
Release covidcast-indicators 0.3.56
2 parents b338a09 + 9703073 commit ada4165

Some content is hidden

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

60 files changed

+51794
-406
lines changed

.bumpversion.cfg

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.3.55
2+
current_version = 0.3.56
33
commit = True
44
message = chore: bump covidcast-indicators to {new_version}
55
tag = False

.github/CONTRIBUTING.md

+8-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ The production branch is configured to automatically deploy to our production en
1212

1313
* everything else
1414

15-
All other branches are development branches. We don't enforce a naming policy.
15+
All other branches are development branches. We don't enforce a naming policy, but it is recommended to prefix all branches you create with your name, username, or initials (e.g. `username/branch-name`).
16+
17+
We don't forbid force-pushing, but please keep to a minimum and be careful of using when modifying a branch at the same time as others.
1618

1719
## Issues
1820

@@ -29,7 +31,7 @@ So, how does one go about developing a pipeline for a new data source?
2931
### tl;dr
3032

3133
1. Create your new indicator branch from `main`.
32-
2. Build it using the appropriate template, following the guidelines in the included README.md and REVIEW.md files.
34+
2. Build it using the [indicator template](https://github.com/cmu-delphi/covidcast-indicators/tree/main/_template_python), following the guidelines in the included README.md, REVIEW.md, and INDICATOR_DEV_GUIDE.md files.
3335
3. Make some stuff!
3436
4. When your stuff works, push your development branch to remote, and open a PR against `main` for review.
3537
5. Once your PR has been merged, consult with a platform engineer for the remaining production setup needs. They will create a deployment workflow for your indicator including any necessary production parameters. Production secrets are encrypted in the Ansible vault. This workflow will be tested in staging by admins, who will consult you about any problems they encounter.
@@ -50,7 +52,7 @@ git checkout -b dev-my-feature-branch
5052

5153
### Creating your indicator
5254

53-
Create a directory for your new indicator by making a copy of `_template_r` or `_template_python` depending on the programming language you intend to use. If using Python, add the name of the directory to the list found in `jobs > build > strategy > matrix > packages` in `.github/workflows/python-ci.yml`, which will enable automated checks for your indicator when you make PRs. The template copies of `README.md` and `REVIEW.md` include the minimum requirements for code structure, documentation, linting, testing, and method of configuration. Beyond that, we don't have any established restrictions on implementation; you can look at other existing indicators see some examples of code layout, organization, and general approach.
55+
Create a directory for your new indicator by making a copy of `_template_python`. (We also make a `_template_r` available, but R should be only used as a last resort, due to complications using it in production.) Add the name of the directory to the list found in `jobs > build > strategy > matrix > packages` in `.github/workflows/python-ci.yml`, which will enable automated checks for your indicator when you make PRs. The template copies of `README.md` and `REVIEW.md` include the minimum requirements for code structure, documentation, linting, testing, and method of configuration. Beyond that, we don't have any established restrictions on implementation; you can look at other existing indicators see some examples of code layout, organization, and general approach.
5456

5557
* Consult your peers with questions! :handshake:
5658

@@ -62,7 +64,7 @@ Once you have something that runs locally and passes tests you set up your remot
6264
git push -u origin dev-my-feature-branch
6365
```
6466

65-
You can then draft public API documentation for people who would fetch this
67+
You can then draft [public API documentation](https://cmu-delphi.github.io/delphi-epidata/) for people who would fetch this
6668
data from the API. Public API documentation is kept in the delphi-epidata
6769
repository, and there is a [template Markdown
6870
file](https://github.com/cmu-delphi/delphi-epidata/blob/main/docs/api/covidcast-signals/_source-template.md)
@@ -104,7 +106,8 @@ We use a branch-based git workflow coupled with [Jenkins](https://www.jenkins.io
104106
* Package - Tar and gzip the built environment.
105107
* Deploy - Trigger an Ansible playbook to place the built package onto the runtime host, place any necessary production configuration, and adjust the runtime envirnemnt (if necessary).
106108

107-
There are several additional Jenkins-specific files that will need to be created for each indicator, as well as some configuration additions to the runtime host. It will be important to pair with a platform engineer to prepare the necessary production environment needs, test the workflow, validate on production, and ultimately sign off on a production release.
109+
There are several additional Jenkins-specific files that will need to be created for each indicator, as well as some configuration additions to the runtime host.
110+
It will be important to pair with a platform engineer to prepare the necessary production environment needs, test the workflow, validate on production, and ultimately sign off on a production release.
108111

109112
### Preparing container images of indicators
110113

.github/pull_request_template.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ Itemize code/test/documentation changes and files added/removed.
66
- change1
77
- change2
88

9-
### Fixes
10-
- Fixes #(issue)
9+
### Associated Issue(s)
10+
- Addresses #(issue)

.github/workflows/publish-release.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ jobs:
8686
- name: Release
8787
run: |
8888
make release
89-
- uses: actions/upload-artifact@v2
89+
- uses: actions/upload-artifact@v4
9090
with:
9191
name: delphi_utils
9292
path: _delphi_utils_python/dist/*.tar.gz

.github/workflows/python-ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
with:
5252
python-version: 3.8
5353
cache: "pip"
54-
cache-dependency-path: "setup.py"
54+
cache-dependency-path: "pyproject.toml"
5555
- name: Install testing dependencies
5656
run: |
5757
python -m pip install --upgrade pip

Jenkinsfile

+38-15
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
- TODO: #527 Get this list automatically from python-ci.yml at runtime.
1111
*/
1212

13-
def indicator_list = ["backfill_corrections", "changehc", "claims_hosp", "google_symptoms", "hhs_hosp", "nchs_mortality", "quidel_covidtest", "sir_complainsalot", "doctor_visits", "nwss_wastewater", "nssp"]
13+
def indicator_list = ['backfill_corrections', 'changehc', 'claims_hosp', 'google_symptoms', 'hhs_hosp', 'nchs_mortality', 'quidel_covidtest', 'sir_complainsalot', 'doctor_visits', 'nwss_wastewater', 'nssp']
1414
def build_package_main = [:]
1515
def build_package_prod = [:]
1616
def deploy_staging = [:]
@@ -19,39 +19,62 @@ def deploy_production = [:]
1919
pipeline {
2020
agent any
2121
stages {
22-
stage('Build and Package main') {
22+
stage('Build dev/feature branch') {
23+
when {
24+
not {
25+
anyOf {
26+
branch 'main'
27+
branch 'prod'
28+
}
29+
}
30+
}
31+
steps {
32+
script {
33+
indicator_list.each { indicator ->
34+
stage("Build ${indicator}") {
35+
sh "jenkins/build-indicator.sh ${indicator}"
36+
}
37+
}
38+
}
39+
}
40+
}
41+
stage('Build and Package main branch') {
2342
when {
24-
branch "main";
43+
branch 'main'
2544
}
2645
steps {
2746
script {
2847
indicator_list.each { indicator ->
29-
build_package_main[indicator] = {
30-
sh "jenkins/build-and-package.sh ${indicator} main"
48+
stage("Build ${indicator}") {
49+
sh "jenkins/build-indicator.sh ${indicator}"
50+
}
51+
stage("Package ${indicator}") {
52+
sh "jenkins/package-indicator.sh ${indicator} main"
3153
}
3254
}
33-
parallel build_package_main
3455
}
3556
}
3657
}
37-
stage('Build and Package prod') {
58+
stage('Build and Package prod branch') {
3859
when {
39-
branch "prod";
60+
branch 'prod'
4061
}
4162
steps {
4263
script {
4364
indicator_list.each { indicator ->
44-
build_package_prod[indicator] = {
45-
sh "jenkins/build-and-package.sh ${indicator} prod"
65+
stage("Build ${indicator}") {
66+
sh "jenkins/build-indicator.sh ${indicator}"
67+
}
68+
stage("Package ${indicator}") {
69+
sh "jenkins/package-indicator.sh ${indicator} prod"
4670
}
4771
}
48-
parallel build_package_prod
4972
}
5073
}
5174
}
52-
stage('Deploy staging') {
75+
stage('Deploy main branch to staging env') {
5376
when {
54-
branch "main";
77+
branch 'main'
5578
}
5679
steps {
5780
script {
@@ -64,9 +87,9 @@ pipeline {
6487
}
6588
}
6689
}
67-
stage('Deploy production') {
90+
stage('Deploy prod branch to production env') {
6891
when {
69-
branch "prod";
92+
branch 'prod'
7093
}
7194
steps {
7295
script {

_delphi_utils_python/.bumpversion.cfg

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
[bumpversion]
2-
current_version = 0.3.24
2+
current_version = 0.3.25
33
commit = True
44
message = chore: bump delphi_utils to {new_version}
55
tag = False
66

7-
[bumpversion:file:setup.py]
7+
[bumpversion:file:pyproject.toml]
88

99
[bumpversion:file:delphi_utils/__init__.py]

_delphi_utils_python/DEVELOP.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ To install the module in your default version of Python, run the
99
following from this directory:
1010

1111
```
12-
pip install .
12+
pip install -e '.[dev]'
1313
```
1414

1515
As described in each of the indicator code directories, you will want to install

_delphi_utils_python/Makefile

+5-4
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ venv:
66
install: venv
77
. env/bin/activate; \
88
pip install wheel ; \
9-
pip install -e .
9+
pip install -e '.[dev]'
1010

1111
install-ci: venv
1212
. env/bin/activate; \
13-
pip install wheel ; \
14-
pip install .
13+
pip install 'build[virtualenv]' pylint pytest pydocstyle wheel twine ; \
14+
pip install '.[dev]'
1515

1616
lint:
1717
. env/bin/activate; pylint delphi_utils --rcfile=../pyproject.toml
@@ -30,4 +30,5 @@ clean:
3030

3131
release: lint test
3232
. env/bin/activate ; \
33-
python setup.py sdist bdist_wheel
33+
pip install 'build[virtualenv]' ; \
34+
python -m build --sdist --wheel

_delphi_utils_python/README.md

+29-2
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,32 @@ Submodules:
1717
- `validator`: Data sanity checks and anomaly detection.
1818

1919

20-
Source code can be found here:
21-
[https://github.com/cmu-delphi/covidcast-indicators/](https://github.com/cmu-delphi/covidcast-indicators/)
20+
Source code can be found here:
21+
[https://github.com/cmu-delphi/covidcast-indicators/](https://github.com/cmu-delphi/covidcast-indicators/)
22+
23+
## Logger Usage
24+
25+
Single-thread usage.
26+
27+
```py
28+
from delphi_utils.logger import get_structured_logger
29+
30+
logger = get_structured_logger('my_logger')
31+
logger.info('Hello, world!')
32+
```
33+
34+
Multi-thread usage.
35+
36+
```py
37+
from delphi_utils.logger import get_structured_logger, pool_and_threadedlogger
38+
39+
def f(x, threaded_logger):
40+
threaded_logger.info(f'x={x}')
41+
return x*x
42+
43+
logger = get_structured_logger('my_logger')
44+
logger.info('Hello, world!')
45+
with pool_and_threadedlogger(logger, n_cpu) as (pool, threaded_logger):
46+
for i in range(10):
47+
pool.apply_async(f, args=(i, threaded_logger))
48+
```

_delphi_utils_python/delphi_utils/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
from .nancodes import Nans
1616
from .weekday import Weekday
1717

18-
__version__ = "0.3.24"
18+
__version__ = "0.3.25"

_delphi_utils_python/delphi_utils/geomap.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ def add_population_column(
443443
---------
444444
data: pd.DataFrame
445445
The dataframe with a FIPS code column.
446-
geocode_type: {"fips", "zip"}
446+
geocode_type:
447447
The type of the geocode contained in geocode_col.
448448
geocode_col: str, default None
449449
The name of the column containing the geocodes. If None, uses the geocode_type
@@ -671,8 +671,10 @@ def aggregate_by_weighted_sum(
671671
to a from_geo, e.g. "wastewater collection site").
672672
to_geo: str
673673
The column name of the geocode to aggregate to.
674-
sensor: str
674+
sensor_col: str
675675
The column name of the sensor to aggregate.
676+
time_col: str
677+
The column name of the timestamp to aggregate over.
676678
population_column: str
677679
The column name of the population to weight the sensor by.
678680

_delphi_utils_python/delphi_utils/logger.py

+16-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Structured logger utility for creating JSON logs.
22
3+
See the delphi_utils README.md for usage examples.
4+
35
The Delphi group uses two ~identical versions of this file.
46
Try to keep them in sync with edits, for sanity.
57
https://github.com/cmu-delphi/covidcast-indicators/blob/main/_delphi_utils_python/delphi_utils/logger.py
@@ -133,19 +135,17 @@ class LoggerThread():
133135
"""
134136
A construct to use a logger from multiprocessing workers/jobs.
135137
136-
the bare structlog loggers are thread-safe but not multiprocessing-safe.
137-
a `LoggerThread` will spawn a thread that listens to a mp.Queue
138-
and logs messages from it with the provided logger,
139-
so other processes can send logging messages to it
140-
via the logger-like `SubLogger` interface.
141-
the SubLogger even logs the pid of the caller.
138+
The bare structlog loggers are thread-safe but not multiprocessing-safe. A
139+
`LoggerThread` will spawn a thread that listens to a mp.Queue and logs
140+
messages from it with the provided logger, so other processes can send
141+
logging messages to it via the logger-like `SubLogger` interface. The
142+
SubLogger even logs the pid of the caller.
142143
143-
this is good to use with a set of jobs that are part of a mp.Pool,
144-
but isnt recommended for general use
145-
because of overhead from threading and multiprocessing,
146-
and because it might introduce lag to log messages.
144+
This is good to use with a set of jobs that are part of a mp.Pool, but isnt
145+
recommended for general use because of overhead from threading and
146+
multiprocessing, and because it might introduce lag to log messages.
147147
148-
somewhat inspired by:
148+
Somewhat inspired by:
149149
docs.python.org/3/howto/logging-cookbook.html#logging-to-a-single-file-from-multiple-processes
150150
"""
151151

@@ -236,13 +236,11 @@ def pool_and_threadedlogger(logger, *poolargs):
236236
"""
237237
Provide (to a context) a multiprocessing Pool and a proxy to the supplied logger.
238238
239-
Emulates the multiprocessing.Pool() context manager,
240-
but also provides (via a LoggerThread) a SubLogger proxy to logger
241-
that can be safely used by pool workers.
242-
The SubLogger proxy interface supports these methods: debug, info, warning, error,
243-
and critical.
244-
Also "cleans up" the pool by waiting for workers to complete
245-
as it exits the context.
239+
Emulates the multiprocessing.Pool() context manager, but also provides (via
240+
a LoggerThread) a SubLogger proxy to logger that can be safely used by pool
241+
workers. The SubLogger proxy interface supports these methods: debug, info,
242+
warning, error, and critical. Also "cleans up" the pool by waiting for
243+
workers to complete as it exits the context.
246244
"""
247245
with multiprocessing.Manager() as manager:
248246
logger_thread = LoggerThread(logger, manager.Queue())

_delphi_utils_python/pyproject.toml

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
[build-system]
2+
requires = ["setuptools", "setuptools-scm>=8.0"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "delphi-utils"
7+
version = "0.3.25"
8+
description = "Shared Utility Functions for Indicators"
9+
readme = "README.md"
10+
requires-python = "== 3.8.*"
11+
license = { text = "MIT License" }
12+
classifiers = [
13+
"Development Status :: 5 - Production/Stable",
14+
"Intended Audience :: Developers",
15+
"Programming Language :: Python :: 3.8",
16+
"License :: MIT",
17+
]
18+
dependencies = [
19+
"boto3",
20+
"covidcast",
21+
"cvxpy",
22+
"epiweeks",
23+
"gitpython",
24+
"importlib_resources>=1.3",
25+
"numpy",
26+
"pandas>=1.1.0",
27+
"requests",
28+
"slackclient",
29+
"scs<3.2.6", # TODO: remove this ; it is a cvxpy dependency, and the excluded version appears to break our jenkins build. see: https://github.com/cvxgrp/scs/issues/283
30+
"structlog",
31+
"xlrd", # needed by Pandas to read Excel files
32+
]
33+
34+
[project.urls]
35+
Homepage = "https://github.com/cmu-delphi/covidcast-indicators"
36+
37+
[project.optional-dependencies]
38+
dev = [
39+
"darker[isort]~=2.1.1",
40+
"pylint==2.8.3",
41+
"pytest",
42+
"pydocstyle",
43+
"pytest-cov",
44+
"mock",
45+
"moto~=4.2.14",
46+
"requests-mock",
47+
"freezegun",
48+
]
49+
flash = ["scipy"]
50+
51+
[tool.setuptools.packages.find]
52+
where = ["."]
53+
include = ["delphi_utils"]
54+
namespaces = true
55+
56+
[tool.setuptools.package-data]
57+
"delphi_utils.data" = ["20*/*.csv"]

0 commit comments

Comments
 (0)