pykosis 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.
Files changed (41) hide show
  1. pykosis-0.1.0/.agents/plugins/marketplace.json +20 -0
  2. pykosis-0.1.0/.claude-plugin/marketplace.json +27 -0
  3. pykosis-0.1.0/.github/workflows/check.yml +25 -0
  4. pykosis-0.1.0/.github/workflows/publish.yml +61 -0
  5. pykosis-0.1.0/.github/workflows/reusable-check.yml +98 -0
  6. pykosis-0.1.0/.gitignore +33 -0
  7. pykosis-0.1.0/LICENSE +21 -0
  8. pykosis-0.1.0/PKG-INFO +555 -0
  9. pykosis-0.1.0/README.en.md +539 -0
  10. pykosis-0.1.0/README.md +526 -0
  11. pykosis-0.1.0/plugins/kosis/.claude-plugin/plugin.json +19 -0
  12. pykosis-0.1.0/plugins/kosis/.codex-plugin/plugin.json +33 -0
  13. pykosis-0.1.0/plugins/kosis/skills/data/SKILL.md +72 -0
  14. pykosis-0.1.0/plugins/kosis/skills/explanation/SKILL.md +56 -0
  15. pykosis-0.1.0/plugins/kosis/skills/list/SKILL.md +58 -0
  16. pykosis-0.1.0/plugins/kosis/skills/meta/SKILL.md +58 -0
  17. pykosis-0.1.0/plugins/kosis/skills/search/SKILL.md +58 -0
  18. pykosis-0.1.0/pyproject.toml +60 -0
  19. pykosis-0.1.0/src/pykosis/__init__.py +60 -0
  20. pykosis-0.1.0/src/pykosis/__main__.py +8 -0
  21. pykosis-0.1.0/src/pykosis/_cache.py +75 -0
  22. pykosis-0.1.0/src/pykosis/_config.py +65 -0
  23. pykosis-0.1.0/src/pykosis/_parse.py +55 -0
  24. pykosis-0.1.0/src/pykosis/_transport.py +155 -0
  25. pykosis-0.1.0/src/pykosis/cli.py +327 -0
  26. pykosis-0.1.0/src/pykosis/client.py +381 -0
  27. pykosis-0.1.0/src/pykosis/curation/__init__.py +11 -0
  28. pykosis-0.1.0/src/pykosis/curation/_generated.py +1336 -0
  29. pykosis-0.1.0/src/pykosis/curation/_indicator.py +154 -0
  30. pykosis-0.1.0/src/pykosis/exceptions.py +72 -0
  31. pykosis-0.1.0/src/pykosis/pivot.py +98 -0
  32. pykosis-0.1.0/src/pykosis/py.typed +0 -0
  33. pykosis-0.1.0/src/pykosis/types.py +265 -0
  34. pykosis-0.1.0/tests/test_cli.py +183 -0
  35. pykosis-0.1.0/tests/test_client.py +468 -0
  36. pykosis-0.1.0/tests/test_config.py +57 -0
  37. pykosis-0.1.0/tests/test_curation.py +94 -0
  38. pykosis-0.1.0/tests/test_parse.py +38 -0
  39. pykosis-0.1.0/tests/test_pivot.py +86 -0
  40. pykosis-0.1.0/tools/curation_design.tsv +101 -0
  41. pykosis-0.1.0/tools/gen_curation.py +126 -0
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "pykosis",
3
+ "interface": {
4
+ "displayName": "kosis"
5
+ },
6
+ "plugins": [
7
+ {
8
+ "name": "kosis",
9
+ "source": {
10
+ "source": "local",
11
+ "path": "./plugins/kosis"
12
+ },
13
+ "policy": {
14
+ "installation": "AVAILABLE",
15
+ "authentication": "ON_INSTALL"
16
+ },
17
+ "category": "Productivity"
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "pykosis",
3
+ "owner": {
4
+ "name": "seokhoonj"
5
+ },
6
+ "description": "Read KOSIS (Statistics Korea) national statistics",
7
+ "plugins": [
8
+ {
9
+ "name": "kosis",
10
+ "displayName": "kosis",
11
+ "source": "./plugins/kosis",
12
+ "description": "Read KOSIS (Statistics Korea) national statistics",
13
+ "author": {
14
+ "name": "seokhoonj"
15
+ },
16
+ "homepage": "https://github.com/seokhoonj/pykosis",
17
+ "category": "Productivity",
18
+ "keywords": [
19
+ "kosis",
20
+ "statistics korea",
21
+ "korea",
22
+ "official statistics",
23
+ "census"
24
+ ]
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,25 @@
1
+ name: check
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ branches: [main]
7
+ pull_request:
8
+
9
+ # A newer push to the same branch or PR makes the older run's result obsolete,
10
+ # so cancel it rather than let both run to completion. The event name is in the
11
+ # key so a push never cancels a pull-request run, or vice versa.
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ # The check only reads the code to lint, type, and test it -- it never writes to the
17
+ # repo -- so it runs with the least privilege that still allows a checkout.
18
+ permissions:
19
+ contents: read
20
+
21
+ jobs:
22
+ check:
23
+ # The full check lives in reusable-check.yml so the release gate in
24
+ # publish.yml runs the identical job on the release commit.
25
+ uses: ./.github/workflows/reusable-check.yml
@@ -0,0 +1,61 @@
1
+ name: publish
2
+
3
+ # Publish to PyPI on a GitHub Release, via PyPI Trusted Publishing (OIDC): no API
4
+ # token or password is stored anywhere -- GitHub mints a short-lived identity token
5
+ # that PyPI verifies against the publisher registered for this repo (owner seokhoonj
6
+ # / repo pykosis / this workflow / environment "pypi").
7
+ #
8
+ # Three jobs. `gate` runs the same reusable check that check.yml runs, on the
9
+ # release commit, so a red build (a lint/type error, a broken test, a lost py.typed
10
+ # or console script) cannot reach an upload. `build` builds the sdist and wheel and
11
+ # hands them to `publish` as an artifact. `publish` -- the only job holding the OIDC
12
+ # token -- downloads that artifact and uploads it, and checks out no source, so the
13
+ # privileged step runs the least code.
14
+
15
+ on:
16
+ release:
17
+ types: [published]
18
+
19
+ # Workflow-level floor: any job without its own `permissions:` block still gets a
20
+ # read-only token, so a job added later cannot silently inherit a write-capable
21
+ # default. The build and publish jobs narrow it further below.
22
+ permissions:
23
+ contents: read
24
+
25
+ jobs:
26
+ gate:
27
+ uses: ./.github/workflows/reusable-check.yml
28
+
29
+ build:
30
+ needs: gate
31
+ runs-on: ubuntu-latest
32
+ timeout-minutes: 15
33
+ permissions:
34
+ contents: read
35
+ steps:
36
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
37
+ with:
38
+ persist-credentials: false
39
+ - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
40
+ - name: Build sdist and wheel, then check the metadata
41
+ run: |
42
+ uv build
43
+ uvx twine check dist/*
44
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
45
+ with:
46
+ name: dist
47
+ path: dist/
48
+
49
+ publish:
50
+ needs: build
51
+ runs-on: ubuntu-latest
52
+ timeout-minutes: 15
53
+ environment: pypi
54
+ permissions:
55
+ id-token: write # OIDC; this is what replaces a stored token
56
+ steps:
57
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
58
+ with:
59
+ name: dist
60
+ path: dist/
61
+ - uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1
@@ -0,0 +1,98 @@
1
+ name: reusable check
2
+
3
+ # The full check -- tests, lint, types, and the packaging assertions -- factored
4
+ # into one reusable job so both `check.yml` (on push / PR) and the release gate in
5
+ # `publish.yml` run the *identical* thing. One definition is what makes "publish
6
+ # gates on the full check" true; a second hand-maintained copy would drift, and a
7
+ # check added here silently would not gate releases.
8
+
9
+ on:
10
+ workflow_call:
11
+
12
+ # The floor lives on the shared body, not only on `check.yml`: `publish.yml`'s gate
13
+ # calls this same workflow, and if the floor were only on `check.yml` the gate would
14
+ # run this check with the repo-default (possibly write) token. Declared here, the
15
+ # check is read-only from every caller. A reusable workflow can only downscope from
16
+ # the caller, so this never widens anyone's token.
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ check:
22
+ runs-on: ubuntu-latest
23
+ timeout-minutes: 15
24
+ strategy:
25
+ fail-fast: false
26
+ matrix:
27
+ # Every minor release from the requires-python floor (>=3.11) through the
28
+ # current stable CPython -- the same set the trove classifiers advertise, so
29
+ # each is an audit of the other (no version claimed but untested).
30
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
31
+
32
+ steps:
33
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
34
+ with:
35
+ persist-credentials: false
36
+ - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
37
+
38
+ - name: Install
39
+ # A venv per matrix version, not `uv pip --system`: the runner's system
40
+ # Python is externally managed and is one fixed version whatever the matrix
41
+ # says. This is also what the README tells a person to run.
42
+ run: |
43
+ uv venv --python ${{ matrix.python-version }}
44
+ uv pip install -e ".[dev]"
45
+ .venv/bin/python -c "import sys; print('testing on', sys.version)"
46
+
47
+ - name: Test
48
+ run: .venv/bin/pytest -q
49
+
50
+ - name: Lint
51
+ run: .venv/bin/ruff check src tests
52
+
53
+ - name: Types
54
+ run: .venv/bin/mypy src
55
+
56
+ - name: Confirm the only runtime dependency is httpx
57
+ # A bare install must pull in nothing but httpx; a second runtime dependency
58
+ # creeping into `dependencies` is caught here rather than in a user's
59
+ # environment.
60
+ run: |
61
+ uv venv /tmp/bare --python ${{ matrix.python-version }}
62
+ uv pip install --python /tmp/bare/bin/python .
63
+ /tmp/bare/bin/python -c "
64
+ import re
65
+ import importlib.metadata as md
66
+ requires = md.requires('pykosis') or []
67
+ runtime = [r for r in requires if 'extra ==' not in r]
68
+ # Each requirement's bare name (before any version/marker/extra), PEP 503
69
+ # normalized; the runtime set must be exactly httpx.
70
+ names = sorted(re.split(r'[<>=!~;\[\s]', r, maxsplit=1)[0].replace('_', '-').lower() for r in runtime)
71
+ assert names == ['httpx'], f'unexpected runtime dependencies: {runtime}'
72
+ import pykosis
73
+ print('pykosis imports with only httpx')
74
+ "
75
+ # The console script runs, and its top-level --version prints (not shoved
76
+ # into a required subcommand).
77
+ /tmp/bare/bin/kosis --version
78
+
79
+ - name: Confirm a user's type checker can see the hints
80
+ # Every hint in this package is invisible to a user unless py.typed ships
81
+ # alongside it (PEP 561), and the source cannot answer whether it did:
82
+ # src/pykosis/py.typed can sit in git while the built wheel omits it. So ask
83
+ # it the way a user does -- install the built package into a clean
84
+ # environment and run their checker over their code.
85
+ run: |
86
+ uv venv /tmp/typed --python ${{ matrix.python-version }}
87
+ uv pip install --python /tmp/typed/bin/python . mypy
88
+ cat > /tmp/user_code.py <<'PY'
89
+ from pykosis import KOSIS
90
+
91
+ # start_period takes str | None; an int is neither, so a checker that can see
92
+ # the shipped hints must reject it. If py.typed is missing from the wheel,
93
+ # mypy skips pykosis instead and emits no such error.
94
+ KOSIS(api_key="k").fetch_data(org_id="101", tbl_id="DT_1B42", start_period=123)
95
+ PY
96
+ /tmp/typed/bin/mypy /tmp/user_code.py > /tmp/mypy_out 2>&1 || true
97
+ cat /tmp/mypy_out
98
+ grep -q 'incompatible type' /tmp/mypy_out
@@ -0,0 +1,33 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+ .env
11
+
12
+ # uv
13
+ uv.lock
14
+
15
+ # Tooling caches
16
+ .pytest_cache/
17
+ .ruff_cache/
18
+ .mypy_cache/
19
+ .coverage
20
+ htmlcov/
21
+
22
+ # Local scratch (never tracked)
23
+ dev/
24
+ refs/
25
+
26
+ # AI coding agents
27
+ CLAUDE.md
28
+ .claude/
29
+ AGENTS.md
30
+ AGENT.md
31
+ .codex/
32
+ GEMINI.md
33
+ .gemini/
pykosis-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Seokhoon Joo
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.