diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index abdb75b..afb6245 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -25,6 +25,9 @@ jobs: - name: Check code format with Ruff run: uv run ruff format --check us + - name: Check types with ty + run: uv run ty check us + testing: needs: linting runs-on: ubuntu-latest diff --git a/pyproject.toml b/pyproject.toml index 287f66e..aaf54d6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,12 @@ dependencies = ['jellyfish'] states = "us.cli.states:main" [dependency-groups] -dev = ['ruff', 'pytest', 'pytz'] +dev = [ + 'ruff', + 'pytest', + 'pytz', + "ty>=0.0.38", +] [tool.ruff] line-length = 120 diff --git a/us/cli/states.py b/us/cli/states.py index a6f1f3f..ae79819 100644 --- a/us/cli/states.py +++ b/us/cli/states.py @@ -38,8 +38,10 @@ def main(): sys.stdout.write("\n") sys.stdout.write(" shapefiles:\n") - for region, url in state.shapefile_urls().items(): - sys.stdout.write(" %s: %s\n" % (region, url)) + urls = state.shapefile_urls() + if urls is not None: + for region, url in urls.items(): + sys.stdout.write(" %s: %s\n" % (region, url)) sys.stdout.write("\n") diff --git a/us/states.py b/us/states.py index fd06388..7e3771d 100644 --- a/us/states.py +++ b/us/states.py @@ -4,7 +4,7 @@ from typing import Any, Callable, Dict, Iterable, List, Optional, Type from urllib.parse import urljoin -import jellyfish # type: ignore +import jellyfish FIPS_RE = re.compile(r"^\d{2}$") ABBR_RE = re.compile(r"^[a-zA-Z]{2}$") @@ -137,7 +137,6 @@ def lookup( # fallback results are cached under a separate, fallback-specific key so # they never leak into non-fallback lookups -- or lookups using a # different fallback -- of the same value - fallback_key = None if fallback_func is not None: fallback_key = f"{cache_key}:fallback:{fallback_func!r}" if use_cache and fallback_key in _lookup_cache: diff --git a/us/tests/test_us.py b/us/tests/test_us.py index 7942562..b98482f 100644 --- a/us/tests/test_us.py +++ b/us/tests/test_us.py @@ -1,8 +1,8 @@ import re from itertools import chain -import jellyfish # type: ignore -import pytest # type: ignore +import jellyfish +import pytest import pytz import us @@ -251,10 +251,15 @@ def test_dc(): @pytest.mark.skip def test_head(): - import requests + # `requests` is intentionally not declared as a dependency; this test + # is permanently skipped and the import is dead code for ty. + import requests # ty: ignore[unresolved-import] for state in us.STATES_AND_TERRITORIES: - for url in state.shapefile_urls().values(): + urls = state.shapefile_urls() + if urls is None: + continue + for url in urls.values(): resp = requests.head(url) assert resp.status_code == 200 @@ -312,6 +317,7 @@ def test_county_fips_format(): def test_county_fips_prefixed_by_state(): for state in us.STATES_AND_TERRITORIES: + assert state.fips is not None, f"{state.abbr}: missing state fips" for county in state.counties: assert county.fips.startswith(state.fips), ( f"{state.abbr}: county {county.name} fips {county.fips} not prefixed by state fips {state.fips}" diff --git a/uv.lock b/uv.lock index 77557fe..7626600 100644 --- a/uv.lock +++ b/uv.lock @@ -440,6 +440,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, ] +[[package]] +name = "ty" +version = "0.0.38" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/33/3b/45be6b37d5060d6917bf7f1f234c00d360fc5f8b7486f8a96af640e25661/ty-0.0.38.tar.gz", hash = "sha256:fbc8d47f7630457669ab41e333dc093897fdb7ead1ffc94dcf8f30b5d39aa56d", size = 5681218, upload-time = "2026-05-20T00:15:32.781Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/43/ea9b4e57d6a266670dbe34858e92f6093ca054ad1b48f1c82580a72340fb/ty-0.0.38-py3-none-linux_armv6l.whl", hash = "sha256:3501dcf44ca03f813f9cb4fabfdf601adc0ac1337c411405b470530679e37a45", size = 11289326, upload-time = "2026-05-20T00:14:52.371Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ff/24e2f623a1c6b5f5ccf8bf82fccd937033c6a7dba57a4028c7f41270fa4a/ty-0.0.38-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b34b4094b76252c3e8c90762cdd5e8a9f1101534484745ff4b480f71eb38ac2e", size = 11063047, upload-time = "2026-05-20T00:14:42.832Z" }, + { url = "https://files.pythonhosted.org/packages/e9/41/4f0d910f0acbd20b358eda80a5cd6a8361d27ff5b8e87ab559d3f69f125e/ty-0.0.38-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c518ad33a877677365baab2e21d82cf59ffee789203a15a143f5179ee5a1d3f8", size = 10494436, upload-time = "2026-05-20T00:15:24.425Z" }, + { url = "https://files.pythonhosted.org/packages/69/d8/da06833422082aa98b169a391f9197e2d73865e96c90b6979ac886b890a2/ty-0.0.38-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9238494722303eccddc6a27eb647948b694eecd6b974910d13b9e6cd46bbeb6a", size = 11000992, upload-time = "2026-05-20T00:14:58.368Z" }, + { url = "https://files.pythonhosted.org/packages/16/f7/e1172197fb827e6410ca3eb0dc68ef2789f3c70683696f2a0ce5c90764fd/ty-0.0.38-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:31d91d7336c5d51bf822ac0df512f300584ca4dcca041fc6a6d7df03a8ddbb31", size = 11058583, upload-time = "2026-05-20T00:15:11.314Z" }, + { url = "https://files.pythonhosted.org/packages/5b/61/7fbaf0c05981e006a8804287819c574dff90a6bf8e96efad7226be0700aa/ty-0.0.38-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65165879814993450710b9349791e4898c65e36b1e14eec554884c06a2f20ff1", size = 11531036, upload-time = "2026-05-20T00:15:14.62Z" }, + { url = "https://files.pythonhosted.org/packages/49/e3/47c0c64e401d50f925df3e52479d4e7626754b2a9e38201d142fdacd6252/ty-0.0.38-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d61868b8d1c4033bf8088191de953fed245c2f9e1bb9d2d53e5699170b0924c", size = 12129991, upload-time = "2026-05-20T00:14:39.475Z" }, + { url = "https://files.pythonhosted.org/packages/90/99/2f452d02901bcd7f1b109cf5b848727ce37f372c3406143aa52d1305d40e/ty-0.0.38-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8f9a9175548c98dbff7707865738c07c2b1f8e07a09b8c68101baebb5dac59a4", size = 11756167, upload-time = "2026-05-20T00:15:27.526Z" }, + { url = "https://files.pythonhosted.org/packages/dd/0c/c7e14d111c813e1a20b82e944f1c997c4631a2bb710eaa64fb6b26835e13/ty-0.0.38-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:375d3a964c6b4aea2e9237fdb5eb9ed03dc43088986a94209a28a4ea3b62001c", size = 11637099, upload-time = "2026-05-20T00:15:21.261Z" }, + { url = "https://files.pythonhosted.org/packages/37/de/ab02659dd1ed62898db7db4d37f9937c80854dd45e95093fa0fe10328d82/ty-0.0.38-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:cdfd547782c45267aa0b52abad31bd406bf4768c264532ef9e2360cd3c6ce048", size = 11813583, upload-time = "2026-05-20T00:14:45.875Z" }, + { url = "https://files.pythonhosted.org/packages/7e/57/bd1b5ebf4e71a4295484afac0202df1740b0807762b86744b1bef4534984/ty-0.0.38-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:858bc675b75626470abe4e6c3b3934b853642b04f2ac4d7139fcefea3b48b213", size = 10975405, upload-time = "2026-05-20T00:15:30.354Z" }, + { url = "https://files.pythonhosted.org/packages/e7/55/0305c78711bbd23922cf291996a08ef9544f4179da98e9a75c14e608f379/ty-0.0.38-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:54be4f00432870da42cd74fe145a3362fd248e22d032c74bd807cb45bf068f94", size = 11097551, upload-time = "2026-05-20T00:14:55.179Z" }, + { url = "https://files.pythonhosted.org/packages/7c/4f/7effe7f9a6ac9719eb7234172c01739c5f888bb47f9acc2ea8da1f4afed3/ty-0.0.38-py3-none-musllinux_1_2_i686.whl", hash = "sha256:494af66a76a86dbf16a3003d3b63b03484aa4c7489dfe11f3ee5413b98b22d60", size = 11214391, upload-time = "2026-05-20T00:15:18.094Z" }, + { url = "https://files.pythonhosted.org/packages/75/cd/d9fdfec3a74a6ad0209fa5e7113ae29d4f457d0651cfbb813b4c6563e0d4/ty-0.0.38-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3d92527c4be78a5ce6d32e8bb0aa2a6988d4076eddf1294e56fdaf06d1a98e7e", size = 11730871, upload-time = "2026-05-20T00:14:49.219Z" }, + { url = "https://files.pythonhosted.org/packages/0e/4a/beefade12d109b4f7793d61b04b4478b1ad4d1465a719e7ff55b2d42461a/ty-0.0.38-py3-none-win32.whl", hash = "sha256:36fc5dd5dc09207ff3004b1560a79a3fb8d12456daeec914a7b802a918da654c", size = 10548583, upload-time = "2026-05-20T00:15:07.892Z" }, + { url = "https://files.pythonhosted.org/packages/15/64/941b205e2e46cc2297c245c64aa7691410b7454fa4d07a6cb3cf59487833/ty-0.0.38-py3-none-win_amd64.whl", hash = "sha256:eef0a8956ba14514076b1a963d13eb32986d9ebad7f0527b3cc01cb68bf35147", size = 11650542, upload-time = "2026-05-20T00:15:01.441Z" }, + { url = "https://files.pythonhosted.org/packages/59/02/c1c4f9ec4b94d95190636fa13f79c32f65165fbe3a0503882d4df164d2ac/ty-0.0.38-py3-none-win_arm64.whl", hash = "sha256:79abfc8658a026c30b1c955613437dab3ef4b12feca56a3e6df50903cc39e07f", size = 11010307, upload-time = "2026-05-20T00:15:04.567Z" }, +] + [[package]] name = "typing-extensions" version = "4.13.2" @@ -482,6 +507,7 @@ dev = [ { name = "pytest", version = "9.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "pytz" }, { name = "ruff" }, + { name = "ty" }, ] [package.metadata] @@ -492,4 +518,5 @@ dev = [ { name = "pytest" }, { name = "pytz" }, { name = "ruff" }, + { name = "ty", specifier = ">=0.0.38" }, ]