pydconfig 1.0.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.
- pydconfig-1.0.0/.github/workflows/compatibility.yml +54 -0
- pydconfig-1.0.0/.gitignore +221 -0
- pydconfig-1.0.0/.python-version +1 -0
- pydconfig-1.0.0/.worknotes/compatibility-plan.md +56 -0
- pydconfig-1.0.0/.worknotes/configuration-library-design.md +18 -0
- pydconfig-1.0.0/.worknotes/instruction-audit.md +17 -0
- pydconfig-1.0.0/.worknotes/package-rename.md +19 -0
- pydconfig-1.0.0/.worknotes/product-plan.md +147 -0
- pydconfig-1.0.0/.worknotes/release-plan.md +49 -0
- pydconfig-1.0.0/.worknotes/reviews/design-review.md +68 -0
- pydconfig-1.0.0/.worknotes/reviews/implementation-review.md +26 -0
- pydconfig-1.0.0/.worknotes/reviews/initial-proposal.md +503 -0
- pydconfig-1.0.0/.worknotes/reviews/planning-review.md +32 -0
- pydconfig-1.0.0/.worknotes/technical-design.md +413 -0
- pydconfig-1.0.0/PKG-INFO +133 -0
- pydconfig-1.0.0/README.md +102 -0
- pydconfig-1.0.0/docs/configuration-reference.md +205 -0
- pydconfig-1.0.0/docs/development.md +119 -0
- pydconfig-1.0.0/docs/integration-guide.md +141 -0
- pydconfig-1.0.0/docs/user-guide.md +292 -0
- pydconfig-1.0.0/examples/basic/.env.example +2 -0
- pydconfig-1.0.0/examples/basic/.env.local.example +2 -0
- pydconfig-1.0.0/examples/basic/.gitignore +2 -0
- pydconfig-1.0.0/examples/basic/README.md +27 -0
- pydconfig-1.0.0/examples/basic/app.py +52 -0
- pydconfig-1.0.0/examples/basic/config.local.yaml +4 -0
- pydconfig-1.0.0/examples/basic/config.yaml +9 -0
- pydconfig-1.0.0/pyproject.toml +63 -0
- pydconfig-1.0.0/requirements/compatibility.txt +5 -0
- pydconfig-1.0.0/scripts/check_compatibility.py +156 -0
- pydconfig-1.0.0/scripts/check_distribution.py +68 -0
- pydconfig-1.0.0/src/pydconfig/__init__.py +35 -0
- pydconfig-1.0.0/src/pydconfig/binding.py +87 -0
- pydconfig-1.0.0/src/pydconfig/bootstrap.py +47 -0
- pydconfig-1.0.0/src/pydconfig/defaults.py +89 -0
- pydconfig-1.0.0/src/pydconfig/errors.py +88 -0
- pydconfig-1.0.0/src/pydconfig/lexical.py +242 -0
- pydconfig-1.0.0/src/pydconfig/loader.py +115 -0
- pydconfig-1.0.0/src/pydconfig/model.py +27 -0
- pydconfig-1.0.0/src/pydconfig/nodes.py +176 -0
- pydconfig-1.0.0/src/pydconfig/pipeline.py +200 -0
- pydconfig-1.0.0/src/pydconfig/provenance.py +37 -0
- pydconfig-1.0.0/src/pydconfig/py.typed +0 -0
- pydconfig-1.0.0/src/pydconfig/schema.py +214 -0
- pydconfig-1.0.0/src/pydconfig/settings.py +138 -0
- pydconfig-1.0.0/src/pydconfig/snapshot.py +87 -0
- pydconfig-1.0.0/src/pydconfig/sources.py +202 -0
- pydconfig-1.0.0/tests/conftest.py +34 -0
- pydconfig-1.0.0/tests/test_binding_and_quoting.py +222 -0
- pydconfig-1.0.0/tests/test_review_regressions.py +77 -0
- pydconfig-1.0.0/tests/test_schema_and_defaults.py +249 -0
- pydconfig-1.0.0/tests/test_snapshot_and_diagnostics.py +228 -0
- pydconfig-1.0.0/tests/test_sources_and_profiles.py +253 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
name: Package compatibility
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
package:
|
|
13
|
+
name: Python ${{ matrix.python }} / ${{ matrix.os }}
|
|
14
|
+
runs-on: ${{ matrix.os }}
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
os: [ubuntu-latest]
|
|
19
|
+
python: ["3.10", "3.11", "3.12", "3.13", "3.14.7"]
|
|
20
|
+
include:
|
|
21
|
+
- os: macos-latest
|
|
22
|
+
python: "3.14.7"
|
|
23
|
+
- os: windows-latest
|
|
24
|
+
python: "3.14.7"
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v7.0.1
|
|
27
|
+
- uses: actions/setup-python@v7.0.0
|
|
28
|
+
with:
|
|
29
|
+
python-version: ${{ matrix.python }}
|
|
30
|
+
cache: pip
|
|
31
|
+
cache-dependency-path: |
|
|
32
|
+
requirements/compatibility.txt
|
|
33
|
+
pyproject.toml
|
|
34
|
+
- name: Install the compatibility baseline
|
|
35
|
+
run: python -m pip install -r requirements/compatibility.txt build
|
|
36
|
+
- name: Build wheel from sdist
|
|
37
|
+
run: python -m build
|
|
38
|
+
- name: Install the built package and verification tools
|
|
39
|
+
run: python -m pip install "dist/pydconfig-1.0.0-py3-none-any.whl[dev]"
|
|
40
|
+
- name: Check package metadata
|
|
41
|
+
run: python -m twine check dist/*
|
|
42
|
+
- name: Check dependencies
|
|
43
|
+
run: python -m pip check
|
|
44
|
+
- name: Check upstream settings APIs
|
|
45
|
+
run: python scripts/check_compatibility.py
|
|
46
|
+
- name: Run contracts against the installed wheel
|
|
47
|
+
timeout-minutes: 3
|
|
48
|
+
run: python -m pytest -q -o faulthandler_timeout=30
|
|
49
|
+
- name: Check installed package and file example
|
|
50
|
+
run: python scripts/check_distribution.py
|
|
51
|
+
- name: Type check public implementation
|
|
52
|
+
run: python -m mypy
|
|
53
|
+
- name: Check formatting and imports
|
|
54
|
+
run: python -m ruff check src tests scripts examples/basic/app.py
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
# Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
# poetry.lock
|
|
109
|
+
# poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
# pdm.lock
|
|
116
|
+
# pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
# pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# Redis
|
|
135
|
+
*.rdb
|
|
136
|
+
*.aof
|
|
137
|
+
*.pid
|
|
138
|
+
|
|
139
|
+
# RabbitMQ
|
|
140
|
+
mnesia/
|
|
141
|
+
rabbitmq/
|
|
142
|
+
rabbitmq-data/
|
|
143
|
+
|
|
144
|
+
# ActiveMQ
|
|
145
|
+
activemq-data/
|
|
146
|
+
|
|
147
|
+
# SageMath parsed files
|
|
148
|
+
*.sage.py
|
|
149
|
+
|
|
150
|
+
# Environments
|
|
151
|
+
.env
|
|
152
|
+
.env.*
|
|
153
|
+
!.env.example
|
|
154
|
+
!.env.*.example
|
|
155
|
+
.envrc
|
|
156
|
+
.venv
|
|
157
|
+
env/
|
|
158
|
+
venv/
|
|
159
|
+
ENV/
|
|
160
|
+
env.bak/
|
|
161
|
+
venv.bak/
|
|
162
|
+
|
|
163
|
+
# Spyder project settings
|
|
164
|
+
.spyderproject
|
|
165
|
+
.spyproject
|
|
166
|
+
|
|
167
|
+
# Rope project settings
|
|
168
|
+
.ropeproject
|
|
169
|
+
|
|
170
|
+
# mkdocs documentation
|
|
171
|
+
/site
|
|
172
|
+
|
|
173
|
+
# mypy
|
|
174
|
+
.mypy_cache/
|
|
175
|
+
.dmypy.json
|
|
176
|
+
dmypy.json
|
|
177
|
+
|
|
178
|
+
# Pyre type checker
|
|
179
|
+
.pyre/
|
|
180
|
+
|
|
181
|
+
# pytype static type analyzer
|
|
182
|
+
.pytype/
|
|
183
|
+
|
|
184
|
+
# Cython debug symbols
|
|
185
|
+
cython_debug/
|
|
186
|
+
|
|
187
|
+
# PyCharm
|
|
188
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
189
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
190
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
191
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
192
|
+
# .idea/
|
|
193
|
+
|
|
194
|
+
# Abstra
|
|
195
|
+
# Abstra is an AI-powered process automation framework.
|
|
196
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
197
|
+
# Learn more at https://abstra.io/docs
|
|
198
|
+
.abstra/
|
|
199
|
+
|
|
200
|
+
# Visual Studio Code
|
|
201
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
202
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
203
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
204
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
205
|
+
# .vscode/
|
|
206
|
+
# Temporary file for partial code execution
|
|
207
|
+
tempCodeRunnerFile.py
|
|
208
|
+
|
|
209
|
+
# Ruff stuff:
|
|
210
|
+
.ruff_cache/
|
|
211
|
+
|
|
212
|
+
# PyPI configuration file
|
|
213
|
+
.pypirc
|
|
214
|
+
|
|
215
|
+
# Marimo
|
|
216
|
+
marimo/_static/
|
|
217
|
+
marimo/_lsp/
|
|
218
|
+
__marimo__/
|
|
219
|
+
|
|
220
|
+
# Streamlit
|
|
221
|
+
.streamlit/secrets.toml
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14.7
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Python 호환성 기준
|
|
2
|
+
|
|
3
|
+
확인일: 2026-09-26. 지원 목표는 표준 CPython 3.10–3.14다. 라이브러리는 pydantic·pydantic-settings·python-dotenv를 필수 기반으로 사용하며 YAML 파싱에는 PyYAML을 사용한다.
|
|
4
|
+
|
|
5
|
+
## 버전과 지원 목표
|
|
6
|
+
|
|
7
|
+
| 대상 | 기준 | 근거와 범위 |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| Python 개발 기준 | 3.14.7 | [공식 릴리스](https://www.python.org/downloads/release/python-3147/). 확인일 기준 최신 안정 버전이다. |
|
|
10
|
+
| Python 지원 목표 | 표준 CPython 3.10–3.14 | Ubuntu에서 다섯 minor, macOS·Windows에서 3.14.7을 기반 probe CI 대상으로 둔다. |
|
|
11
|
+
| 제외한 실행 환경 | pre-release·free-threaded·PyPy | 이번 실행·지원 판정에 포함하지 않는다. |
|
|
12
|
+
|
|
13
|
+
지원 범위는 사용자가 지정한 Python 3.10–3.14다. `.python-version`은 개발 기준인 3.14.7로 고정한다. 실제 pydconfig 전체 계약 시험과 패키징 gate를 통과한 뒤 라이브러리 지원으로 선언한다.
|
|
14
|
+
|
|
15
|
+
## 의존성 baseline
|
|
16
|
+
|
|
17
|
+
| 라이브러리 | 확인한 버전 | 역할 |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| pydantic | 2.13.5 | 모델·필드 검증·공개 model_fields/model_rebuild/create_model |
|
|
20
|
+
| pydantic-settings | 2.15.0 | BaseSettings·custom source·source debug |
|
|
21
|
+
| python-dotenv | 1.2.3 | interpolate=False 파일 파싱 |
|
|
22
|
+
| PyYAML | 6.0.3 | YAML reader 기반 |
|
|
23
|
+
|
|
24
|
+
확인한 버전의 Python Requires-Python과 3.14 classifier를 PyPI metadata에서 확인하고 고정 버전 설치를 수행했다. metadata만으로 실제 라이브러리 호환성을 승인하지 않는다. [Pydantic](https://pypi.org/project/pydantic/2.13.5/), [Pydantic Settings](https://pypi.org/project/pydantic-settings/2.15.0/), [python-dotenv](https://pypi.org/project/python-dotenv/1.2.3/), [PyYAML](https://pypi.org/project/PyYAML/6.0.3/)
|
|
25
|
+
|
|
26
|
+
## 실행 가능한 검사
|
|
27
|
+
|
|
28
|
+
[scripts/check_compatibility.py](../scripts/check_compatibility.py)는 구현 전 단계에서 다음을 검사한다.
|
|
29
|
+
|
|
30
|
+
- forward reference를 public model_rebuild로 완성하고 model_fields의 annotation을 읽는다. [Python 3.14 annotation 변경](https://docs.python.org/3.14/whatsnew/3.14.html#pep-649-and-pep-749-deferred-evaluation-of-annotations)에 대응하는 기반 확인이다.
|
|
31
|
+
- 실제 BaseSettings/custom source, required aggregate field의 빈 DefaultSettingsSource, input deep copy와 2→4의 독립 재검증을 확인한다.
|
|
32
|
+
- Settings debug를 활성화하고 source의 값 없는 repr이 secret sentinel을 로그에 넣지 않는지 확인한다. 시험 fixture가 debug를 켜는 것이며 제품이 debug를 끄거나 OS/logger를 변경해 값을 숨기는 구현이 아니다.
|
|
33
|
+
- Pydantic native boolean 대소문자 처리와 python-dotenv의 syntax quote·실제 quote·literal 보간·공백 보존을 확인한다. pydconfig의 quote 처리 구현은 아직 없다.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
python -m pip install -r requirements/compatibility.txt
|
|
37
|
+
python scripts/check_compatibility.py
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 이전 실행 기록
|
|
41
|
+
|
|
42
|
+
- macOS arm64 / CPython 3.14.4와 3.13.13에서 고정 의존성 설치와 기반 probe를 통과했다. 시스템 Python을 교체하지 않고 임시 venv를 사용했다.
|
|
43
|
+
- Linux arm64 / 공식 Python 3.10.21-slim과 3.14.7-slim 컨테이너에서 같은 기반 probe를 통과했다.
|
|
44
|
+
- Ubuntu CPython 3.10·3.11·3.12·3.13·3.14.7과 macOS·Windows 3.14.7의 7개 CI job이 모두 통과했다. 검증 code commit은 `bd23d4b03d70acd9375cd4814c7fee446925b53f`이며 [실행 결과](https://github.com/pydemia/pydconfig/actions/runs/36237714964)를 completed/success로 확인했다. 이는 이번 변경 전 기록이다.
|
|
45
|
+
- 전체 pydconfig 구현·wheel/sdist·G1–G11은 아직 수행할 구현 단계 작업이다. 최초 리뷰 원본과 v2/v3의 승인 기록은 보존한다.
|
|
46
|
+
|
|
47
|
+
## 이번 변경의 실행 기록
|
|
48
|
+
|
|
49
|
+
- macOS CPython 3.14.4·3.13.13에서 수정한 probe를 통과했다.
|
|
50
|
+
- Python 설정 API만 대상으로 정리한 code commit `0370734a007cf16a711a20f91474dd07945fea92`의 [CI](https://github.com/pydemia/pydconfig/actions/runs/36239341897)가 completed/success다.
|
|
51
|
+
- Ubuntu의 Python 3.10·3.11·3.12·3.13·3.14.7, macOS·Windows 3.14.7의 7개 job을 각각 completed/success로 확인했다.
|
|
52
|
+
- 이 결과는 기반 API 호환성 판정이다. ConfigLoader 구현·smart quote·전체 G1–G11·wheel 설치는 아직 검증되지 않았다.
|
|
53
|
+
|
|
54
|
+
## v1.0.0 구현 검증
|
|
55
|
+
|
|
56
|
+
위 기록은 probe-only 준비 단계의 결과다. 실제 src/pydconfig 구현과 pytest 계약 시험, mypy, sdist→wheel build·설치·예제 검증을 추가했다. 동일한 7개 Python/OS 조합의 새 CI 결과는 [release 기록](release-plan.md)에 귀속한다. 지원 범위 밖 Python 구현·버전은 이 결과로 보장하지 않는다.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# pydconfig 문서 안내
|
|
2
|
+
|
|
3
|
+
기존 통합 제안서를 리뷰한 뒤 기획서와 상세 설계서로 분리했다. 초기 문서 리뷰를 보존하고 v1.0.0의 구현·시험·배포 기록을 별도로 연결한다.
|
|
4
|
+
|
|
5
|
+
| 문서 | 내용 |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| [기획서](product-plan.md) | 요구사항 R1–R14, 사용자 경험, MVP·후속 범위, 이관과 완료 기준 |
|
|
8
|
+
| [상세 설계서](technical-design.md) | API, 내부 데이터, 실행 순서, source·default·검증·snapshot의 동작 계약 |
|
|
9
|
+
| [기획 리뷰](reviews/planning-review.md) | 독립 기획 리뷰의 지적, 반영, 재검토 결과 |
|
|
10
|
+
| [설계 리뷰](reviews/design-review.md) | 구조·설정 규칙 리뷰의 지적, 반영, 재검토 결과 |
|
|
11
|
+
| [패키지 이름 변경](package-rename.md) | 배포명·import·저장소·실제 디렉터리 변경과 Codex 경로 전환 완료 |
|
|
12
|
+
| [호환성 기준](compatibility-plan.md) | Python 3.10–3.14, 의존성 baseline, 실행 가능한 기반 probe와 검증 한계 |
|
|
13
|
+
| [사용자 가이드](../docs/user-guide.md) | 기본 파일 예제, 이름·경로, 프로파일·환경변수·snapshot 사용 계약 |
|
|
14
|
+
| [설정 규칙](../docs/configuration-reference.md) | API 옵션, 파싱·병합·boolean·quote·오류 reference |
|
|
15
|
+
| [애플리케이션 연동](../docs/integration-guide.md) | 생성자 주입·FastAPI·테스트 격리·이관 |
|
|
16
|
+
| [개발 가이드](../docs/development.md) | 기반 probe·CI, 구현 후 build·설치·release 절차 |
|
|
17
|
+
| [Release 작업 기록](release-plan.md) | v1.0.0 요청, 배포 범위 확인, 문서·branch·검증 준비 상태 |
|
|
18
|
+
| [최초 제안 원본](reviews/initial-proposal.md) | 첫 리뷰의 고정 baseline; 이름 변경 전 표기를 포함하며 현재 설계와 다를 수 있음 |
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# 작업 문서 위치와 지침 적용 확인
|
|
2
|
+
|
|
3
|
+
확인일: 2026-09-26. 이 기록은 pydconfig 기획·설계·리뷰 문서의 저장 위치를 바로잡은 근거다.
|
|
4
|
+
|
|
5
|
+
## 확인한 사실
|
|
6
|
+
|
|
7
|
+
- 최초 문서는 `docs/`에 작성됐다. 당시 세션에 제공된 지침과 저장소·상위 디렉터리·개인 Codex AGENTS에는 `.worknotes` 규칙이 없었다.
|
|
8
|
+
- 세션에 사용 가능한 스킬 목록에는 `software-engineering`, `persona-cross-review`가 없었다. 실제 사용한 로컬 스킬은 `evidence-based-code-review`였다.
|
|
9
|
+
- [skills.pydemia.ai](https://skills.pydemia.ai)의 공개 Skills 26개와 Prompts 27개 상세 페이지를 모두 조회했고 표시된 본문에서 `worknotes` 문자열이 발견되지 않았다. 조회 실패는 없었다. 해당 Hub의 표시 source revision은 `2465d7c4d843`였다.
|
|
10
|
+
- 관련 [개발 지침](https://skills.pydemia.ai/skills/software-engineering), [persona 리뷰 지침](https://skills.pydemia.ai/skills/persona-cross-review), [문서 작성 지침](https://skills.pydemia.ai/skills/document-writing-workflow)에도 저장 경로를 `.worknotes`로 지정하는 규칙은 없었다.
|
|
11
|
+
- 사이트가 링크한 GitHub 원본은 현재 인증 환경에서 HTTP 404로 조회되지 않았다. 공개 발행본과 최신 canonical 원본의 일치 여부는 확인하지 못했다. 로컬 agent-skills checkout은 `9317322`로 Hub revision과 달랐다.
|
|
12
|
+
|
|
13
|
+
## 수정
|
|
14
|
+
|
|
15
|
+
사용자의 `.worknotes` 저장 위치 지시를 현재 작업의 기준으로 적용했다. 기획서·상세 설계서·리뷰 보고서·최초 제안·문서 안내의 여섯 파일을 `.worknotes/`로 이동하고 README 링크를 변경했다. 이동 전후 파일 SHA-256이 같음을 확인했으며 최초 리뷰 baseline hash도 유지했다.
|
|
16
|
+
|
|
17
|
+
기획·설계의 내용과 최종 리뷰 판정은 이동으로 바꾸지 않았다. 관련 스킬을 설치하거나 사이트·canonical 지침을 변경한 것은 아니다. 공개 발행본에 없는 규칙을 읽고 적용했다고 소급 기록하지 않는다.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# 패키지·저장소 이름 변경
|
|
2
|
+
|
|
3
|
+
변경일: 2026-09-26. 사용자가 공개 패키지 이름을 `pydconfig`로 선택하고 저장소·디렉터리 이름 변경을 요청했다.
|
|
4
|
+
|
|
5
|
+
| 대상 | 변경 결과 |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| PyPI 배포명 / Python import | `pydconfig` / `pydconfig` |
|
|
8
|
+
| GitHub 저장소 | https://github.com/pydemia/pydconfig |
|
|
9
|
+
| Git origin | GitHub의 `pydemia/pydconfig` 경로로 변경 |
|
|
10
|
+
| 로컬 실제 디렉터리 | `/Users/a09255/git/pydconfig` |
|
|
11
|
+
| 구현 예정 경로 | `src/pydconfig/` |
|
|
12
|
+
| 기본 환경변수 / 프로파일 선택 | `PYDCONFIG_` / `PYDCONFIG_PROFILE` |
|
|
13
|
+
| 내부 source 클래스 | `PydConfigSource` |
|
|
14
|
+
|
|
15
|
+
GitHub 저장소 ID 1388674507과 로컬 HEAD `34765006f3426251edf077c20bdc9580f860a1e5`를 유지했다. 로컬 디렉터리 이동 전후의 파일 hash가 같고 기존 미커밋 변경이 보존됐다. 패키지 구현 파일이나 pyproject.toml은 아직 없으므로 현재 설계의 import·패키지 경로와 이름을 변경한 상태다. PyPI 업로드는 수행하지 않았다.
|
|
16
|
+
|
|
17
|
+
최초 이름 변경 당시 Codex에 등록된 프로젝트는 기존 경로를 참조했다. 해당 앱 조작은 도구의 안전 제한으로 차단되어 `/Users/a09255/git/pydemia-config`에 새 디렉터리를 가리키는 호환 심볼릭 링크를 남겼다. 이후 사용자가 새 폴더를 작업공간에 추가했다. 현재 작업 디렉터리와 Codex 등록 경로가 모두 `/Users/a09255/git/pydconfig`인 것을 확인하고 호환 링크를 제거했다.
|
|
18
|
+
|
|
19
|
+
최초 리뷰 원본 [initial-proposal.md](reviews/initial-proposal.md)는 당시 이름과 SHA-256 `662877e0cac8f8aeb59d669bfa033bcbf3caa8a20d917a2bdf734552db779ab5`를 보존한다. 그 외 현 기획·설계·리뷰 설명의 패키지 이름은 새 이름으로 맞췄다.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# pydconfig 기획서
|
|
2
|
+
|
|
3
|
+
상태: v1.0.0 구현 반영안 v6. 작성일: 2026-09-26. 사용자 지정 기반은 pydantic·pydantic-settings·python-dotenv다. 라이브러리 API는 src/pydconfig에 구현했다. 검증·배포 증거는 release-plan.md에 기록한다. 동작 계약과 내부 구조는 [상세 설계서](technical-design.md)에 정의한다. 최초 통합 문서는 [리뷰 기준 원본](reviews/initial-proposal.md)으로 보존했다.
|
|
4
|
+
|
|
5
|
+
## 해결할 문제와 사용 대상
|
|
6
|
+
|
|
7
|
+
현재 서비스마다 YAML 로딩, 환경변수 치환, 설정 클래스 분리, 기본값 병합을 반복 구현한다. 같은 설정이 코드·YAML·환경변수에 있으면 실제 적용값을 판단하기 어렵고 import 시점의 전역 객체 때문에 앱·테스트별 설정을 분리하기 어렵다.
|
|
8
|
+
|
|
9
|
+
Python 애플리케이션이 이름별 설정을 타입으로 선언하고, 환경별 값을 일관된 순서로 적용한 객체를 주입받도록 한다. 최초 대상은 FastAPI 서비스와 배치·CLI다. 웹 프레임워크 없이도 같은 설정을 사용할 수 있어야 한다.
|
|
10
|
+
|
|
11
|
+
## 패키지와 저장소 이름
|
|
12
|
+
|
|
13
|
+
| 항목 | 이름 또는 경로 |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| PyPI 배포명 / Python import | `pydconfig` / `pydconfig` |
|
|
16
|
+
| GitHub 저장소 | `pydemia/pydconfig` |
|
|
17
|
+
| 로컬 프로젝트 | `/Users/a09255/git/pydconfig` |
|
|
18
|
+
| 구현 패키지 경로 | `src/pydconfig/` |
|
|
19
|
+
| 기본 환경변수 / 프로파일 변수 | `PYDCONFIG_` / `PYDCONFIG_PROFILE` |
|
|
20
|
+
|
|
21
|
+
개인 계정명은 패키지명에 포함하지 않는다. 패키지 구현 경로는 src/pydconfig이며 wheel·sdist metadata의 배포명도 pydconfig다. 최초 리뷰 원본의 이전 이름은 당시 검토 근거로 보존한다.
|
|
22
|
+
|
|
23
|
+
## 요구사항과 인수 기준
|
|
24
|
+
|
|
25
|
+
| ID | 요구사항 | 인수 기준 |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| R1 | name별 설정과 nested 구조 | 같은 타입을 `primary_db`, `replica_db`로 등록해 서로 다른 경로의 값을 조회한다. 이름 또는 등록 경로 충돌은 명시적 오류다. |
|
|
28
|
+
| R2 | env가 코드 기본값과 YAML을 override | YAML에 placeholder가 없어도 `MYAPP_DATABASE__POOL__SIZE=20`이 nested 값을 변경한다. |
|
|
29
|
+
| R3 | YAML의 `${ENVVAR}` | YAML 구조를 파싱한 뒤 값만 치환한다. unset·빈 값·fallback·escape가 문서 규칙과 일치한다. |
|
|
30
|
+
| R4 | `.env`와 `.env.<profile>` | 두 파일을 누적 적용하고 실제 프로세스 환경변수가 같은 변수의 값을 이긴다. `.env.local`은 local 프로파일에서만 읽는다. |
|
|
31
|
+
| R5 | 최상단 profile | 기본 YAML의 `profile`을 사용한다. 외부 선택값이 우선하며 profile 전용 파일은 선택을 다시 바꾸지 않는다. |
|
|
32
|
+
| R6 | 검증된 설정 주입 | 시작 시 모든 등록 모델을 검증한다. 소비자는 name과 타입을 지정해 객체를 받으며 부분 성공 snapshot은 없다. |
|
|
33
|
+
| R7 | 값의 출처 확인 | `explain(path)`에서 정의 source와 placeholder 참조 source를 구분한다. 원문 값을 출력하지 않는다. |
|
|
34
|
+
| R8 | 독립적인 실행·테스트 | import와 load가 `os.environ`을 수정하지 않는다. 서로 다른 root/profile/environ으로 만든 snapshot은 공유 상태가 없다. |
|
|
35
|
+
| R9 | 설정 변경 | 원본 snapshot을 보존하고 새 override를 재검증한다. 파일·환경의 재로딩은 명시적으로 요청한다. |
|
|
36
|
+
| R10 | 지정 기반 라이브러리 | pydantic·pydantic-settings·python-dotenv를 필수 사용한다. 실제 BaseSettings/custom source 실행과 dotenv 파싱을 확인한다. |
|
|
37
|
+
| R11 | 환경 설정 데이터에 한정한 타입 지원 | `arbitrary_types_allowed=False`를 유지한다. 임의 객체 필드·설정에 주입할 클라이언트 인스턴스·이를 허용하는 subclass는 등록에서 거부한다. |
|
|
38
|
+
| R12 | boolean 대소문자 처리 | `True/False`, `true/false`, `TRUE/FALSE`, 혼합 대소문자를 같은 boolean으로 읽는다. 실제 quote가 남은 환경 입력도 명시된 정규화 규칙으로 처리하며 알 수 없는 token은 오류다. |
|
|
39
|
+
| R13 | 환경 입력의 quote 처리 | bool·숫자·복합 JSON은 짝이 맞는 바깥 quote 한 겹을 제거한다. 문자열은 기본 보존하고 필드별 `env_quote_policy`로 제거를 선택한다. 내부 quote·escape·replay 입력을 반복 변환하지 않는다. |
|
|
40
|
+
| R14 | Python 3.10–3.14와 호환 | 표준 CPython 3.10–3.14를 대상으로 개발 기준 Python 3.14.7과 기반 의존성의 공개 API·파서 동작을 검증한다. 기반 probe와 실제 pydconfig 계약·배포 패키지 시험 결과를 구분한다. |
|
|
41
|
+
|
|
42
|
+
## MVP 범위와 확장 순서
|
|
43
|
+
|
|
44
|
+
MVP는 `ConfigLoader`, `ConfigModel`, `ConfigSnapshot`의 세 API를 중심으로 한다. 이름 등록, 단일 profile, 기본·profile YAML, dotenv 누적 로딩, nested env 바인딩, YAML 보간, 타입 검증, 독립 snapshot, 값 없는 출처 진단을 지원하며 R10의 기반 라이브러리를 사용한다. 환경 입력의 boolean과 quote 처리는 R12·R13에 따른다.
|
|
45
|
+
|
|
46
|
+
필수 기반은 **pydantic v2, pydantic-settings v2, python-dotenv**다. pydantic은 모델·타입 검증, pydantic-settings는 BaseSettings와 사용자 정의 설정 소스 실행, python-dotenv는 dotenv 파일 파싱을 담당한다. name registry·profile bootstrap·provenance는 이 기반 위에서 구현한다. 세부 schema 지원 범위는 설계서에 고정한다. 표준 CPython 3.10–3.14를 지원 목표로 두고 개발 기준은 최신 안정 Python 3.14.7로 고정한다. Python 3.15 pre-release와 free-threaded/PyPy 지원은 이번 검증 범위에 포함하지 않는다. 미지원 타입은 register 시 거부한다. 버전 확인 근거와 실행 범위는 [호환성 기준](compatibility-plan.md)에 기록한다.
|
|
47
|
+
|
|
48
|
+
| 시점 | 범위 | 완료 기준 |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| 계약 prototype | BaseSettings custom source, source 충돌, nested default, 보간, snapshot 재검증 | 필수 세 라이브러리의 공개 확장 API로 계약을 구현할 수 있음을 확인한다. 불가능한 계약은 문서를 먼저 변경한다. |
|
|
51
|
+
| MVP | R1–R14, 문서·최소 예제·배포 패키지 | 설계서의 계약 시험 통과, clean install 후 예제 실행, import 부작용 없음 |
|
|
52
|
+
| 첫 서비스 적용 | template-backend의 작은 설정 영역 | 비민감 fixture로 기존 동작과 차이를 비교하고 이관·복구 절차를 확인한다. |
|
|
53
|
+
| 사용성 확장 | FastAPI adapter, alias, explicit multi-YAML, schema export | 필요한 호환 입력과 adapter의 앱별 격리를 검증한다. |
|
|
54
|
+
| 운영 확장 | 명시적 secret directory, custom sources, 검증 CLI | 추가 source의 순서·실패 정책을 공개하고 기존 기본 순서를 유지한다. |
|
|
55
|
+
|
|
56
|
+
임의 Python 객체 타입 지원은 제품 범위에 포함하지 않는다. 설정을 읽어 애플리케이션에 주입하는 라이브러리이므로 DB client·logger·service 객체는 검증된 설정을 받은 application bootstrap에서 생성한다. `arbitrary_types_allowed=True`를 활성화하는 호환 모드도 제공하지 않는다.
|
|
57
|
+
|
|
58
|
+
초기 버전에서 범용 DI 컨테이너, 자동 서비스 탐색, 자동 reload, 원격 설정 서버, 복수 활성 profile, YAML include·표현식 실행은 제공하지 않는다. dotenv는 파일 형식 파싱만 사용하며 **dotenv 내부 변수 보간은 후속 기능**으로 둔다. `${...}` 보간의 MVP 적용 대상은 YAML 값이다. 이는 원래 사용자 요구를 충족하면서 별도 dotenv 참조 엔진의 구현 비용을 제한한 선택이다.
|
|
59
|
+
|
|
60
|
+
## 사용 경험
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from pathlib import Path
|
|
64
|
+
from pydantic import Field, SecretStr
|
|
65
|
+
from pydconfig import ConfigLoader, ConfigModel
|
|
66
|
+
|
|
67
|
+
class PoolConfig(ConfigModel):
|
|
68
|
+
size: int = Field(default=10, ge=1)
|
|
69
|
+
|
|
70
|
+
class DatabaseConfig(ConfigModel):
|
|
71
|
+
host: str = "localhost"
|
|
72
|
+
password: SecretStr
|
|
73
|
+
pool: PoolConfig = Field(default_factory=PoolConfig)
|
|
74
|
+
|
|
75
|
+
loader = ConfigLoader(root_dir=Path.cwd(), env_prefix="MYAPP_")
|
|
76
|
+
loader.register("database", DatabaseConfig)
|
|
77
|
+
settings = loader.load()
|
|
78
|
+
database = settings.get("database", DatabaseConfig)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```yaml
|
|
82
|
+
# config.yaml
|
|
83
|
+
profile: local
|
|
84
|
+
database:
|
|
85
|
+
host: "${DB_HOST:-localhost}"
|
|
86
|
+
password: "${DB_PASSWORD}"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```dotenv
|
|
90
|
+
# .env
|
|
91
|
+
DB_PASSWORD=example-only
|
|
92
|
+
MYAPP_DATABASE__POOL__SIZE=5
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```dotenv
|
|
96
|
+
# .env.local
|
|
97
|
+
DB_HOST=127.0.0.1
|
|
98
|
+
MYAPP_DATABASE__POOL__SIZE=3
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
위 입력에서 profile은 local, host는 127.0.0.1, pool.size는 3이다. OS의 `MYAPP_DATABASE__POOL__SIZE=20`이 있으면 size는 20이 된다. 생성자 주입에서는 이 객체를 그대로 인자로 전달한다. Spring의 `@Value`에 대응하는 자동 decorator 주입은 MVP 사용 경험에 포함하지 않는다.
|
|
102
|
+
|
|
103
|
+
boolean 필드는 `False`, `false`, `FALSE`, 실제 quote를 포함한 `"False"`를 모두 False로 읽는다. 문자열 필드는 대소문자·공백·quote를 자동 변경하지 않는다. 배포 도구가 host 문자열에 quote까지 주입하는 환경은 `ConfigLoader(..., env_quote_policy={"database.host": "unwrap"})`로 해당 경로만 한 겹 제거한다. 비밀번호에 quote가 실제로 필요한 경우에는 보존한다. shell이나 dotenv의 문법상 quote와 ENVVAR에 저장된 quote 문자는 구분한다.
|
|
104
|
+
|
|
105
|
+
## 우선순위와 프로파일 정책
|
|
106
|
+
|
|
107
|
+
설정 필드의 우선순위는 낮은 순서부터 다음과 같다.
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
모델 기본값 < 기본 YAML < profile YAML < .env 바인딩
|
|
111
|
+
< .env.<profile> 바인딩 < OS env 바인딩 < 명시적 overrides
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
profile 선택은 `load(profile=...) > OS PYDCONFIG_PROFILE > 기본 .env의 PYDCONFIG_PROFILE > 기본 YAML profile > 미선택`이다. 미선택 시 기본 파일만 읽는다. 실제 환경변수명과 설정 경로의 우선순위는 구분한다. `${DB_HOST}`는 YAML 값의 참조이며 `.env`의 직접 필드 변수 `MYAPP_DATABASE__HOST`가 그 YAML 값을 덮으면 OS의 `DB_HOST`가 있어도 직접 필드 값이 유지된다.
|
|
115
|
+
|
|
116
|
+
프로파일 YAML이 없다는 이유만으로 선택한 profile이 유효하다고 판단하지 않는다. 배포에서 `allowed_profiles=("local", "test", "stg", "prd")`를 지정해 오타를 거부한다. profile YAML 존재가 필요하면 `require_profile_yaml=True`를 사용한다. 설정이 환경변수만으로 완성되는 앱에는 파일 존재를 강제하지 않는다.
|
|
117
|
+
|
|
118
|
+
## Reference와 구현 선택
|
|
119
|
+
|
|
120
|
+
| Reference | 채택 내용 | 적용 범위 |
|
|
121
|
+
| --- | --- | --- |
|
|
122
|
+
| [Spring Boot](https://docs.spring.io/spring-boot/reference/features/external-config.html) | 소스 우선순위·구조화된 바인딩·시작 시 검증 | 사용 모델을 참고하며 전체 Spring 표기법 호환을 약속하지 않는다. |
|
|
123
|
+
| [Pydantic Settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) | BaseSettings·custom settings source | 필수 구현 기반. 단일 aggregate settings에서 사용자 정의 소스를 실행한다. |
|
|
124
|
+
| [Dynaconf](https://www.dynaconf.com/merging/) | 명시적 병합 정책 | MVP는 mapping 재귀 병합·list 교체로 제한한다. |
|
|
125
|
+
| [OmegaConf](https://omegaconf.readthedocs.io/en/latest/usage.html) | 계층형 설정·보간 | YAML 변수 보간만 채택하고 설정 간 참조는 후속 기능으로 둔다. |
|
|
126
|
+
| [python-dotenv](https://bbc2.github.io/python-dotenv/) | 환경을 수정하지 않는 파일 파싱 | `dotenv_values(interpolate=False)`를 사용한다. |
|
|
127
|
+
|
|
128
|
+
이미 있는 라이브러리 위에 필요한 차이만 추가한다. loader는 registry와 실행 컨텍스트를 만들고 pydantic-settings의 custom source가 bootstrap·병합·보간을 수행한다. 최종 검증도 실제 BaseSettings 생성에서 수행한다. 모델마다 별도 BaseSettings를 만들어 기본 env/dotenv 소스와 중복 로딩하지 않는다. Pydantic Settings를 선택 의존성이나 비교 후보로 두는 이전 제안은 사용자 지정에 따라 폐기했다.
|
|
129
|
+
|
|
130
|
+
## 기존 코드 이관과 호환성
|
|
131
|
+
|
|
132
|
+
기존 구현의 근거는 [최초 제안의 근거 표](reviews/initial-proposal.md#기존-구현에서-이어받을-부분)에 보존했다. 정적 소스 관찰이며 서비스 실행 검증은 아니다.
|
|
133
|
+
|
|
134
|
+
- `_root_key`를 name/path 등록으로 옮기고 `config:` wrapper는 명시적 호환 변환에서 제거한다.
|
|
135
|
+
- `env_prefix=""`는 경로와 정확히 일치하는 기존 변수만 보존한다. `JWT__SSO_AUTHCODE_URL`과 `sso_url_authcode`처럼 불일치하는 이름은 application bootstrap에서 명시적으로 mapping한다. alias adapter 출시 전 core가 추측하지 않는다.
|
|
136
|
+
- `DEFAULT_CONFIG`와 `APP_CONFIG` 두 파일의 병합은 explicit multi-YAML 기능 도입 후 이관한다. MVP만으로 기존 shared 로더 전체를 대체할 수 있다고 보지 않는다.
|
|
137
|
+
- 기존 validator는 순수 검증·변환만 옮긴다. 로거 변경, 클라이언트 생성 등 외부 상태 변경은 snapshot 성공 후 application bootstrap에서 실행한다.
|
|
138
|
+
- `unknown="ignore"`는 일부 영역의 단계적 이관에만 사용하고 무시한 경로를 보고한다. 등록하지 않은 영역의 placeholder는 평가하지 않는다.
|
|
139
|
+
- dotenv 누적 로딩, 미정의 placeholder 오류, strict key 검사, null·list 계약의 차이를 fixture로 확인한다.
|
|
140
|
+
|
|
141
|
+
이관 중에는 기존 로더와 새 로더를 독립적으로 실행해 비민감 설정만 비교한다. 사용 서비스에서 새 로더를 선택하는 bootstrap 변경을 되돌리는 것이 복구 방법이며 라이브러리가 원래 dotenv나 YAML을 수정하지 않는다.
|
|
142
|
+
|
|
143
|
+
## 완료와 검토의 의미
|
|
144
|
+
|
|
145
|
+
문서 리뷰 완료는 구현·호환성 검증 완료와 구분한다. MVP 완료는 R1–R14에 연결된 계약 시험, 플랫폼별 경로·환경 처리, wheel/sdist 설치, 타입 검사, 예제 실행 결과로 판단한다. 성능 수치는 측정 후 기록하며 현재 기획 단계에서 목표 처리시간을 임의로 약속하지 않는다.
|
|
146
|
+
|
|
147
|
+
리뷰의 지적·반영·재검토 결과는 [기획 리뷰](reviews/planning-review.md)와 [설계 리뷰](reviews/design-review.md)에 기록한다.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# v1.0.0 release 작업 기록
|
|
2
|
+
|
|
3
|
+
요청: build·push, release branch, v1.0.0 tag, GitHub Release에 wheel 첨부, 충분한 README·guide 작성. 날짜: 2026-09-26.
|
|
4
|
+
|
|
5
|
+
## 범위 정정
|
|
6
|
+
|
|
7
|
+
사용자 정정에 따라 Kubernetes 지원 요구를 제거했다. 제품의 대상은 Python 애플리케이션의 설정 데이터와 환경변수 주입이다. Python 지원 범위는 3.10–3.14를 유지한다. 기획 R14·설계 G11·CI를 Python 설정 기반에 맞추고 manifest 예제·schema 검사·jsonschema 의존성을 제거했다.
|
|
8
|
+
|
|
9
|
+
최초 리뷰 원본은 수정하지 않았다. 이전 검증 기록은 당시 commit·CI에 귀속시키며 새 변경의 검증으로 재사용하지 않는다.
|
|
10
|
+
|
|
11
|
+
## 확정한 배포 범위
|
|
12
|
+
|
|
13
|
+
사용자가 “설계한 설정 라이브러리를 구현·검증한 뒤 release”를 선택했다. 문서·probe만 패키징하는 선택은 진행하지 않는다. ConfigLoader·ConfigModel·ConfigSnapshot과 계약 시험, wheel·sdist를 구현해 v1.0.0으로 배포한다. release branch·tag·GitHub Release에도 반영하며 PyPI 인증이나 업로드가 동작하지 않으면 사용자가 수동 업로드한다.
|
|
14
|
+
|
|
15
|
+
아래 과거 문서·probe 기록은 당시 commit의 결과다. 이번 구현의 검증은 별도 단락에서 기록한다.
|
|
16
|
+
|
|
17
|
+
## 문서와 branch 준비
|
|
18
|
+
|
|
19
|
+
- main의 `68c8fc8e85fa2eb7ace7faab2a2b0703fe795da0`에서 로컬 release branch를 생성했다.
|
|
20
|
+
- README와 사용자·설정 규칙·연동·개발 가이드를 작성했다. 모든 API 예제에 구현 전 상태를 명시했다.
|
|
21
|
+
- basic 예제에 YAML·profile YAML·dotenv template·Python 예제를 추가했다. expected output은 설계 계약이며 runtime 실행 결과가 아니다.
|
|
22
|
+
|
|
23
|
+
## 검증과 push
|
|
24
|
+
|
|
25
|
+
- macOS CPython 3.14.4·3.13.13에서 수정한 기반 probe를 통과했다.
|
|
26
|
+
- 문서 16개에서 local link·anchor 56개를 확인했다. README·guide의 Python block 16개와 YAML block 4개, basic 파일 예제의 syntax·dotenv template 파싱을 확인했다.
|
|
27
|
+
- 기본 예제의 API 실행은 하지 않았다. 실제 라이브러리 구현이 없기 때문이다.
|
|
28
|
+
- git diff --check를 통과했고 최초 리뷰 원본 SHA256이 기존 값과 일치한다.
|
|
29
|
+
|
|
30
|
+
- code commit `0370734a007cf16a711a20f91474dd07945fea92`를 origin/release에 push하고 원격 branch의 존재를 확인했다.
|
|
31
|
+
- [CI 실행 36239341897](https://github.com/pydemia/pydconfig/actions/runs/36239341897)의 7개 job이 모두 completed/success다. Ubuntu Python 3.10–3.14와 macOS·Windows 3.14.7에서 기반 API를 확인했다.
|
|
32
|
+
|
|
33
|
+
검증 결과 기록은 문서만 변경하며 code 검증 commit과 구분한다. main은 release의 문서·probe 변경을 fast-forward로 반영한다. 태그·GitHub Release는 범위 확정과 배포물 검증 뒤 진행한다.
|
|
34
|
+
|
|
35
|
+
## v1.0.0 구현 검증 진행
|
|
36
|
+
|
|
37
|
+
src/pydconfig와 build metadata, 계약 시험을 작성했다. macOS CPython 3.14.4에서 172개 시험이 통과했고 타입·배포물·플랫폼 검증은 진행 중이다. CI는 설치한 wheel에 전체 계약 시험을 실행하도록 변경한다. 태그와 GitHub Release는 이 검증이 통과한 commit을 가리키게 한다. 완료 결과와 PyPI 상태는 검증 후 기록한다.
|
|
38
|
+
|
|
39
|
+
## 최종 구현·플랫폼 검증
|
|
40
|
+
|
|
41
|
+
검증 code/test commit: `790a3d05790fe81ef462bb4134a33f0f28da7ab1`. [CI 36245893892](https://github.com/pydemia/pydconfig/actions/runs/36245893892)는 7개 job 모두 completed/success다. Ubuntu CPython 3.10·3.11·3.12·3.13·3.14.7, macOS·Windows 3.14.7에서 sdist→wheel build, 실제 wheel 설치 후 계약 시험, 기본 예제, upstream probe, mypy, Ruff, pip check, twine check를 완료했다.
|
|
42
|
+
|
|
43
|
+
로컬 CPython 3.14.4에서는 계약 시험 173개와 mypy 15개 source 파일, Ruff를 통과했다. checkout 밖 별도 venv에 wheel을 설치한 뒤 같은 173개 시험, site-packages import·version·py.typed·기본 파일 예제, pip check와 twine check를 확인했다. 이 build는 sdist를 먼저 만들고 그 sdist로 wheel을 만든다. 사용자 문서 6개에서 Python block 17개를 compile하고 local link/anchor 25개를 확인했다. FastAPI 0.141.1·httpx 0.28.1·Starlette 1.7.0의 문서 예제는 생성자 주입, snapshot override와 독립된 두 app의 TestClient 호출을 로컬에서 확인했다. FastAPI는 core/CI 의존성이나 모든 버전 지원 선언에 포함하지 않는다.
|
|
44
|
+
|
|
45
|
+
첫 CI의 Windows 계약 단계가 오래 실행돼 취소했다. 진단 verbose 실행에서 oversized fixture의 자동 test ID가 1 MiB 원문을 포함해 수 MB 로그를 만드는 문제를 확인했다. 짧은 explicit ID, concise 출력, 3분 step 제한과 faulthandler를 적용한 최종 CI가 모든 플랫폼에서 통과했다. 취소된 run 36245085310·36245623148은 최종 성공 근거로 재사용하지 않는다. 원격 로그 다운로드는 BlobNotFound로 확보하지 못했으며, 실제 job·step의 success와 로컬 시험 출력을 검증 증거로 사용한다.
|
|
46
|
+
|
|
47
|
+
배포 파일 검사는 py.typed 포함, wheel 내 tests·dotenv 파일 제외, sdist 내 예제 dotenv template 포함 및 실제 dotenv 제외를 확인했다. 코드·문서에서 credential pattern을 발견하지 않았고 최초 리뷰 원본 SHA256은 기존 값과 일치한다. 저작자·라이선스 값은 사용자 결정이 없어 metadata에 임의로 넣지 않았다.
|
|
48
|
+
|
|
49
|
+
이 기록 commit은 문서만 변경한다. 실행 code·test·workflow는 위 검증 commit과 같다. 최종 tag·GitHub Release·PyPI의 외부 게시 상태는 게시 후 별도로 확인해 기록한다.
|