From c415d48511da230f0e6ddb0d4a2bb801388ea162 Mon Sep 17 00:00:00 2001 From: Paolo Di Lorenzo Date: Tue, 17 Feb 2026 10:50:47 -0500 Subject: [PATCH 1/4] Use default ssl certs for map data update script --- data-raw/certs/www2-census-gov-chain.pem | 92 ------------------------ data-raw/scripts/config.ini | 1 - data-raw/scripts/shapefiles.py | 10 +-- 3 files changed, 3 insertions(+), 100 deletions(-) delete mode 100644 data-raw/certs/www2-census-gov-chain.pem diff --git a/data-raw/certs/www2-census-gov-chain.pem b/data-raw/certs/www2-census-gov-chain.pem deleted file mode 100644 index 989eae6..0000000 --- a/data-raw/certs/www2-census-gov-chain.pem +++ /dev/null @@ -1,92 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEUDCCA/egAwIBAgIQaDrV1+TMjrWOBiXILF9rhzAKBggqhkjOPQQDAjBSMQsw -CQYDVQQGEwJVUzEZMBcGA1UECgwQQ0xPVURGTEFSRSwgSU5DLjEoMCYGA1UEAwwf -Q2xvdWRmbGFyZSBUTFMgSXNzdWluZyBFQ0MgQ0EgMTAeFw0yNTA0MDMxNjQzMzda -Fw0yNjA0MDMxNjQ4MzVaMBoxGDAWBgNVBAMMD3d3dzIuY2Vuc3VzLmdvdjBZMBMG -ByqGSM49AgEGCCqGSM49AwEHA0IABPln+y1wtdnOs3sPFcf6B5cE5I92d8/F4jyd -pPszdhAxeOrBvu8hdtNAfBIEQahXw25tHyJ8a5PHQPLnW+wy3MWjggLlMIIC4TAM -BgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFJzECXJHGBd7pxqJs5I11eEDjP6SMGwG -CCsGAQUFBwEBBGAwXjA5BggrBgEFBQcwAoYtaHR0cDovL2kuY2YtYi5zc2wuY29t -L0Nsb3VkZmxhcmUtVExTLUktRTEuY2VyMCEGCCsGAQUFBzABhhVodHRwOi8vby5j -Zi1iLnNzbC5jb20wGgYDVR0RBBMwEYIPd3d3Mi5jZW5zdXMuZ292MCMGA1UdIAQc -MBowCAYGZ4EMAQIBMA4GDCsGAQQBgqkwAQMBATAdBgNVHSUEFjAUBggrBgEFBQcD -AgYIKwYBBQUHAwEwPgYDVR0fBDcwNTAzoDGgL4YtaHR0cDovL2MuY2YtYi5zc2wu -Y29tL0Nsb3VkZmxhcmUtVExTLUktRTEuY3JsMA4GA1UdDwEB/wQEAwIHgDAPBgkr -BgEEAYLaSywEAgUAMIIBfwYKKwYBBAHWeQIEAgSCAW8EggFrAWkAdwAOV5S8866p -PjMbLJkHs/eQ35vCPXEyJd0hqSWsYcVOIQAAAZX8ko+bAAAEAwBIMEYCIQCNc92s -rBx9YkFERIfu2ZoldiZHEqfkItZ818VIrEVNDAIhAOP3IF7IXgObk2Rr1vGTdO3R -Jmrc5rFeR3TE4oCzOWqwAHcASZybad4dfOz8Nt7Nh2SmuFuvCoeAGdFVUvvp6ynd -+MMAAAGV/JKPmQAABAMASDBGAiEAp9V1pHP+SKUonoy7foADCOfCdTpc2nj/Yq/V -2lAT2nICIQCK577pOoUWXLiq+1TKnhg/lw0ypV6Sondkg6+k0t6/XgB1AMs49xWJ -fIShRF9bwd37yW7ymlnNRwppBYWwyxTDFFjnAAABlfySj+YAAAQDAEYwRAIgHUDA -Zr6xm1Lzdk5EFSxdT6RWmR15dTuq/OOUWzO3So0CIGV9yT4exupT8q0Q+b14ybVc -oXGru2Kbm61LxMqgvcADMAoGCCqGSM49BAMCA0cAMEQCID4A0hXYQDqtjZHwDuWl -YCfg02kAhRobK0bOSjqEwUr6AiAJnCOWKa1qK8fu143WgcLJR11/Aj3XGBWINcJd -0xLtuA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC5DCCAmqgAwIBAgIQLD+iaS9BE707f+W2BLSdTTAKBggqhkjOPQQDAzBPMQsw -CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSYwJAYDVQQDDB1T -U0wuY29tIFRMUyBUcmFuc2l0IEVDQyBDQSBSMjAeFw0yMzEwMzExNzE3NDlaFw0z -MzEwMjgxNzE3NDhaMFIxCzAJBgNVBAYTAlVTMRkwFwYDVQQKDBBDTE9VREZMQVJF -LCBJTkMuMSgwJgYDVQQDDB9DbG91ZGZsYXJlIFRMUyBJc3N1aW5nIEVDQyBDQSAx -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEByHHIHytNSzTS+F3JA7hHMDGd2cp -cY9i3MLTKmE6DJTKc6JwvW50pwKodvd2Qj4RAAy2jSejsVgw5jeh6syt3KOCASMw -ggEfMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUMqLH2FiL/3/APPJV -aTPszswfvJcwSAYIKwYBBQUHAQEEPDA6MDgGCCsGAQUFBzAChixodHRwOi8vY2Vy -dC5zc2wuY29tL1NTTC5jb20tVExTLVQtRUNDLVIyLmNlcjARBgNVHSAECjAIMAYG -BFUdIAAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMD0GA1UdHwQ2MDQw -MqAwoC6GLGh0dHA6Ly9jcmxzLnNzbC5jb20vU1NMLmNvbS1UTFMtVC1FQ0MtUjIu -Y3JsMB0GA1UdDgQWBBScxAlyRxgXe6caibOSNdXhA4z+kjAOBgNVHQ8BAf8EBAMC -AYYwCgYIKoZIzj0EAwMDaAAwZQIxAL0Sk3RweR6uG1aSHF3JgHQptubP9xoZyUmz -HSa+SSdY5wTGSx5qAowrLPCpLio2PAIwXQGgYzf5QzD/1Bsu87WrUcIVtLixr5KQ -wKBaFAyIJ7OOiWgW0HV/NA1UeuSe0zmN ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID0DCCArigAwIBAgIRAK2NLfZGgaDTZEfqqU+ic8EwDQYJKoZIhvcNAQELBQAw -ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV -BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yNDA2MjEwMDAwMDBaFw0y -ODEyMzEyMzU5NTlaME8xCzAJBgNVBAYTAlVTMRgwFgYDVQQKDA9TU0wgQ29ycG9y -YXRpb24xJjAkBgNVBAMMHVNTTC5jb20gVExTIFRyYW5zaXQgRUNDIENBIFIyMHYw -EAYHKoZIzj0CAQYFK4EEACIDYgAEZOd9mQNTXJEe6vjYI62hvyziY4nvKGj27dfw -7Ktorncr5HaXG1Dr21koLW+4NrmrjZfKTCKe7onZAj/9enM6kI0rzC86N4PaDbQt -RRtzcgllX3ghPeeLZj9H/Qkp1hQPo4IBJzCCASMwHwYDVR0jBBgwFoAUoBEKIz6W -8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYEFDKix9hYi/9/wDzyVWkz7M7MH7yXMA4G -A1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdJQQWMBQGCCsG -AQUFBwMBBggrBgEFBQcDAjAjBgNVHSAEHDAaMAgGBmeBDAECATAOBgwrBgEEAYKp -MAEDAQEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v -QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEEKDAmMCQGCCsG -AQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQAD -ggEBAB4oL4ChKaKGZVZK8uAXjj8wvFdm45uvhU/t14QeH5bwETeKiQQXBga4/Nyz -zvpfuoEycantX+tHl/muwpmuHT0Z6IKYoICaMxOIktcTF4qHvxQW2WItHjOglrTj -qlXJXVL+3HCO60TEloSX8eUGsqfLQkc//z3Lb4gz117+fkDbnPt8+2REq3SCvaAG -hlh/lWWfHqTAiHed/qqzBSYqqvfjNlhIfXnPnhfAv/PpOUO1PmxCEAEYrg+VoS+O -+EBd1zkT0V7CfrPpj30cAMs2h+k4pPMwcLuB3Ku4TncBTRyt5K0gbJ3pQ0Rk9Hmu -wOz5QAZ+2n1q4TlApJzBfwFrCDg= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj -YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM -GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua -BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe -3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 -YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR -rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm -ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU -oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF -MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v -QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t -b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF -AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q -GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz -Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 -G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi -l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 -smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== ------END CERTIFICATE----- diff --git a/data-raw/scripts/config.ini b/data-raw/scripts/config.ini index f47f894..629dfae 100644 --- a/data-raw/scripts/config.ini +++ b/data-raw/scripts/config.ini @@ -1,6 +1,5 @@ [shapefiles] url = https://www2.census.gov/geo/tiger/GENZ{year}/shp/cb_{year}_us_{entity}_{res}.zip -cert = www2-census-gov-chain.pem current_year = 2024 entities = state,county res = 20m diff --git a/data-raw/scripts/shapefiles.py b/data-raw/scripts/shapefiles.py index e79c195..b1bd1ef 100644 --- a/data-raw/scripts/shapefiles.py +++ b/data-raw/scripts/shapefiles.py @@ -11,8 +11,8 @@ def __init__(self, message, code=None): super().__init__(message) self.code = code -def _download_and_extract(file_url: str, extract_dir: str, cert_url: str) -> bool: - response = requests.get(file_url, verify = cert_url) +def _download_and_extract(file_url: str, extract_dir: str) -> bool: + response = requests.get(file_url) LOCAL_FILE = "download.zip" if response.status_code == 200: @@ -54,7 +54,6 @@ def download_shapefiles(selected_year=None): SECTION = "shapefiles" url_template = config.get(SECTION, "url") - cert_file = config.get(SECTION, "cert") current_year = config.getint(SECTION, "current_year") entities = config.get(SECTION, "entities").split(",") res = config.get(SECTION, "res") @@ -68,9 +67,6 @@ def download_shapefiles(selected_year=None): with open(gh_env, "a") as f: f.write(f"shp_year={year}\n") - # create cert file URL - cert_url = os.path.join(script_dir, "..", "certs", cert_file) - # create output directory extract_dir = os.path.join(script_dir, "..", "shapefiles", str(year)) @@ -82,7 +78,7 @@ def download_shapefiles(selected_year=None): # attempt shapefile downloads for entity in entities: url = url_template.format(year=year, entity=entity, res=res) - _download_and_extract(url, extract_dir, cert_url) + _download_and_extract(url, extract_dir) if (gh_env := os.getenv("GITHUB_ENV")): with open(gh_env, "a") as f: From aa8a9766e37a27038203036a9ef4bf9124f71c0a Mon Sep 17 00:00:00 2001 From: Paolo Di Lorenzo Date: Tue, 17 Feb 2026 13:07:33 -0500 Subject: [PATCH 2/4] Clean up shapefiles.py and build map data workflow --- .github/workflows/build-map-data.yaml | 86 ++++++++++++++++++++++----- data-raw/scripts/shapefiles.py | 54 +++++++++++------ 2 files changed, 107 insertions(+), 33 deletions(-) diff --git a/.github/workflows/build-map-data.yaml b/.github/workflows/build-map-data.yaml index 5a42a3a..e986b70 100644 --- a/.github/workflows/build-map-data.yaml +++ b/.github/workflows/build-map-data.yaml @@ -14,11 +14,13 @@ on: default: '' jobs: - build: + download: runs-on: ubuntu-latest - env: - PUSHOVER_API_KEY: ${{ secrets.PUSHOVER_API_KEY }} - PUSHOVER_USER_KEY: ${{ secrets.PUSHOVER_USER_KEY }} + outputs: + exit_code: ${{ steps.dl-shp.outputs.exit_code }} + shp_year: ${{ steps.dl-shp.outputs.shp_year }} + state_shp: ${{ steps.dl-shp.outputs.state_shp }} + county_shp: ${{ steps.dl-shp.outputs.county_shp }} steps: - name: Checkout @@ -37,6 +39,34 @@ jobs: id: dl-shp run: | python data-raw/scripts/shapefiles.py ${{ inputs.year }} + echo "shp_year=${{ env.shp_year }}" >> "$GITHUB_OUTPUT" + echo "state_shp=${{ env.state_shp }}" >> "$GITHUB_OUTPUT" + echo "county_shp=${{ env.county_shp }}" >> "$GITHUB_OUTPUT" + + - name: Upload shapefiles + if: steps.dl-shp.outputs.exit_code == '0' + uses: actions/upload-artifact@v4 + with: + name: shapefiles + path: data-raw/shapefiles/${{ env.shp_year }} + + process: + runs-on: ubuntu-latest + needs: download + if: needs.download.outputs.exit_code == '0' + outputs: + pr_url: ${{ steps.save-pr-info.outputs.pr_url }} + pr_number: ${{ steps.save-pr-info.outputs.pr_number }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download shapefiles + uses: actions/download-artifact@v4 + with: + name: shapefiles + path: data-raw/shapefiles/${{ needs.download.outputs.shp_year }} - name: Setup R uses: r-lib/actions/setup-r@v2 @@ -48,9 +78,9 @@ jobs: - name: Modify shapefiles env: - STATE_SHP: ${{ env.state_shp }} - COUNTY_SHP: ${{ env.county_shp }} - YEAR: ${{ env.shp_year }} + STATE_SHP: ${{ needs.download.outputs.state_shp }} + COUNTY_SHP: ${{ needs.download.outputs.county_shp }} + YEAR: ${{ needs.download.outputs.shp_year }} run: | input_dir <- file.path("data-raw", "shapefiles", Sys.getenv("YEAR")) output_dir <- file.path("inst", "extdata", Sys.getenv("YEAR")) @@ -80,7 +110,7 @@ jobs: - name: Determine pull request parameters id: pr-params env: - YEAR: ${{ env.shp_year }} + YEAR: ${{ needs.download.outputs.shp_year }} run: | echo "branch_name=data-update/$YEAR" >> "$GITHUB_OUTPUT" echo "pr_title=Add $YEAR map data" >> "$GITHUB_OUTPUT" @@ -100,7 +130,7 @@ jobs: token: ${{ secrets.BOT_PAT }} author: ${{ secrets.BOT_USER }} committer: ${{ secrets.BOT_USER }} - commit-message: "[automated] Add ${{ env.shp_year }} map data based on available shapefiles" + commit-message: "[automated] Add ${{ needs.download.outputs.shp_year }} map data based on available shapefiles" branch: ${{ steps.pr-params.outputs.branch_name }} title: ${{ steps.pr-params.outputs.pr_title }} body: ${{ steps.pr-body.outputs.result }} @@ -109,17 +139,45 @@ jobs: labels: data update delete-branch: true + - name: Save PR info + id: save-pr-info + run: | + echo "pr_url=${{ steps.open-pr.outputs.pull-request-url }}" >> "$GITHUB_OUTPUT" + echo "pr_number=${{ steps.open-pr.outputs.pull-request-number }}" >> "$GITHUB_OUTPUT" + + notify: + runs-on: ubuntu-latest + needs: [download, process] + if: always() + env: + PUSHOVER_API_KEY: ${{ secrets.PUSHOVER_API_KEY }} + PUSHOVER_USER_KEY: ${{ secrets.PUSHOVER_USER_KEY }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.9' + cache: 'pip' + + - name: Install Python dependencies + run: pip install -r data-raw/scripts/requirements.txt + - name: Send success notification + if: needs.download.outputs.exit_code == '0' && needs.process.result == 'success' run: | - python data-raw/scripts/pushover.py "✅ usmapdata has updated its data files, a PR review is needed: PR #${{ steps.open-pr.outputs.pull-request-number }}" + python data-raw/scripts/pushover.py "✅ usmapdata has updated its data files, a PR review is needed: PR #${{ needs.process.outputs.pr_number }}" - name: Send data not found notification - if: ${{ failure() && steps.dl-shp.outputs.exit_code == '404' }} + if: needs.download.outputs.exit_code == '404' run: | - python data-raw/scripts/pushover.py "⚠️ usmapdata failed to find map data files for ${{ env.shp_year }}." "LOW" + python data-raw/scripts/pushover.py "⚠️ usmapdata failed to find map data files for ${{ needs.download.outputs.shp_year }}." "LOW" - name: Send failure notification - if: ${{ failure() && steps.dl-shp.outputs.exit_code != '404' }} + if: needs.download.outputs.exit_code != '0' && needs.download.outputs.exit_code != '404' run: | - python data-raw/scripts/pushover.py "❌ usmapdata failed to update map data files. (error: ${{ steps.dl-shp.outputs.exit_code }})" "LOW" + python data-raw/scripts/pushover.py "❌ usmapdata failed to update map data files. (error: ${{ needs.download.outputs.exit_code }})" "LOW" diff --git a/data-raw/scripts/shapefiles.py b/data-raw/scripts/shapefiles.py index b1bd1ef..ebcd277 100644 --- a/data-raw/scripts/shapefiles.py +++ b/data-raw/scripts/shapefiles.py @@ -4,36 +4,48 @@ import requests import shutil import sys +import tempfile from zipfile import ZipFile class DownloadError(Exception): - def __init__(self, message, code=None): + def __init__(self, message, code): super().__init__(message) self.code = code -def _download_and_extract(file_url: str, extract_dir: str) -> bool: - response = requests.get(file_url) - LOCAL_FILE = "download.zip" +def _download_and_extract(file_url: str, extract_dir: str): + response = requests.get(file_url, timeout=30) - if response.status_code == 200: - with open(LOCAL_FILE, "wb") as f: - f.write(response.content) - print(f"{LOCAL_FILE} downloaded from {file_url}.") + if response.status_code != 200: + raise DownloadError(f"Failed to download {file_url}.", code=response.status_code) + + with tempfile.NamedTemporaryFile(suffix='.zip', delete=False) as tmp_file: + tmp_filename = tmp_file.name + tmp_file.write(response.content) + print(f"Files downloaded from {file_url} to {tmp_filename}.") - with ZipFile(LOCAL_FILE, "r") as z: + try: + with ZipFile(tmp_filename, "r") as z: z.extractall(extract_dir) - print(f"{LOCAL_FILE} extracted to {extract_dir}.") + print(f"{tmp_filename} extracted to {extract_dir}.") + finally: + os.remove(tmp_filename) - os.remove(LOCAL_FILE) - else: - raise DownloadError(f"Failed to download {file_url}.", code=response.status_code) +def _exit(sys_code: int, gh_code: int=None): + """ + Exits with the given code(s). + + Parameters: + sys_code: The exit code to call sys.exit() with. + gh_code (optional): The code to set in the GitHub output. + If None, uses sys_code. + """ + gh_code = sys_code if gh_code is None else gh_code -def _failed(code: int): if (gh_env := os.getenv("GITHUB_OUTPUT")): with open(gh_env, "a") as f: - f.write(f"exit_code={code}\n") + f.write(f"exit_code={gh_code}\n") - sys.exit(code) + sys.exit(sys_code) def download_shapefiles(selected_year=None): """ @@ -72,7 +84,7 @@ def download_shapefiles(selected_year=None): if os.path.exists(extract_dir): shutil.rmtree(extract_dir) - shutil.os.makedirs(extract_dir) + os.makedirs(extract_dir) try: # attempt shapefile downloads @@ -89,16 +101,20 @@ def download_shapefiles(selected_year=None): config.set(SECTION, "current_year", f"{year}") with open(config_file, "w") as f: config.write(f) + + _exit(0) except DownloadError as e: if e.code == 404: # i.e. shapefiles not found print(f"The shapefiles for {year} were not found. Better luck next time!") + # "files not found" is not considered a system failure + _exit(sys_code=0, gh_code=404) else: # other download errors print(e) + _exit(e.code) - _failed(e.code) except Exception as e: print(e) - _failed(-1) + _exit(-1) if __name__ == "__main__": From da7c73c27f08409018507c3dff89eec2bd4bb2d6 Mon Sep 17 00:00:00 2001 From: Paolo Di Lorenzo Date: Tue, 17 Feb 2026 13:09:54 -0500 Subject: [PATCH 3/4] Increase map data file download timeout --- data-raw/scripts/shapefiles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data-raw/scripts/shapefiles.py b/data-raw/scripts/shapefiles.py index ebcd277..da434d9 100644 --- a/data-raw/scripts/shapefiles.py +++ b/data-raw/scripts/shapefiles.py @@ -13,7 +13,7 @@ def __init__(self, message, code): self.code = code def _download_and_extract(file_url: str, extract_dir: str): - response = requests.get(file_url, timeout=30) + response = requests.get(file_url, timeout=300) if response.status_code != 200: raise DownloadError(f"Failed to download {file_url}.", code=response.status_code) From 594e07f300299c93ca39090497f93880d1e2026e Mon Sep 17 00:00:00 2001 From: Paolo Di Lorenzo Date: Tue, 17 Feb 2026 13:16:32 -0500 Subject: [PATCH 4/4] Fix shapefile step output in build map data workflow --- .github/workflows/build-map-data.yaml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-map-data.yaml b/.github/workflows/build-map-data.yaml index e986b70..2eb56a0 100644 --- a/.github/workflows/build-map-data.yaml +++ b/.github/workflows/build-map-data.yaml @@ -18,9 +18,9 @@ jobs: runs-on: ubuntu-latest outputs: exit_code: ${{ steps.dl-shp.outputs.exit_code }} - shp_year: ${{ steps.dl-shp.outputs.shp_year }} - state_shp: ${{ steps.dl-shp.outputs.state_shp }} - county_shp: ${{ steps.dl-shp.outputs.county_shp }} + shp_year: ${{ steps.info.outputs.shp_year }} + state_shp: ${{ steps.info.outputs.state_shp }} + county_shp: ${{ steps.info.outputs.county_shp }} steps: - name: Checkout @@ -39,6 +39,10 @@ jobs: id: dl-shp run: | python data-raw/scripts/shapefiles.py ${{ inputs.year }} + + - name: Save shapefile info + id: info + run: | echo "shp_year=${{ env.shp_year }}" >> "$GITHUB_OUTPUT" echo "state_shp=${{ env.state_shp }}" >> "$GITHUB_OUTPUT" echo "county_shp=${{ env.county_shp }}" >> "$GITHUB_OUTPUT" @@ -55,8 +59,8 @@ jobs: needs: download if: needs.download.outputs.exit_code == '0' outputs: - pr_url: ${{ steps.save-pr-info.outputs.pr_url }} - pr_number: ${{ steps.save-pr-info.outputs.pr_number }} + pr_url: ${{ steps.info.outputs.pr_url }} + pr_number: ${{ steps.info.outputs.pr_number }} steps: - name: Checkout @@ -140,7 +144,7 @@ jobs: delete-branch: true - name: Save PR info - id: save-pr-info + id: info run: | echo "pr_url=${{ steps.open-pr.outputs.pull-request-url }}" >> "$GITHUB_OUTPUT" echo "pr_number=${{ steps.open-pr.outputs.pull-request-number }}" >> "$GITHUB_OUTPUT"