demografix 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,49 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Set up Python ${{ matrix.python-version }}
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+
24
+ - name: Install package with dev extras
25
+ run: python -m pip install -e .[dev]
26
+
27
+ - name: Run tests
28
+ run: python -m pytest -q
29
+
30
+ build:
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - uses: actions/checkout@v4
34
+
35
+ - name: Set up Python
36
+ uses: actions/setup-python@v5
37
+ with:
38
+ python-version: "3.x"
39
+
40
+ - name: Build sdist and wheel
41
+ run: |
42
+ python -m pip install build
43
+ python -m build
44
+
45
+ - name: Upload distribution artifacts
46
+ uses: actions/upload-artifact@v4
47
+ with:
48
+ name: dist
49
+ path: dist/
@@ -0,0 +1,73 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+
8
+ jobs:
9
+ build:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Set up Python
15
+ uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.x"
18
+
19
+ - name: Verify tag matches manifest version
20
+ run: |
21
+ tag="${GITHUB_REF_NAME#v}"
22
+ manifest="$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])')"
23
+ echo "Tag version: $tag"
24
+ echo "Manifest version: $manifest"
25
+ if [ "$tag" != "$manifest" ]; then
26
+ echo "::error::Tag version ($tag) does not match pyproject.toml version ($manifest)."
27
+ exit 1
28
+ fi
29
+
30
+ - name: Build sdist and wheel
31
+ run: |
32
+ python -m pip install build
33
+ python -m build
34
+
35
+ - name: Upload distribution artifacts
36
+ uses: actions/upload-artifact@v4
37
+ with:
38
+ name: dist
39
+ path: dist/
40
+
41
+ publish-pypi:
42
+ needs: build
43
+ runs-on: ubuntu-latest
44
+ environment: release
45
+ permissions:
46
+ id-token: write
47
+ steps:
48
+ - name: Download distribution artifacts
49
+ uses: actions/download-artifact@v4
50
+ with:
51
+ name: dist
52
+ path: dist/
53
+
54
+ - name: Publish to PyPI via Trusted Publishing
55
+ uses: pypa/gh-action-pypi-publish@release/v1
56
+
57
+ github-release:
58
+ needs: publish-pypi
59
+ runs-on: ubuntu-latest
60
+ permissions:
61
+ contents: write
62
+ steps:
63
+ - name: Download distribution artifacts
64
+ uses: actions/download-artifact@v4
65
+ with:
66
+ name: dist
67
+ path: dist/
68
+
69
+ - name: Create GitHub Release
70
+ uses: softprops/action-gh-release@v2
71
+ with:
72
+ files: dist/*
73
+ generate_release_notes: true
@@ -0,0 +1,10 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .pytest_cache/
4
+ build/
5
+ dist/
6
+ *.egg-info/
7
+ .venv/
8
+ venv/
9
+ .mypy_cache/
10
+ .ruff_cache/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Demografix
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,183 @@
1
+ Metadata-Version: 2.4
2
+ Name: demografix
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for the Demografix APIs: genderize.io, agify.io, nationalize.io.
5
+ Project-URL: Homepage, https://genderize.io
6
+ Project-URL: Documentation, https://genderize.io/documentation/api
7
+ Project-URL: Repository, https://github.com/DemografixGenderize/demografix-python
8
+ Project-URL: Issues, https://github.com/DemografixGenderize/demografix-python/issues
9
+ Author-email: Demografix <info@genderize.io>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: agify,demografix,demographics,genderize,nationalize
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Requires-Python: >=3.10
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=7; extra == 'dev'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # Demografix Python SDK
27
+
28
+ Run demographic analysis over names — predicted gender, age, and nationality — from one client. The package
29
+ covers [genderize.io](https://genderize.io), [agify.io](https://agify.io), and
30
+ [nationalize.io](https://nationalize.io).
31
+
32
+ ## Install
33
+
34
+ ```
35
+ pip install demografix
36
+ ```
37
+
38
+ The SDK has zero runtime dependencies. It requires Python 3.10 or newer.
39
+
40
+ ## Quickstart
41
+
42
+ Construct a client, run a list of names through a batch call, read the predictions, and read the quota.
43
+
44
+ ```python
45
+ from collections import Counter
46
+ from demografix import Demografix
47
+
48
+ client = Demografix(api_key="YOUR_API_KEY")
49
+
50
+ names = ["michael", "matthew", "jane", "sofia", "lars"]
51
+
52
+ batch = client.genderize_batch(names)
53
+
54
+ split = Counter(r.gender or "unknown" for r in batch.results)
55
+ print(split) # Counter({'male': 3, 'female': 2})
56
+ print(batch.quota.remaining) # 24987
57
+ ```
58
+
59
+ ## API keys
60
+
61
+ An API key is required. Creating one is free and includes 2,500 requests per month. Generate a key in your
62
+ dashboard at [genderize.io](https://genderize.io), [agify.io](https://agify.io), or
63
+ [nationalize.io](https://nationalize.io). One key works across all three services.
64
+
65
+ ## Usage
66
+
67
+ ### Gender
68
+
69
+ ```python
70
+ result = client.genderize("peter")
71
+ result.gender # "male", "female", or None
72
+ result.probability # 1.0
73
+ result.count # 1352696
74
+
75
+ batch = client.genderize_batch(["michael", "matthew", "jane"])
76
+ gender_mix = Counter(r.gender or "unknown" for r in batch.results)
77
+ ```
78
+
79
+ ### Age
80
+
81
+ ```python
82
+ result = client.agify("michael")
83
+ result.age # 57 or None
84
+ result.count # 311558
85
+
86
+ batch = client.agify_batch(["michael", "matthew", "jane"])
87
+ ages = [r.age for r in batch.results if r.age is not None]
88
+ average_age = sum(ages) / len(ages)
89
+ ```
90
+
91
+ ### Nationality
92
+
93
+ ```python
94
+ result = client.nationalize("nguyen")
95
+ result.country[0].country_id # "VN"
96
+ result.country[0].probability # 0.891132
97
+
98
+ batch = client.nationalize_batch(["nguyen", "schmidt", "rossi"])
99
+ top_countries = Counter(
100
+ r.country[0].country_id for r in batch.results if r.country
101
+ )
102
+ ```
103
+
104
+ Each batch accepts at most 10 names. A batch of more than 10 raises `ValidationError` before any request
105
+ goes out.
106
+
107
+ ## country_id
108
+
109
+ `genderize` and `agify` accept an optional `country_id` (ISO 3166-1 alpha-2) to scope the prediction to one
110
+ country. Input is case-insensitive; the response echoes it uppercase. `nationalize` has no such parameter.
111
+
112
+ ```python
113
+ result = client.genderize("kim", country_id="us")
114
+ result.country_id # "US"
115
+
116
+ batch = client.agify_batch(["michael", "matthew"], country_id="us")
117
+ ```
118
+
119
+ ## Quota
120
+
121
+ Every result and every raised error carries a `quota` read from the response headers. Quota is never cached
122
+ on the client; read it from the returned value.
123
+
124
+ | Field | Meaning |
125
+ |---|---|
126
+ | `limit` | names allowed in the current window |
127
+ | `remaining` | names left in the current window |
128
+ | `reset` | seconds until the window resets |
129
+
130
+ ```python
131
+ batch = client.genderize_batch(["michael", "matthew"])
132
+ batch.quota.remaining
133
+ ```
134
+
135
+ ## Errors
136
+
137
+ Non-2xx responses raise a typed exception. Transport failures raise `TransportError`. Every exception
138
+ subclasses `DemografixError` and carries `status`, `message`, and `quota` (when the response included
139
+ headers).
140
+
141
+ | Exception | Status | Cause |
142
+ |---|---|---|
143
+ | `AuthError` | 401 | invalid or missing API key |
144
+ | `SubscriptionError` | 402 | expired freebie or inactive subscription |
145
+ | `ValidationError` | 422 | bad parameter, or a batch over 10 names (raised client-side) |
146
+ | `RateLimitError` | 429 | window exhausted; `quota` is always populated |
147
+ | `DemografixError` | other non-2xx | base class for the hierarchy |
148
+ | `TransportError` | none | network error, timeout, or non-JSON body |
149
+
150
+ A `RateLimitError` carries `quota`, so `reset` tells you how long to wait before retrying.
151
+
152
+ ```python
153
+ import time
154
+ from demografix import Demografix, RateLimitError
155
+
156
+ client = Demografix(api_key="YOUR_API_KEY")
157
+ names = ["michael", "matthew", "jane"]
158
+
159
+ while True:
160
+ try:
161
+ batch = client.genderize_batch(names)
162
+ break
163
+ except RateLimitError as exc:
164
+ time.sleep(exc.quota.reset)
165
+ ```
166
+
167
+ ## Methods
168
+
169
+ | Method | Returns | country_id |
170
+ |---|---|---|
171
+ | `genderize(name, country_id=None)` | `GenderizeResult` | yes |
172
+ | `genderize_batch(names, country_id=None)` | `Batch` of `GenderizePrediction` | yes |
173
+ | `agify(name, country_id=None)` | `AgifyResult` | yes |
174
+ | `agify_batch(names, country_id=None)` | `Batch` of `AgifyPrediction` | yes |
175
+ | `nationalize(name)` | `NationalizeResult` | no |
176
+ | `nationalize_batch(names)` | `Batch` of `NationalizePrediction` | no |
177
+
178
+ A `*Result` exposes the prediction fields directly plus a `quota`. A `Batch` exposes `results` plus one
179
+ `quota` for the whole response.
180
+
181
+ ## Reference
182
+
183
+ Full API reference: [genderize.io/documentation/api](https://genderize.io/documentation/api).
@@ -0,0 +1,158 @@
1
+ # Demografix Python SDK
2
+
3
+ Run demographic analysis over names — predicted gender, age, and nationality — from one client. The package
4
+ covers [genderize.io](https://genderize.io), [agify.io](https://agify.io), and
5
+ [nationalize.io](https://nationalize.io).
6
+
7
+ ## Install
8
+
9
+ ```
10
+ pip install demografix
11
+ ```
12
+
13
+ The SDK has zero runtime dependencies. It requires Python 3.10 or newer.
14
+
15
+ ## Quickstart
16
+
17
+ Construct a client, run a list of names through a batch call, read the predictions, and read the quota.
18
+
19
+ ```python
20
+ from collections import Counter
21
+ from demografix import Demografix
22
+
23
+ client = Demografix(api_key="YOUR_API_KEY")
24
+
25
+ names = ["michael", "matthew", "jane", "sofia", "lars"]
26
+
27
+ batch = client.genderize_batch(names)
28
+
29
+ split = Counter(r.gender or "unknown" for r in batch.results)
30
+ print(split) # Counter({'male': 3, 'female': 2})
31
+ print(batch.quota.remaining) # 24987
32
+ ```
33
+
34
+ ## API keys
35
+
36
+ An API key is required. Creating one is free and includes 2,500 requests per month. Generate a key in your
37
+ dashboard at [genderize.io](https://genderize.io), [agify.io](https://agify.io), or
38
+ [nationalize.io](https://nationalize.io). One key works across all three services.
39
+
40
+ ## Usage
41
+
42
+ ### Gender
43
+
44
+ ```python
45
+ result = client.genderize("peter")
46
+ result.gender # "male", "female", or None
47
+ result.probability # 1.0
48
+ result.count # 1352696
49
+
50
+ batch = client.genderize_batch(["michael", "matthew", "jane"])
51
+ gender_mix = Counter(r.gender or "unknown" for r in batch.results)
52
+ ```
53
+
54
+ ### Age
55
+
56
+ ```python
57
+ result = client.agify("michael")
58
+ result.age # 57 or None
59
+ result.count # 311558
60
+
61
+ batch = client.agify_batch(["michael", "matthew", "jane"])
62
+ ages = [r.age for r in batch.results if r.age is not None]
63
+ average_age = sum(ages) / len(ages)
64
+ ```
65
+
66
+ ### Nationality
67
+
68
+ ```python
69
+ result = client.nationalize("nguyen")
70
+ result.country[0].country_id # "VN"
71
+ result.country[0].probability # 0.891132
72
+
73
+ batch = client.nationalize_batch(["nguyen", "schmidt", "rossi"])
74
+ top_countries = Counter(
75
+ r.country[0].country_id for r in batch.results if r.country
76
+ )
77
+ ```
78
+
79
+ Each batch accepts at most 10 names. A batch of more than 10 raises `ValidationError` before any request
80
+ goes out.
81
+
82
+ ## country_id
83
+
84
+ `genderize` and `agify` accept an optional `country_id` (ISO 3166-1 alpha-2) to scope the prediction to one
85
+ country. Input is case-insensitive; the response echoes it uppercase. `nationalize` has no such parameter.
86
+
87
+ ```python
88
+ result = client.genderize("kim", country_id="us")
89
+ result.country_id # "US"
90
+
91
+ batch = client.agify_batch(["michael", "matthew"], country_id="us")
92
+ ```
93
+
94
+ ## Quota
95
+
96
+ Every result and every raised error carries a `quota` read from the response headers. Quota is never cached
97
+ on the client; read it from the returned value.
98
+
99
+ | Field | Meaning |
100
+ |---|---|
101
+ | `limit` | names allowed in the current window |
102
+ | `remaining` | names left in the current window |
103
+ | `reset` | seconds until the window resets |
104
+
105
+ ```python
106
+ batch = client.genderize_batch(["michael", "matthew"])
107
+ batch.quota.remaining
108
+ ```
109
+
110
+ ## Errors
111
+
112
+ Non-2xx responses raise a typed exception. Transport failures raise `TransportError`. Every exception
113
+ subclasses `DemografixError` and carries `status`, `message`, and `quota` (when the response included
114
+ headers).
115
+
116
+ | Exception | Status | Cause |
117
+ |---|---|---|
118
+ | `AuthError` | 401 | invalid or missing API key |
119
+ | `SubscriptionError` | 402 | expired freebie or inactive subscription |
120
+ | `ValidationError` | 422 | bad parameter, or a batch over 10 names (raised client-side) |
121
+ | `RateLimitError` | 429 | window exhausted; `quota` is always populated |
122
+ | `DemografixError` | other non-2xx | base class for the hierarchy |
123
+ | `TransportError` | none | network error, timeout, or non-JSON body |
124
+
125
+ A `RateLimitError` carries `quota`, so `reset` tells you how long to wait before retrying.
126
+
127
+ ```python
128
+ import time
129
+ from demografix import Demografix, RateLimitError
130
+
131
+ client = Demografix(api_key="YOUR_API_KEY")
132
+ names = ["michael", "matthew", "jane"]
133
+
134
+ while True:
135
+ try:
136
+ batch = client.genderize_batch(names)
137
+ break
138
+ except RateLimitError as exc:
139
+ time.sleep(exc.quota.reset)
140
+ ```
141
+
142
+ ## Methods
143
+
144
+ | Method | Returns | country_id |
145
+ |---|---|---|
146
+ | `genderize(name, country_id=None)` | `GenderizeResult` | yes |
147
+ | `genderize_batch(names, country_id=None)` | `Batch` of `GenderizePrediction` | yes |
148
+ | `agify(name, country_id=None)` | `AgifyResult` | yes |
149
+ | `agify_batch(names, country_id=None)` | `Batch` of `AgifyPrediction` | yes |
150
+ | `nationalize(name)` | `NationalizeResult` | no |
151
+ | `nationalize_batch(names)` | `Batch` of `NationalizePrediction` | no |
152
+
153
+ A `*Result` exposes the prediction fields directly plus a `quota`. A `Batch` exposes `results` plus one
154
+ `quota` for the whole response.
155
+
156
+ ## Reference
157
+
158
+ Full API reference: [genderize.io/documentation/api](https://genderize.io/documentation/api).
@@ -0,0 +1,73 @@
1
+ # Releasing
2
+
3
+ This package publishes to PyPI through GitHub Actions. Publishing uses PyPI
4
+ Trusted Publishing (OIDC), so there is no API token to store or rotate. The
5
+ `release` workflow runs on any pushed tag that matches `v*.*.*`.
6
+
7
+ ## One-time setup
8
+
9
+ Do this once, before the first release.
10
+
11
+ ### 1. Reserve the project name on PyPI
12
+
13
+ The project name `demografix` must exist on PyPI, or be claimable by the
14
+ account that registers the Trusted Publisher. Confirm the name is available at
15
+ https://pypi.org/project/demografix/ before going further.
16
+
17
+ ### 2. Register the Trusted Publisher on PyPI
18
+
19
+ In the PyPI project settings, under "Publishing", add a new GitHub trusted
20
+ publisher with these exact values:
21
+
22
+ - Owner: `DemografixGenderize`
23
+ - Repository: `demografix-python`
24
+ - Workflow name: `release.yml`
25
+ - Environment: `release`
26
+
27
+ If the project does not exist on PyPI yet, register the publisher as a
28
+ "pending" publisher instead. PyPI creates the project on the first successful
29
+ upload.
30
+
31
+ ### 3. Create the `release` environment in GitHub
32
+
33
+ In the repository settings, under "Environments", create an environment named
34
+ `release`. The publish job references this environment. Add required reviewers
35
+ or branch restrictions here if you want a manual gate before any upload.
36
+
37
+ No secrets are required. Trusted Publishing exchanges a short-lived OIDC token
38
+ for the upload credential at publish time. Do not add a `PYPI_API_TOKEN` or any
39
+ password.
40
+
41
+ ## Cutting a release
42
+
43
+ 1. Bump `version` in `pyproject.toml` to the new `X.Y.Z`.
44
+ 2. Commit the bump:
45
+
46
+ ```
47
+ git commit -am "Release vX.Y.Z"
48
+ ```
49
+
50
+ 3. Tag the commit. The tag must match the manifest version, with a `v` prefix:
51
+
52
+ ```
53
+ git tag vX.Y.Z
54
+ ```
55
+
56
+ 4. Push the commit and the tag:
57
+
58
+ ```
59
+ git push origin main
60
+ git push origin vX.Y.Z
61
+ ```
62
+
63
+ Pushing the tag starts the `release` workflow. It verifies the tag matches the
64
+ `pyproject.toml` version, builds the sdist and wheel, publishes to PyPI, and
65
+ creates a GitHub Release with the built artifacts attached.
66
+
67
+ ## If a release fails
68
+
69
+ - Tag/version mismatch: the build job stops before publishing. Delete the tag
70
+ (`git tag -d vX.Y.Z` and `git push origin :vX.Y.Z`), fix the version, and tag
71
+ again.
72
+ - PyPI rejects the upload because the version already exists: bump to a new
73
+ version and tag again. PyPI does not allow re-uploading an existing version.
@@ -0,0 +1,81 @@
1
+ """Summarize the demographic mix of a list of names.
2
+
3
+ Run a roster through all three services in batches of 10 and print an aggregate
4
+ gender split, age distribution, and nationality mix across the whole list.
5
+
6
+ Usage:
7
+ DEMOGRAFIX_API_KEY=your_key python examples/demographics_summary.py
8
+ """
9
+
10
+ import os
11
+ from collections import Counter
12
+
13
+ from demografix import Demografix
14
+
15
+ NAMES = [
16
+ "michael",
17
+ "matthew",
18
+ "jane",
19
+ "nguyen",
20
+ "kim",
21
+ "sofia",
22
+ "lars",
23
+ "amara",
24
+ ]
25
+
26
+
27
+ def chunked(items, size):
28
+ for start in range(0, len(items), size):
29
+ yield items[start : start + size]
30
+
31
+
32
+ def main():
33
+ api_key = os.environ.get("DEMOGRAFIX_API_KEY")
34
+ if not api_key:
35
+ raise SystemExit("Set DEMOGRAFIX_API_KEY to run this example.")
36
+ client = Demografix(api_key=api_key)
37
+
38
+ genders = Counter()
39
+ ages = []
40
+ countries = Counter()
41
+ remaining = None
42
+
43
+ for chunk in chunked(NAMES, 10):
44
+ g = client.genderize_batch(chunk)
45
+ a = client.agify_batch(chunk)
46
+ n = client.nationalize_batch(chunk)
47
+ remaining = n.quota.remaining
48
+
49
+ for prediction in g.results:
50
+ genders[prediction.gender or "unknown"] += 1
51
+ for prediction in a.results:
52
+ if prediction.age is not None:
53
+ ages.append(prediction.age)
54
+ for prediction in n.results:
55
+ if prediction.country:
56
+ countries[prediction.country[0].country_id] += 1
57
+
58
+ total = len(NAMES)
59
+ print("Names analyzed: %d" % total)
60
+
61
+ print("\nGender split:")
62
+ for gender, count in genders.most_common():
63
+ print(" %-8s %d (%.0f%%)" % (gender, count, 100 * count / total))
64
+
65
+ if ages:
66
+ print("\nAge distribution:")
67
+ print(" count %d" % len(ages))
68
+ print(" min %d" % min(ages))
69
+ print(" median %d" % sorted(ages)[len(ages) // 2])
70
+ print(" max %d" % max(ages))
71
+
72
+ print("\nTop nationality mix:")
73
+ for country_id, count in countries.most_common(5):
74
+ print(" %-4s %d" % (country_id, count))
75
+
76
+ if remaining is not None:
77
+ print("\nQuota remaining: %d" % remaining)
78
+
79
+
80
+ if __name__ == "__main__":
81
+ main()
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "demografix"
7
+ version = "0.1.0"
8
+ description = "Official Python SDK for the Demografix APIs: genderize.io, agify.io, nationalize.io."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Demografix", email = "info@genderize.io" }]
14
+ keywords = ["genderize", "agify", "nationalize", "demografix", "demographics"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ ]
25
+ dependencies = []
26
+
27
+ [project.optional-dependencies]
28
+ dev = ["pytest>=7"]
29
+
30
+ [project.urls]
31
+ Homepage = "https://genderize.io"
32
+ Documentation = "https://genderize.io/documentation/api"
33
+ Repository = "https://github.com/DemografixGenderize/demografix-python"
34
+ Issues = "https://github.com/DemografixGenderize/demografix-python/issues"
35
+
36
+ [tool.hatch.build.targets.wheel]
37
+ packages = ["src/demografix"]
38
+ # PEP 561: ship the py.typed marker so type checkers pick up the inline types.
39
+ force-include = { "src/demografix/py.typed" = "demografix/py.typed" }