Skip to content

Commit 6de41db

Browse files
rahul4091claude
andcommitted
feat: add countrystatecity-phonecodes package
New package providing international phone/dialing codes for 250+ countries with full type safety, lazy loading, and mypy strict support. - get_all_phonecodes() — all entries - get_phonecode_by_country(country_code) — lookup by ISO2 - get_countries_by_phonecode(phone_code) — countries sharing a code - search_phonecodes(query) — search by name, code, or phone code - supports +prefix in phone code lookups (e.g. "+44" == "44") Updated all 4 GitHub Actions workflows to include phonecodes. Updated root README with new package, usage example, and install. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c45bdb9 commit 6de41db

19 files changed

Lines changed: 1890 additions & 13 deletions

File tree

.github/workflows/publish.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ on:
1717
- timezones
1818
- currencies
1919
- translations
20+
- phonecodes
2021
- all
2122
workflow_call:
2223
inputs:
@@ -45,20 +46,20 @@ jobs:
4546
run: |
4647
INPUT="${{ inputs.package }}"
4748
if [ "$INPUT" = "all" ]; then
48-
echo 'packages=["countries","timezones","currencies","translations"]' >> $GITHUB_OUTPUT
49+
echo 'packages=["countries","timezones","currencies","translations","phonecodes"]' >> $GITHUB_OUTPUT
4950
elif [ -n "$INPUT" ]; then
5051
echo "packages=[\"$INPUT\"]" >> $GITHUB_OUTPUT
5152
else
5253
# Push trigger: only publish packages whose files actually changed
5354
PKGS=""
54-
for pkg in countries timezones currencies translations; do
55+
for pkg in countries timezones currencies translations phonecodes; do
5556
if git diff --name-only HEAD~1 HEAD -- "python/packages/$pkg/" | grep -q .; then
5657
PKGS="${PKGS}\"${pkg}\","
5758
fi
5859
done
5960
PKGS="[${PKGS%,}]"
6061
if [ "$PKGS" = "[]" ]; then
61-
PKGS='["countries","timezones","currencies","translations"]'
62+
PKGS='["countries","timezones","currencies","translations","phonecodes"]'
6263
fi
6364
echo "packages=$PKGS" >> $GITHUB_OUTPUT
6465
fi

.github/workflows/python-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
fail-fast: false
1919
matrix:
2020
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
21-
package: [countries, timezones, currencies, translations]
21+
package: [countries, timezones, currencies, translations, phonecodes]
2222

2323
steps:
2424
- uses: actions/checkout@v4

.github/workflows/release.yml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626

2727
- name: Install dependencies
2828
run: |
29-
for pkg in countries timezones currencies translations; do
29+
for pkg in countries timezones currencies translations phonecodes; do
3030
pip install -e "python/packages/$pkg/.[dev]" -q
3131
done
3232
@@ -44,7 +44,7 @@ jobs:
4444
new_version = f'{major}.{minor}.{patch + 1}'
4545
4646
# Apply same version to all packages
47-
for pkg in ['countries', 'timezones', 'currencies', 'translations']:
47+
for pkg in ['countries', 'timezones', 'currencies', 'translations', 'phonecodes']:
4848
pyproject = pathlib.Path(f'python/packages/{pkg}/pyproject.toml')
4949
content = pyproject.read_text()
5050
content = re.sub(r'version = \"\d+\.\d+\.\d+\"', f'version = \"{new_version}\"', content)
@@ -67,7 +67,7 @@ jobs:
6767
PR_NUMBER: ${{ github.event.pull_request.number }}
6868
run: |
6969
DATE=$(date +%Y-%m-%d)
70-
for pkg in countries timezones currencies translations; do
70+
for pkg in countries timezones currencies translations phonecodes; do
7171
CHANGELOG="python/packages/$pkg/CHANGELOG.md"
7272
ENTRY="## [${NEW_VERSION#v}] - $DATE\n\n### Changed\n- Updated data from upstream database (PR #$PR_NUMBER)\n"
7373
if [ -f "$CHANGELOG" ]; then
@@ -81,7 +81,7 @@ jobs:
8181
8282
- name: Run tests
8383
run: |
84-
for pkg in countries timezones currencies translations; do
84+
for pkg in countries timezones currencies translations phonecodes; do
8585
pytest python/packages/$pkg/tests/
8686
done
8787
@@ -95,7 +95,8 @@ jobs:
9595
python/packages/countries/pyproject.toml python/packages/countries/countrystatecity_countries/__init__.py python/packages/countries/CHANGELOG.md \
9696
python/packages/timezones/pyproject.toml python/packages/timezones/countrystatecity_timezones/__init__.py python/packages/timezones/CHANGELOG.md \
9797
python/packages/currencies/pyproject.toml python/packages/currencies/countrystatecity_currencies/__init__.py python/packages/currencies/CHANGELOG.md \
98-
python/packages/translations/pyproject.toml python/packages/translations/countrystatecity_translations/__init__.py python/packages/translations/CHANGELOG.md
98+
python/packages/translations/pyproject.toml python/packages/translations/countrystatecity_translations/__init__.py python/packages/translations/CHANGELOG.md \
99+
python/packages/phonecodes/pyproject.toml python/packages/phonecodes/countrystatecity_phonecodes/__init__.py python/packages/phonecodes/CHANGELOG.md
99100
git commit -m "chore: release ${NEW_VERSION} for all packages"
100101
git push
101102

