kpubdata 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.
- kpubdata-0.1.0/.github/ISSUE_TEMPLATE/new-provider-adapter.yml +105 -0
- kpubdata-0.1.0/.github/workflows/ci.yml +98 -0
- kpubdata-0.1.0/.github/workflows/integration.yml +50 -0
- kpubdata-0.1.0/.github/workflows/publish-pypi.yml +60 -0
- kpubdata-0.1.0/.gitignore +37 -0
- kpubdata-0.1.0/AGENTS.md +247 -0
- kpubdata-0.1.0/API_SPEC.md +160 -0
- kpubdata-0.1.0/ARCHITECTURE.md +464 -0
- kpubdata-0.1.0/CANONICAL_MODEL.md +355 -0
- kpubdata-0.1.0/CHANGELOG.md +40 -0
- kpubdata-0.1.0/CONTRIBUTING.md +193 -0
- kpubdata-0.1.0/LICENSE +21 -0
- kpubdata-0.1.0/PACKAGING.md +114 -0
- kpubdata-0.1.0/PKG-INFO +380 -0
- kpubdata-0.1.0/PRD.md +306 -0
- kpubdata-0.1.0/PROVIDER_ADAPTER_CONTRACT.md +251 -0
- kpubdata-0.1.0/README.md +343 -0
- kpubdata-0.1.0/ROADMAP.md +55 -0
- kpubdata-0.1.0/SUPPORTED_DATA.md +50 -0
- kpubdata-0.1.0/VALIDATION.md +106 -0
- kpubdata-0.1.0/docs/adrs/0001-dialect-inspired-architecture.md +22 -0
- kpubdata-0.1.0/docs/adrs/0002-standardize-ux-not-native-shape.md +21 -0
- kpubdata-0.1.0/docs/architecture-diagrams.md +496 -0
- kpubdata-0.1.0/docs/datago-api-reference.md +220 -0
- kpubdata-0.1.0/docs/product-family-architecture.md +369 -0
- kpubdata-0.1.0/docs/providers/bok.md +207 -0
- kpubdata-0.1.0/docs/providers/datago.md +393 -0
- kpubdata-0.1.0/docs/providers/kosis.md +216 -0
- kpubdata-0.1.0/docs/quickstart.md +152 -0
- kpubdata-0.1.0/docs/tutorial-ai-agent-workflow.md +490 -0
- kpubdata-0.1.0/pyproject.toml +80 -0
- kpubdata-0.1.0/src/kpubdata/__init__.py +52 -0
- kpubdata-0.1.0/src/kpubdata/catalog.py +101 -0
- kpubdata-0.1.0/src/kpubdata/client.py +179 -0
- kpubdata-0.1.0/src/kpubdata/config.py +119 -0
- kpubdata-0.1.0/src/kpubdata/core/__init__.py +25 -0
- kpubdata-0.1.0/src/kpubdata/core/capability.py +56 -0
- kpubdata-0.1.0/src/kpubdata/core/dataset.py +153 -0
- kpubdata-0.1.0/src/kpubdata/core/models.py +156 -0
- kpubdata-0.1.0/src/kpubdata/core/protocol.py +60 -0
- kpubdata-0.1.0/src/kpubdata/core/representation.py +19 -0
- kpubdata-0.1.0/src/kpubdata/exceptions.py +116 -0
- kpubdata-0.1.0/src/kpubdata/providers/__init__.py +5 -0
- kpubdata-0.1.0/src/kpubdata/providers/_common.py +204 -0
- kpubdata-0.1.0/src/kpubdata/providers/bok/__init__.py +7 -0
- kpubdata-0.1.0/src/kpubdata/providers/bok/adapter.py +333 -0
- kpubdata-0.1.0/src/kpubdata/providers/bok/catalogue.json +25 -0
- kpubdata-0.1.0/src/kpubdata/providers/datago/__init__.py +7 -0
- kpubdata-0.1.0/src/kpubdata/providers/datago/adapter.py +313 -0
- kpubdata-0.1.0/src/kpubdata/providers/datago/catalogue.json +92 -0
- kpubdata-0.1.0/src/kpubdata/providers/kosis/__init__.py +7 -0
- kpubdata-0.1.0/src/kpubdata/providers/kosis/adapter.py +254 -0
- kpubdata-0.1.0/src/kpubdata/providers/kosis/catalogue.json +26 -0
- kpubdata-0.1.0/src/kpubdata/providers/lofin/__init__.py +7 -0
- kpubdata-0.1.0/src/kpubdata/providers/lofin/adapter.py +329 -0
- kpubdata-0.1.0/src/kpubdata/providers/lofin/catalogue.json +127 -0
- kpubdata-0.1.0/src/kpubdata/py.typed +0 -0
- kpubdata-0.1.0/src/kpubdata/registry.py +135 -0
- kpubdata-0.1.0/src/kpubdata/transport/__init__.py +16 -0
- kpubdata-0.1.0/src/kpubdata/transport/decode.py +74 -0
- kpubdata-0.1.0/src/kpubdata/transport/http.py +380 -0
- kpubdata-0.1.0/src/kpubdata/transport/retry.py +68 -0
- kpubdata-0.1.0/tests/__init__.py +0 -0
- kpubdata-0.1.0/tests/contract/__init__.py +0 -0
- kpubdata-0.1.0/tests/contract/provider_adapter.py +81 -0
- kpubdata-0.1.0/tests/contract/test_bok.py +100 -0
- kpubdata-0.1.0/tests/contract/test_datago.py +81 -0
- kpubdata-0.1.0/tests/contract/test_kosis.py +102 -0
- kpubdata-0.1.0/tests/contract/test_lofin.py +137 -0
- kpubdata-0.1.0/tests/fixtures/bok/error_auth.json +6 -0
- kpubdata-0.1.0/tests/fixtures/bok/success_empty.json +6 -0
- kpubdata-0.1.0/tests/fixtures/bok/success_single_page.json +34 -0
- kpubdata-0.1.0/tests/fixtures/datago/error_auth_30.json +9 -0
- kpubdata-0.1.0/tests/fixtures/datago/error_invalid_request_10.json +9 -0
- kpubdata-0.1.0/tests/fixtures/datago/error_rate_limit_22.json +9 -0
- kpubdata-0.1.0/tests/fixtures/datago/error_service_unavailable_01.json +9 -0
- kpubdata-0.1.0/tests/fixtures/datago/error_xml_auth_30.xml +8 -0
- kpubdata-0.1.0/tests/fixtures/datago/success_apt_trade.json +43 -0
- kpubdata-0.1.0/tests/fixtures/datago/success_empty.json +14 -0
- kpubdata-0.1.0/tests/fixtures/datago/success_multi_page_1.json +25 -0
- kpubdata-0.1.0/tests/fixtures/datago/success_multi_page_2.json +21 -0
- kpubdata-0.1.0/tests/fixtures/datago/success_single_item.json +19 -0
- kpubdata-0.1.0/tests/fixtures/datago/success_single_page.json +35 -0
- kpubdata-0.1.0/tests/fixtures/datago/success_string_numerics.json +21 -0
- kpubdata-0.1.0/tests/fixtures/datago/success_xml.xml +22 -0
- kpubdata-0.1.0/tests/fixtures/datago/success_xml_single_item.xml +18 -0
- kpubdata-0.1.0/tests/fixtures/kosis/error_auth.json +4 -0
- kpubdata-0.1.0/tests/fixtures/kosis/success_empty.json +1 -0
- kpubdata-0.1.0/tests/fixtures/kosis/success_single_page.json +5 -0
- kpubdata-0.1.0/tests/fixtures/lofin/error_auth.json +8 -0
- kpubdata-0.1.0/tests/fixtures/lofin/success_single_page.json +50 -0
- kpubdata-0.1.0/tests/integration/__init__.py +0 -0
- kpubdata-0.1.0/tests/integration/conftest.py +54 -0
- kpubdata-0.1.0/tests/integration/test_bok_live.py +219 -0
- kpubdata-0.1.0/tests/integration/test_client_flow.py +198 -0
- kpubdata-0.1.0/tests/integration/test_datago_live.py +74 -0
- kpubdata-0.1.0/tests/integration/test_exception_propagation.py +229 -0
- kpubdata-0.1.0/tests/integration/test_kosis_live.py +236 -0
- kpubdata-0.1.0/tests/integration/test_lofin_live.py +199 -0
- kpubdata-0.1.0/tests/integration/test_transport_http.py +265 -0
- kpubdata-0.1.0/tests/unit/__init__.py +0 -0
- kpubdata-0.1.0/tests/unit/core/__init__.py +0 -0
- kpubdata-0.1.0/tests/unit/core/test_dataset.py +139 -0
- kpubdata-0.1.0/tests/unit/core/test_dataset_coverage.py +47 -0
- kpubdata-0.1.0/tests/unit/core/test_exceptions.py +88 -0
- kpubdata-0.1.0/tests/unit/core/test_exceptions_coverage.py +9 -0
- kpubdata-0.1.0/tests/unit/core/test_models.py +135 -0
- kpubdata-0.1.0/tests/unit/core/test_models_fixtures.py +236 -0
- kpubdata-0.1.0/tests/unit/providers/__init__.py +0 -0
- kpubdata-0.1.0/tests/unit/providers/datago/__init__.py +0 -0
- kpubdata-0.1.0/tests/unit/providers/datago/conftest.py +70 -0
- kpubdata-0.1.0/tests/unit/providers/datago/test_adapter.py +480 -0
- kpubdata-0.1.0/tests/unit/providers/datago/test_adapter_coverage.py +333 -0
- kpubdata-0.1.0/tests/unit/providers/datago/test_fixtures.py +137 -0
- kpubdata-0.1.0/tests/unit/test_catalog.py +137 -0
- kpubdata-0.1.0/tests/unit/test_catalog_coverage.py +49 -0
- kpubdata-0.1.0/tests/unit/test_catalogue_validation.py +113 -0
- kpubdata-0.1.0/tests/unit/test_client_coverage.py +121 -0
- kpubdata-0.1.0/tests/unit/test_client_transport_requirements.py +134 -0
- kpubdata-0.1.0/tests/unit/test_config.py +56 -0
- kpubdata-0.1.0/tests/unit/test_config_coverage.py +41 -0
- kpubdata-0.1.0/tests/unit/test_registry.py +83 -0
- kpubdata-0.1.0/tests/unit/test_registry_coverage.py +109 -0
- kpubdata-0.1.0/tests/unit/transport/__init__.py +0 -0
- kpubdata-0.1.0/tests/unit/transport/test_decode.py +90 -0
- kpubdata-0.1.0/tests/unit/transport/test_decode_coverage.py +22 -0
- kpubdata-0.1.0/tests/unit/transport/test_http_coverage.py +92 -0
- kpubdata-0.1.0/tests/unit/transport/test_http_coverage_extra.py +50 -0
- kpubdata-0.1.0/tests/unit/transport/test_logging.py +122 -0
- kpubdata-0.1.0/tests/unit/transport/test_retry.py +54 -0
- kpubdata-0.1.0/tests/unit/transport/test_retry_after.py +126 -0
- kpubdata-0.1.0/tests/unit/transport/test_retry_coverage.py +21 -0
- kpubdata-0.1.0/tests/unit/transport/test_transport_requirements.py +73 -0
- kpubdata-0.1.0/uv.lock +1518 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
name: New Provider Adapter
|
|
2
|
+
description: Propose or track a new Korean public data provider adapter
|
|
3
|
+
title: "[Provider] "
|
|
4
|
+
labels: ["type:feature"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
## New Provider Adapter Request
|
|
10
|
+
|
|
11
|
+
Use this template to propose adding a new Korean public data provider.
|
|
12
|
+
|
|
13
|
+
- type: input
|
|
14
|
+
id: provider-name
|
|
15
|
+
attributes:
|
|
16
|
+
label: Provider Name
|
|
17
|
+
description: The official name of the data provider (Korean and English)
|
|
18
|
+
placeholder: "e.g., 서울열린데이터광장 (Seoul Open Data)"
|
|
19
|
+
validations:
|
|
20
|
+
required: true
|
|
21
|
+
|
|
22
|
+
- type: input
|
|
23
|
+
id: base-url
|
|
24
|
+
attributes:
|
|
25
|
+
label: API Base URL
|
|
26
|
+
description: The base URL for the provider's API
|
|
27
|
+
placeholder: "e.g., http://openapi.seoul.go.kr:8088"
|
|
28
|
+
validations:
|
|
29
|
+
required: true
|
|
30
|
+
|
|
31
|
+
- type: dropdown
|
|
32
|
+
id: auth-type
|
|
33
|
+
attributes:
|
|
34
|
+
label: Authentication Type
|
|
35
|
+
options:
|
|
36
|
+
- API Key (query parameter)
|
|
37
|
+
- API Key (header)
|
|
38
|
+
- OAuth 2.0
|
|
39
|
+
- No auth
|
|
40
|
+
- Other (describe below)
|
|
41
|
+
validations:
|
|
42
|
+
required: true
|
|
43
|
+
|
|
44
|
+
- type: dropdown
|
|
45
|
+
id: response-format
|
|
46
|
+
attributes:
|
|
47
|
+
label: Response Format
|
|
48
|
+
multiple: true
|
|
49
|
+
options:
|
|
50
|
+
- JSON
|
|
51
|
+
- XML
|
|
52
|
+
- CSV
|
|
53
|
+
- Excel
|
|
54
|
+
- Other
|
|
55
|
+
validations:
|
|
56
|
+
required: true
|
|
57
|
+
|
|
58
|
+
- type: textarea
|
|
59
|
+
id: datasets
|
|
60
|
+
attributes:
|
|
61
|
+
label: Key Datasets
|
|
62
|
+
description: List the most important datasets this provider offers
|
|
63
|
+
placeholder: |
|
|
64
|
+
- 서울시 실시간 대기환경 (Real-time air quality)
|
|
65
|
+
- 서울시 공공자전거 대여소 (Public bike stations)
|
|
66
|
+
validations:
|
|
67
|
+
required: true
|
|
68
|
+
|
|
69
|
+
- type: textarea
|
|
70
|
+
id: api-docs
|
|
71
|
+
attributes:
|
|
72
|
+
label: API Documentation Links
|
|
73
|
+
description: Links to official API documentation
|
|
74
|
+
placeholder: "https://..."
|
|
75
|
+
validations:
|
|
76
|
+
required: true
|
|
77
|
+
|
|
78
|
+
- type: textarea
|
|
79
|
+
id: notes
|
|
80
|
+
attributes:
|
|
81
|
+
label: Additional Notes
|
|
82
|
+
description: Any quirks, rate limits, or special considerations
|
|
83
|
+
placeholder: |
|
|
84
|
+
- Rate limit: 1000 calls/day
|
|
85
|
+
- Requires registration at data.go.kr
|
|
86
|
+
- Some endpoints return EUC-KR encoding
|
|
87
|
+
validations:
|
|
88
|
+
required: false
|
|
89
|
+
|
|
90
|
+
- type: checkboxes
|
|
91
|
+
id: checklist
|
|
92
|
+
attributes:
|
|
93
|
+
label: Implementation Checklist
|
|
94
|
+
description: Track progress (maintainer use)
|
|
95
|
+
options:
|
|
96
|
+
- label: "API research and documentation"
|
|
97
|
+
- label: "Adapter class with `name` property"
|
|
98
|
+
- label: "`list_datasets()` implementation"
|
|
99
|
+
- label: "`query_records()` with pagination"
|
|
100
|
+
- label: "`get_schema()` implementation"
|
|
101
|
+
- label: "`call_raw()` escape hatch"
|
|
102
|
+
- label: "Fixture responses captured"
|
|
103
|
+
- label: "Unit tests with fixtures"
|
|
104
|
+
- label: "Contract tests passing"
|
|
105
|
+
- label: "Capabilities documented honestly"
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
quality:
|
|
18
|
+
name: Lint & Type Check
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
timeout-minutes: 10
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- uses: astral-sh/setup-uv@v4
|
|
25
|
+
with:
|
|
26
|
+
enable-cache: true
|
|
27
|
+
cache-dependency-glob: "uv.lock"
|
|
28
|
+
|
|
29
|
+
- uses: actions/setup-python@v5
|
|
30
|
+
with:
|
|
31
|
+
python-version: "3.12"
|
|
32
|
+
|
|
33
|
+
- name: Install dependencies
|
|
34
|
+
run: uv sync --frozen --extra dev
|
|
35
|
+
|
|
36
|
+
- name: Ruff check
|
|
37
|
+
run: uv run ruff check .
|
|
38
|
+
|
|
39
|
+
- name: Ruff format check
|
|
40
|
+
run: uv run ruff format --check .
|
|
41
|
+
|
|
42
|
+
- name: Mypy
|
|
43
|
+
run: uv run mypy src
|
|
44
|
+
|
|
45
|
+
test:
|
|
46
|
+
name: Test (Python ${{ matrix.python-version }})
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
timeout-minutes: 15
|
|
49
|
+
strategy:
|
|
50
|
+
fail-fast: false
|
|
51
|
+
matrix:
|
|
52
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v4
|
|
55
|
+
|
|
56
|
+
- uses: astral-sh/setup-uv@v4
|
|
57
|
+
with:
|
|
58
|
+
enable-cache: true
|
|
59
|
+
cache-dependency-glob: "uv.lock"
|
|
60
|
+
|
|
61
|
+
- uses: actions/setup-python@v5
|
|
62
|
+
with:
|
|
63
|
+
python-version: ${{ matrix.python-version }}
|
|
64
|
+
|
|
65
|
+
- name: Install dependencies
|
|
66
|
+
run: uv sync --frozen --extra dev
|
|
67
|
+
|
|
68
|
+
- name: Run tests
|
|
69
|
+
run: uv run pytest -ra
|
|
70
|
+
|
|
71
|
+
build:
|
|
72
|
+
name: Build Package
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
timeout-minutes: 10
|
|
75
|
+
needs: [quality, test]
|
|
76
|
+
steps:
|
|
77
|
+
- uses: actions/checkout@v4
|
|
78
|
+
|
|
79
|
+
- uses: astral-sh/setup-uv@v4
|
|
80
|
+
with:
|
|
81
|
+
enable-cache: true
|
|
82
|
+
cache-dependency-glob: "uv.lock"
|
|
83
|
+
|
|
84
|
+
- uses: actions/setup-python@v5
|
|
85
|
+
with:
|
|
86
|
+
python-version: "3.12"
|
|
87
|
+
|
|
88
|
+
- name: Install dependencies
|
|
89
|
+
run: uv sync --frozen --extra dev
|
|
90
|
+
|
|
91
|
+
- name: Build sdist and wheel
|
|
92
|
+
run: uv run python -m build
|
|
93
|
+
|
|
94
|
+
- name: Upload artifacts
|
|
95
|
+
uses: actions/upload-artifact@v4
|
|
96
|
+
with:
|
|
97
|
+
name: dist
|
|
98
|
+
path: dist/
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Integration Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
provider:
|
|
7
|
+
description: 'Provider to test'
|
|
8
|
+
required: true
|
|
9
|
+
default: 'all'
|
|
10
|
+
type: choice
|
|
11
|
+
options:
|
|
12
|
+
- all
|
|
13
|
+
- datago
|
|
14
|
+
- bok
|
|
15
|
+
- kosis
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
integration:
|
|
22
|
+
name: Integration Tests (${{ github.event.inputs.provider }})
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
timeout-minutes: 15
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
|
|
28
|
+
- uses: astral-sh/setup-uv@v4
|
|
29
|
+
with:
|
|
30
|
+
enable-cache: true
|
|
31
|
+
cache-dependency-glob: "uv.lock"
|
|
32
|
+
|
|
33
|
+
- uses: actions/setup-python@v5
|
|
34
|
+
with:
|
|
35
|
+
python-version: "3.12"
|
|
36
|
+
|
|
37
|
+
- name: Install dependencies
|
|
38
|
+
run: uv sync --frozen --extra dev
|
|
39
|
+
|
|
40
|
+
- name: Run integration tests
|
|
41
|
+
env:
|
|
42
|
+
KPUBDATA_DATAGO_API_KEY: ${{ secrets.KPUBDATA_DATAGO_API_KEY }}
|
|
43
|
+
KPUBDATA_BOK_API_KEY: ${{ secrets.KPUBDATA_BOK_API_KEY }}
|
|
44
|
+
KPUBDATA_KOSIS_API_KEY: ${{ secrets.KPUBDATA_KOSIS_API_KEY }}
|
|
45
|
+
run: |
|
|
46
|
+
if [ "${{ github.event.inputs.provider }}" = "all" ]; then
|
|
47
|
+
uv run pytest -m integration -ra -v
|
|
48
|
+
else
|
|
49
|
+
uv run pytest -m integration -ra -v -k "${{ github.event.inputs.provider }}"
|
|
50
|
+
fi
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
id-token: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
name: Build Package
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
timeout-minutes: 10
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- uses: astral-sh/setup-uv@v4
|
|
20
|
+
with:
|
|
21
|
+
enable-cache: true
|
|
22
|
+
cache-dependency-glob: "uv.lock"
|
|
23
|
+
|
|
24
|
+
- uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.12"
|
|
27
|
+
|
|
28
|
+
- name: Install dependencies
|
|
29
|
+
run: uv sync --frozen --extra dev
|
|
30
|
+
|
|
31
|
+
- name: Run quality gates
|
|
32
|
+
run: |
|
|
33
|
+
uv run ruff check .
|
|
34
|
+
uv run ruff format --check .
|
|
35
|
+
uv run mypy src
|
|
36
|
+
uv run pytest -ra
|
|
37
|
+
|
|
38
|
+
- name: Build sdist and wheel
|
|
39
|
+
run: uv run python -m build
|
|
40
|
+
|
|
41
|
+
- name: Upload artifacts
|
|
42
|
+
uses: actions/upload-artifact@v4
|
|
43
|
+
with:
|
|
44
|
+
name: dist
|
|
45
|
+
path: dist/
|
|
46
|
+
|
|
47
|
+
publish:
|
|
48
|
+
name: Publish to PyPI
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
needs: build
|
|
51
|
+
environment: pypi
|
|
52
|
+
steps:
|
|
53
|
+
- name: Download artifacts
|
|
54
|
+
uses: actions/download-artifact@v4
|
|
55
|
+
with:
|
|
56
|
+
name: dist
|
|
57
|
+
path: dist/
|
|
58
|
+
|
|
59
|
+
- name: Publish to PyPI
|
|
60
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
*.egg-info/
|
|
7
|
+
*.egg
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
.eggs/
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# IDE
|
|
18
|
+
.idea/
|
|
19
|
+
.vscode/
|
|
20
|
+
*.swp
|
|
21
|
+
*.swo
|
|
22
|
+
*~
|
|
23
|
+
|
|
24
|
+
# Testing / Coverage
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
.coverage
|
|
27
|
+
htmlcov/
|
|
28
|
+
.mypy_cache/
|
|
29
|
+
.ruff_cache/
|
|
30
|
+
|
|
31
|
+
# OS
|
|
32
|
+
.DS_Store
|
|
33
|
+
Thumbs.db
|
|
34
|
+
|
|
35
|
+
# Environment
|
|
36
|
+
.env
|
|
37
|
+
.env.local
|
kpubdata-0.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
This repository is built for agentic coding and Codex-heavy development.
|
|
6
|
+
|
|
7
|
+
The project is a Python 3.10+ framework with a small stable public API and provider-specific adapters.
|
|
8
|
+
|
|
9
|
+
## Read these first
|
|
10
|
+
|
|
11
|
+
1. `VALIDATION.md`
|
|
12
|
+
2. `PRD.md`
|
|
13
|
+
3. `ARCHITECTURE.md`
|
|
14
|
+
4. `CANONICAL_MODEL.md`
|
|
15
|
+
5. `PROVIDER_ADAPTER_CONTRACT.md`
|
|
16
|
+
6. `API_SPEC.md`
|
|
17
|
+
7. `PACKAGING.md`
|
|
18
|
+
|
|
19
|
+
## Rules of engagement
|
|
20
|
+
|
|
21
|
+
- Keep the public API small.
|
|
22
|
+
- Do not turn provider quirks into fake universal semantics.
|
|
23
|
+
- Do not remove raw escape hatches.
|
|
24
|
+
- Do not mark a capability as supported unless tests prove it.
|
|
25
|
+
- Keep provider complexity in provider adapters.
|
|
26
|
+
- Update tests and docs with every behavior change.
|
|
27
|
+
- `SUPPORTED_DATA.md`는 지원 Provider/Dataset 현황의 단일 기준 문서(single source of truth)다.
|
|
28
|
+
- Provider/Dataset의 지원 상태 또는 검증 수준이 바뀌면, 같은 PR에서 `SUPPORTED_DATA.md`를 반드시 업데이트한다.
|
|
29
|
+
- `지원`은 fixture/unit/contract 테스트가 통과했을 때만 표시한다.
|
|
30
|
+
- `실API 검증`은 실 API integration 테스트가 존재하고 통과했을 때만 표시한다. 그 전에는 `테스트 검증`으로 유지한다.
|
|
31
|
+
|
|
32
|
+
## Language policy
|
|
33
|
+
|
|
34
|
+
- **Documentation**: Write in Korean by default. English expansion is planned for future releases.
|
|
35
|
+
- **Code**: All code (variable names, function names, comments, docstrings) must be in English.
|
|
36
|
+
- **Commit messages**: Always in English.
|
|
37
|
+
- **Issue / PR titles and descriptions**: Korean is acceptable; English is also fine.
|
|
38
|
+
|
|
39
|
+
## Branch rules
|
|
40
|
+
|
|
41
|
+
- Default branch is `main`. **Never push directly to `main`.**
|
|
42
|
+
- Always work on a feature branch and open a PR.
|
|
43
|
+
- Branch naming: `feat/issue-<number>-<short-description>`, `fix/issue-<number>-<short-description>`, `docs/<short-description>`
|
|
44
|
+
- Never force-push to `main`. Never delete `main`.
|
|
45
|
+
- Never rename or delete branches you did not create.
|
|
46
|
+
- If unsure about any git operation, **ask first — do not guess.**
|
|
47
|
+
|
|
48
|
+
## When to write a plan
|
|
49
|
+
|
|
50
|
+
Before multi-file or architecture-affecting work, create or update a task plan in a local plan file.
|
|
51
|
+
|
|
52
|
+
The plan should include:
|
|
53
|
+
|
|
54
|
+
- scope
|
|
55
|
+
- touched modules
|
|
56
|
+
- risks
|
|
57
|
+
- validation steps
|
|
58
|
+
|
|
59
|
+
## Quality gates
|
|
60
|
+
|
|
61
|
+
Run before marking work complete:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
uv sync --extra dev
|
|
65
|
+
uv run ruff check .
|
|
66
|
+
uv run ruff format --check .
|
|
67
|
+
uv run mypy src
|
|
68
|
+
uv run pytest
|
|
69
|
+
uv run python -m build
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Adapter work rules
|
|
73
|
+
|
|
74
|
+
When adding a provider adapter:
|
|
75
|
+
|
|
76
|
+
- add fixture responses
|
|
77
|
+
- add unit tests
|
|
78
|
+
- add contract tests
|
|
79
|
+
- document capabilities honestly
|
|
80
|
+
- keep `call_raw` working
|
|
81
|
+
|
|
82
|
+
## Public API change rule
|
|
83
|
+
|
|
84
|
+
If a public method, public model, or canonical exception changes:
|
|
85
|
+
|
|
86
|
+
- update `API_SPEC.md`
|
|
87
|
+
- update `PRD.md` if requirements changed
|
|
88
|
+
- add release note/changelog entry
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 이 프로젝트 이해하기
|
|
93
|
+
|
|
94
|
+
KPubData는 한국 공공데이터(data.go.kr 등)라는 거대한 도서관에서 책을 찾아주는 **똑똑한 사서**와 같습니다. 도서관마다 책을 분류하는 방식이 제각각이지만, 사서는 여러분에게 항상 동일한 방식으로 책을 찾아다 줍니다.
|
|
95
|
+
|
|
96
|
+
### 핵심 개념 용어 사전
|
|
97
|
+
|
|
98
|
+
| 용어 | 설명 |
|
|
99
|
+
| :--- | :--- |
|
|
100
|
+
| **Provider** | 데이터를 제공하는 기관 (예: 공공데이터포털, 기상청 등) |
|
|
101
|
+
| **Adapter** | 각 기관의 서로 다른 API 규칙을 KPubData 표준에 맞게 변환해주는 통역사 |
|
|
102
|
+
| **Dataset** | 실제 데이터의 집합 (예: 동네예보, 대기오염정보 등) |
|
|
103
|
+
| **Query** | 데이터를 찾기 위해 던지는 질문 (검색 조건) |
|
|
104
|
+
| **RecordBatch** | 검색 결과로 돌아온 데이터 뭉치 |
|
|
105
|
+
| **Canonical Model** | 기관마다 다른 데이터 형식을 하나로 통일한 표준 모델 |
|
|
106
|
+
| **Raw Escape Hatch** | 표준화된 방식 대신 원본 API를 그대로 쓰고 싶을 때 사용하는 비상구 (`call_raw`) |
|
|
107
|
+
|
|
108
|
+
### 이 프로젝트의 코드가 실행되는 흐름
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
[User] -> [Client] -> [Dataset] -> [Adapter] -> [Transport] -> [Public Data API]
|
|
112
|
+
^ |
|
|
113
|
+
| v
|
|
114
|
+
[User] <- [RecordBatch] <----------- [Parser] <--- [Raw Response]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```mermaid
|
|
118
|
+
sequenceDiagram
|
|
119
|
+
participant U as 사용자 (User)
|
|
120
|
+
participant C as 클라이언트 (Client)
|
|
121
|
+
participant Cat as 카탈로그 (Catalog)
|
|
122
|
+
participant A as 어댑터 (Adapter)
|
|
123
|
+
participant T as 전송 계층 (Transport)
|
|
124
|
+
participant P as 공공 API (Public API)
|
|
125
|
+
|
|
126
|
+
U->>C: 데이터셋 요청
|
|
127
|
+
C->>Cat: 데이터셋 검색/확인
|
|
128
|
+
Cat-->>C: 데이터셋 객체 반환
|
|
129
|
+
U->>C: 데이터 조회 (list/get)
|
|
130
|
+
C->>A: 요청 위임
|
|
131
|
+
A->>T: HTTP 요청
|
|
132
|
+
T->>P: 실제 데이터 요청
|
|
133
|
+
P-->>T: 원본 데이터 응답
|
|
134
|
+
T-->>A: 파싱된 데이터 전달
|
|
135
|
+
A-->>U: RecordBatch 반환
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## AI 에이전트 코딩 가이드
|
|
139
|
+
|
|
140
|
+
에이전트(Copilot, Cursor 등)를 사용하여 개발할 때 다음 규칙을 준수하세요.
|
|
141
|
+
|
|
142
|
+
### 좋은 프롬프트 예시
|
|
143
|
+
- "`datago` 어댑터에 새로운 `Dataset`인 `air_quality`를 추가해줘. `PROVIDER_ADAPTER_CONTRACT.md`를 참고해서 구현하고, `tests/fixtures`에 응답 샘플도 추가해."
|
|
144
|
+
- "`RecordBatch` 모델에 `to_pandas()` 메서드를 추가하고 관련 유닛 테스트를 작성해줘."
|
|
145
|
+
|
|
146
|
+
### 에이전트 금지 사항
|
|
147
|
+
- **Any 타입 남발 금지**: `typing.Any`를 사용하지 말고 명확한 타입을 정의하세요.
|
|
148
|
+
- **type: ignore 금지**: 타입 오류를 해결하지 않고 무시하지 마세요.
|
|
149
|
+
- **테스트 코드 삭제 금지**: 기존 테스트를 지우지 마세요.
|
|
150
|
+
- **Fake universal semantics 금지**: 특정 기관에만 있는 기능을 모든 기관이 지원하는 것처럼 속이지 마세요.
|
|
151
|
+
|
|
152
|
+
### 에이전트 결과물 검증 체크리스트
|
|
153
|
+
- [ ] `mypy` 검사를 통과했는가?
|
|
154
|
+
- [ ] `pytest`가 모두 성공하는가?
|
|
155
|
+
- [ ] `src/` 외부의 파일을 수정하지 않았는가?
|
|
156
|
+
- [ ] `API_SPEC.md`에 정의되지 않은 public 메서드를 추가하지 않았는가?
|
|
157
|
+
|
|
158
|
+
## 파일 구조 가이드
|
|
159
|
+
|
|
160
|
+
```text
|
|
161
|
+
src/kpubdata/
|
|
162
|
+
├── core/ # 핵심 비즈니스 로직 및 추상 클래스
|
|
163
|
+
├── transport/ # HTTP 통신 처리
|
|
164
|
+
├── providers/ # 데이터 제공 기관 정의
|
|
165
|
+
├── adapters/ # 기관별 데이터 변환 로직 (가장 자주 수정하게 될 곳)
|
|
166
|
+
├── client.py # 사용자가 처음 만나는 입구
|
|
167
|
+
├── catalog.py # 사용 가능한 데이터셋 목록 관리
|
|
168
|
+
└── exceptions.py # 공통 에러 정의
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
```mermaid
|
|
172
|
+
graph TD
|
|
173
|
+
root[src/kpubdata/] --> core[core/]
|
|
174
|
+
root --> transport[transport/]
|
|
175
|
+
root --> providers[providers/]
|
|
176
|
+
root --> adapters[adapters/]
|
|
177
|
+
root --> client[client.py]
|
|
178
|
+
root --> catalog[catalog.py]
|
|
179
|
+
root --> exceptions[exceptions.py]
|
|
180
|
+
|
|
181
|
+
core --> core_desc[핵심 비즈니스 로직]
|
|
182
|
+
transport --> transport_desc[HTTP 통신 처리]
|
|
183
|
+
providers --> providers_desc[기관 정의]
|
|
184
|
+
adapters --> adapters_desc[데이터 변환 로직]
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 이 파일을 수정해야 할 때
|
|
188
|
+
- **새로운 데이터 기관을 추가하고 싶을 때**: `adapters/`에 새 디렉토리를 만들고 `core/`의 추상 클래스를 구현합니다.
|
|
189
|
+
- **데이터 조회 방식을 개선하고 싶을 때**: `core/query.py`나 `core/record.py`를 수정합니다.
|
|
190
|
+
|
|
191
|
+
## 어댑터 개발 가이드
|
|
192
|
+
|
|
193
|
+
### 개발 시작부터 완료까지 체크리스트
|
|
194
|
+
1. [ ] 원본 API의 응답 예시(XML/JSON)를 `tests/fixtures/<provider>/<dataset>.json`에 저장
|
|
195
|
+
2. [ ] `ProviderAdapter` 추상 클래스를 상속받아 클래스 생성
|
|
196
|
+
3. [ ] `list()`, `get()` 등 필요한 동작 구현
|
|
197
|
+
4. [ ] `capabilities` 속성에 지원하는 기능 명시
|
|
198
|
+
5. [ ] `call_raw`가 항상 원본 데이터를 반환하도록 보장
|
|
199
|
+
6. [ ] `tests/unit/adapters/`에 유닛 테스트 추가
|
|
200
|
+
7. [ ] `tests/contract/`에 계약 테스트(Contract Test) 추가
|
|
201
|
+
8. [ ] `SUPPORTED_DATA.md` 업데이트 (`상태`, `검증`, `인증`, `공식 문서`, `비고`)
|
|
202
|
+
|
|
203
|
+
```mermaid
|
|
204
|
+
flowchart TD
|
|
205
|
+
Start[시작] --> F1[1. 원본 API 응답 Fixture 저장]
|
|
206
|
+
F1 --> F2[2. ProviderAdapter 상속 클래스 생성]
|
|
207
|
+
F2 --> F3[3. list/get 등 핵심 동작 구현]
|
|
208
|
+
F3 --> F4[4. capabilities 기능 명시]
|
|
209
|
+
F4 --> F5[5. call_raw 보장]
|
|
210
|
+
F5 --> F6[6. 유닛 테스트 추가]
|
|
211
|
+
F6 --> F7[7. 계약 테스트 통과 확인]
|
|
212
|
+
F7 --> F8[8. SUPPORTED_DATA.md 업데이트]
|
|
213
|
+
F8 --> End[완료]
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 핵심 추상 클래스 설명
|
|
217
|
+
- **ProviderAdapter**: 모든 어댑터의 부모입니다. 인증, 요청 생성, 응답 파싱을 담당합니다.
|
|
218
|
+
- **DatasetRef**: 특정 데이터셋을 가리키는 주소 정보입니다.
|
|
219
|
+
- **Query**: 데이터 필터링 조건을 담는 객체입니다.
|
|
220
|
+
- **RecordBatch**: 표준화된 데이터 레코드들의 묶음입니다.
|
|
221
|
+
|
|
222
|
+
### 테스트 작성 가이드
|
|
223
|
+
- **Fixture 기반 테스트**: 가짜 서버를 띄우는 대신, 미리 저장해둔 응답 파일(`fixture`)을 사용하여 어댑터가 올바르게 파싱하는지 확인합니다.
|
|
224
|
+
- **Contract 테스트**: 어댑터가 KPubData의 표준 규약(Contract)을 잘 지키고 있는지 확인하는 테스트입니다. 모든 어댑터는 동일한 인터페이스를 통과해야 합니다.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## 관련 문서
|
|
229
|
+
|
|
230
|
+
### 이 저장소 내 문서
|
|
231
|
+
| 문서 | 설명 |
|
|
232
|
+
| :--- | :--- |
|
|
233
|
+
| [CONTRIBUTING.md](./CONTRIBUTING.md) | 프로젝트 기여 가이드 |
|
|
234
|
+
| [ARCHITECTURE.md](./ARCHITECTURE.md) | 시스템 아키텍처 설계 |
|
|
235
|
+
| [PROVIDER_ADAPTER_CONTRACT.md](./PROVIDER_ADAPTER_CONTRACT.md) | 어댑터 구현 규약 |
|
|
236
|
+
| [CANONICAL_MODEL.md](./CANONICAL_MODEL.md) | 표준 데이터 모델 정의 |
|
|
237
|
+
| [VALIDATION.md](./VALIDATION.md) | 아키텍처 타당성 검증 |
|
|
238
|
+
| [API_SPEC.md](./API_SPEC.md) | 파이썬 API 명세 |
|
|
239
|
+
| [PRD.md](./PRD.md) | 제품 요구사항 정의 |
|
|
240
|
+
| [PACKAGING.md](./PACKAGING.md) | 패키징 및 배포 전략 |
|
|
241
|
+
| [SUPPORTED_DATA.md](./SUPPORTED_DATA.md) | 지원 공공데이터 현황 및 진행 상태 |
|
|
242
|
+
|
|
243
|
+
### KPubData Product Family
|
|
244
|
+
| 저장소 | 문서 | 설명 |
|
|
245
|
+
| :--- | :--- | :--- |
|
|
246
|
+
| [kpubdata-builder](https://github.com/yeongseon/kpubdata-builder) | [AGENTS.md](https://github.com/yeongseon/kpubdata-builder/blob/main/AGENTS.md) | Builder 에이전트 가이드 |
|
|
247
|
+
| [kpubdata-studio](https://github.com/yeongseon/kpubdata-studio) | [AGENTS.md](https://github.com/yeongseon/kpubdata-studio/blob/main/AGENTS.md) | Studio 에이전트 가이드 |
|