.github/workflows/update-data.yml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ jobs:
6262
python python/packages/timezones/scripts/generate-data.py
6363
python python/packages/currencies/scripts/generate-data.py
6464
python python/packages/translations/scripts/generate-data.py
65+
python python/packages/phonecodes/scripts/generate-data.py
6566
6667
- name: Collect new data statistics
6768
id: data-stats
@@ -70,23 +71,25 @@ jobs:
7071
TIMEZONES=$(cat python/packages/timezones/countrystatecity_timezones/data/timezones.json | grep -o '"zoneName"' | wc -l)
7172
CURRENCIES=$(cat python/packages/currencies/countrystatecity_currencies/data/currencies.json | grep -o '"code"' | wc -l)
7273
TRANSLATIONS=$(cat python/packages/translations/countrystatecity_translations/data/translations.json | grep -o '"lang"' | wc -l)
74+
PHONECODES=$(cat python/packages/phonecodes/countrystatecity_phonecodes/data/phonecodes.json | grep -o '"phoneCode"' | wc -l)
7375
echo "countries=$COUNTRIES" >> $GITHUB_OUTPUT
7476
echo "timezones=$TIMEZONES" >> $GITHUB_OUTPUT
7577
echo "currencies=$CURRENCIES" >> $GITHUB_OUTPUT
7678
echo "translations=$TRANSLATIONS" >> $GITHUB_OUTPUT
77-
echo "Countries: $COUNTRIES | Timezones: $TIMEZONES | Currencies: $CURRENCIES | Translations: $TRANSLATIONS"
79+
echo "phonecodes=$PHONECODES" >> $GITHUB_OUTPUT
80+
echo "Countries: $COUNTRIES | Timezones: $TIMEZONES | Currencies: $CURRENCIES | Translations: $TRANSLATIONS | Phonecodes: $PHONECODES"
7881
7982
- name: Run tests with new data
8083
run: |
81-
for pkg in countries timezones currencies translations; do
84+
for pkg in countries timezones currencies translations phonecodes; do
8285
echo "=== Testing $pkg ==="
8386
pip install -e "python/packages/$pkg/.[dev]" -q
8487
pytest python/packages/$pkg/tests/ --cov=countrystatecity_$pkg --cov-report=term
8588
done
8689
8790
- name: Type check
8891
run: |
89-
for pkg in countries timezones currencies translations; do
92+
for pkg in countries timezones currencies translations phonecodes; do
9093
echo "=== Type checking $pkg ==="
9194
mypy python/packages/$pkg/countrystatecity_$pkg/ --strict
9295
done
@@ -104,6 +107,7 @@ jobs:
104107
python/packages/timezones/countrystatecity_timezones/data \
105108
python/packages/currencies/countrystatecity_currencies/data \
106109
python/packages/translations/countrystatecity_translations/data \
110+
python/packages/phonecodes/countrystatecity_phonecodes/data \
107111
| grep -q .; then
108112
echo "changed=true" >> $GITHUB_OUTPUT
109113
echo "Data changes detected"
@@ -131,6 +135,7 @@ jobs:
131135
| countrystatecity-timezones | ${{ steps.data-stats.outputs.timezones }} timezones |
132136
| countrystatecity-currencies | ${{ steps.data-stats.outputs.currencies }} currencies |
133137
| countrystatecity-translations | ${{ steps.data-stats.outputs.translations }} translations |
138+
| countrystatecity-phonecodes | ${{ steps.data-stats.outputs.phonecodes }} phone codes |
134139
135140
### Changes
136141
- Downloaded latest dataset from source repository

README.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Official Python packages for accessing comprehensive countries, states, cities,
1515
| **[countrystatecity-timezones](./python/packages/timezones/)** | [![PyPI](https://img.shields.io/pypi/v/countrystatecity-timezones)](https://pypi.org/project/countrystatecity-timezones/) | IANA timezone data and time conversion utilities |
1616
| **[countrystatecity-currencies](./python/packages/currencies/)** | [![PyPI](https://img.shields.io/pypi/v/countrystatecity-currencies)](https://pypi.org/project/countrystatecity-currencies/) | Currency codes, names, and symbols |
1717
| **[countrystatecity-translations](./python/packages/translations/)** | [![PyPI](https://img.shields.io/pypi/v/countrystatecity-translations)](https://pypi.org/project/countrystatecity-translations/) | Country name translations in 18+ languages |
18+
| **[countrystatecity-phonecodes](./python/packages/phonecodes/)** | [![PyPI](https://img.shields.io/pypi/v/countrystatecity-phonecodes)](https://pypi.org/project/countrystatecity-phonecodes/) | International phone/dialing codes for 250+ countries |
1819

1920
> **Note:** There is no bare `countrystatecity` package on PyPI. Always install with the suffix (`-countries`, `-timezones`, `-currencies`, `-translations`).
2021
@@ -27,6 +28,7 @@ pip install countrystatecity-countries
2728
pip install countrystatecity-timezones
2829
pip install countrystatecity-currencies
2930
pip install countrystatecity-translations
31+
pip install countrystatecity-phonecodes
3032
```
3133

3234
## 📖 Usage
@@ -100,6 +102,31 @@ countries = get_countries_by_currency("EUR")
100102
results = search_currencies("dollar")
101103
```
102104

105+
### Phone Codes
106+
107+
```python
108+
from countrystatecity_phonecodes import (
109+
get_all_phonecodes,
110+
get_phonecode_by_country,
111+
get_countries_by_phonecode,
112+
search_phonecodes,
113+
)
114+
115+
# Phone code for a country
116+
us = get_phonecode_by_country("US")
117+
print(f"+{us.phoneCode}{us.countryName}") # +1 — United States
118+
119+
# All countries sharing a dialing code
120+
plus1 = get_countries_by_phonecode("1")
121+
print(f"{len(plus1)} countries use +1")
122+
123+
# Works with or without + prefix
124+
plus44 = get_countries_by_phonecode("+44")
125+
126+
# Search
127+
results = search_phonecodes("united")
128+
```
129+
103130
### Translations
104131

105132
```python
@@ -132,6 +159,7 @@ japanese = get_translations_by_language("ja")
132159
-**400+ timezones** with GMT offsets and time conversion
133160
-**Currency data** for every country
134161
-**Translations** in 18+ languages
162+
-**Phone/dialing codes** for 250+ countries
135163
-**Zero external dependencies** (except Pydantic)
136164
-**Python 3.8–3.12** support
137165
-**Full test coverage** with pytest
@@ -145,7 +173,8 @@ countrystatecity-pypi/
145173
│ ├── countries/ # countrystatecity-countries
146174
│ ├── timezones/ # countrystatecity-timezones
147175
│ ├── currencies/ # countrystatecity-currencies
148-
│ └── translations/ # countrystatecity-translations
176+
│ ├── translations/ # countrystatecity-translations
177+
│ └── phonecodes/ # countrystatecity-phonecodes
149178
150179
└── .github/
151180
└── workflows/
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Changelog
2+
3+
## [1.0.0] - 2026-06-12
4+
5+
### Added
6+
- Initial release of countrystatecity-phonecodes
7+
- `get_all_phonecodes()` — all 250+ phone code entries
8+
- `get_phonecode_by_country(country_code)` — lookup by ISO2 country code
9+
- `get_countries_by_phonecode(phone_code)` — all countries sharing a dialing code
10+
- `search_phonecodes(query)` — search by country name, code, or phone code
11+
- Full type safety with Pydantic models and mypy strict mode
12+
- Lazy loading with LRU cache
13+
- Python 3.8–3.12 support

python/packages/phonecodes/LICENSE

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Open Database License (ODbL) v1.0
2+
3+
This package uses data from the countries-states-cities-database project,
4+
which is licensed under the Open Database License (ODbL) v1.0.
5+
6+
For the full text of the ODbL license, please visit:
7+
https://opendatacommons.org/licenses/odbl/1-0/
8+
9+
Summary:
10+
You are free to:
11+
- Share: Copy and redistribute the database
12+
- Create: Produce works from the database
13+
- Adapt: Modify, transform and build upon the database
14+
15+
Under the following conditions:
16+
- Attribute: You must attribute any public use of the database
17+
- Share-Alike: If you publicly use any adapted version, you must also offer
18+
that adapted database under the ODbL
19+
- Keep open: If you redistribute the database, you must keep it open
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
include README.md
2+
include LICENSE
3+
include CHANGELOG.md
4+
5+
include countrystatecity_phonecodes/py.typed
6+
7+
recursive-include countrystatecity_phonecodes/data *.json
8+
9+
recursive-exclude tests *
10+
exclude tests
11+
12+
exclude .gitignore
13+
recursive-exclude * __pycache__
14+
recursive-exclude * *.py[co]
15+
recursive-exclude * .pytest_cache
16+
recursive-exclude * .mypy_cache
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# countrystatecity-phonecodes
2+
3+
Type-safe Python package for international phone/dialing codes with 250+ country associations.
4+
5+
[![PyPI](https://img.shields.io/pypi/v/countrystatecity-phonecodes)](https://pypi.org/project/countrystatecity-phonecodes/)
6+
[![Python Version](https://img.shields.io/pypi/pyversions/countrystatecity-phonecodes)](https://pypi.org/project/countrystatecity-phonecodes/)
7+
[![License](https://img.shields.io/badge/License-ODbL--1.0-blue.svg)](LICENSE)
8+
9+
## Installation
10+
11+
```bash
12+
pip install countrystatecity-phonecodes
13+
```
14+
15+
## Usage
16+
17+
```python
18+
from countrystatecity_phonecodes import (
19+
get_all_phonecodes,
20+
get_phonecode_by_country,
21+
get_countries_by_phonecode,
22+
search_phonecodes,
23+
)
24+
25+
# Get phone code for a country
26+
us = get_phonecode_by_country("US")
27+
print(f"+{us.phoneCode}{us.countryName}") # +1 — United States
28+
29+
# Get all countries sharing a dialing code
30+
plus1 = get_countries_by_phonecode("1")
31+
print(f"{len(plus1)} countries use +1") # 25 countries use +1
32+
33+
# Works with or without + prefix
34+
plus44 = get_countries_by_phonecode("+44")
35+
36+
# Search by country name, code, or phone code
37+
results = search_phonecodes("united")
38+
results = search_phonecodes("44")
39+
40+
# All phone codes
41+
all_codes = get_all_phonecodes()
42+
print(f"Total entries: {len(all_codes)}")
43+
```
44+
45+
## API Reference
46+
47+
### `get_all_phonecodes() -> List[PhoneCode]`
48+
Returns all phone code entries (one per country).
49+
50+
### `get_phonecode_by_country(country_code: str) -> Optional[PhoneCode]`
51+
Returns the phone code for a country by ISO2 code (e.g., `"US"`).
52+
53+
### `get_countries_by_phonecode(phone_code: str) -> List[PhoneCode]`
54+
Returns all countries sharing a dialing code (e.g., `"1"` or `"+1"`).
55+
56+
### `search_phonecodes(query: str) -> List[PhoneCode]`
57+
Search by country name, ISO2 code, or phone code (case-insensitive).
58+
59+
## PhoneCode Model
60+
61+
```python
62+
class PhoneCode:
63+
phoneCode: str # e.g. "1", "44", "91"
64+
countryCode: str # ISO2 e.g. "US", "GB", "IN"
65+
countryName: str # e.g. "United States"
66+
```
67+
68+
## License
69+
70+
[Open Database License (ODbL-1.0)](LICENSE)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""Official phonecodes database with type hints and lazy loading.
2+
3+
This package provides access to a comprehensive database of international
4+
phone/dialing codes with country associations.
5+
6+
Example:
7+
>>> from countrystatecity_phonecodes import (
8+
... get_phonecode_by_country,
9+
... get_countries_by_phonecode,
10+
... )
11+
>>> us = get_phonecode_by_country("US")
12+
>>> plus1_countries = get_countries_by_phonecode("1")
13+
"""
14+
15+
__version__ = "1.0.0"
16+
17+
from .api import (
18+
get_all_phonecodes,
19+
get_countries_by_phonecode,
20+
get_phonecode_by_country,
21+
search_phonecodes,
22+
)
23+
from .models import PhoneCode
24+
25+
__all__ = [
26+
# Version
27+
"__version__",
28+
# Models
29+
"PhoneCode",
30+
# API
31+
"get_all_phonecodes",
32+
"get_phonecode_by_country",
33+
"get_countries_by_phonecode",
34+
"search_phonecodes",
35+
]

0 commit comments

Comments
 (0)