DefEssential 0.1.7__tar.gz → 0.1.8__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 (193) hide show
  1. defessential-0.1.8/DefEssential.egg-info/PKG-INFO +82 -0
  2. {defessential-0.1.7 → defessential-0.1.8}/DefEssential.egg-info/SOURCES.txt +7 -0
  3. defessential-0.1.8/PKG-INFO +82 -0
  4. defessential-0.1.8/README.en.md +133 -0
  5. defessential-0.1.8/README.md +133 -0
  6. defessential-0.1.8/README.setup.md +48 -0
  7. defessential-0.1.8/issues/task/14/ISSUE.md +30 -0
  8. defessential-0.1.8/issues/task/14/PLAN.md +35 -0
  9. defessential-0.1.8/issues/task/14/README.md +7 -0
  10. defessential-0.1.8/issues/task/14/REQUIREMENTS.md +84 -0
  11. defessential-0.1.8/issues/task/14/TASK.md +22 -0
  12. {defessential-0.1.7 → defessential-0.1.8}/samples/Sample.py +3 -3
  13. {defessential-0.1.7 → defessential-0.1.8}/samples/runners/Requests.py +3 -3
  14. {defessential-0.1.7 → defessential-0.1.8}/samples/runners/Streaming.py +4 -4
  15. defessential-0.1.8/samples/runners/__init__.py +1 -0
  16. {defessential-0.1.7 → defessential-0.1.8}/samples/scripts/DescriptionToFile.py +1 -1
  17. {defessential-0.1.7 → defessential-0.1.8}/setup.py +1 -1
  18. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/Implements/Gunicorn/Server.py +2 -2
  19. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/Implements/Gunicorn/Transport.py +4 -4
  20. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/Implements/Python/Server.py +4 -4
  21. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/Implements/Uvicorn/HTTP.py +2 -2
  22. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/Implements/Uvicorn/Portal.py +1 -1
  23. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/Implements/Uvicorn/Server.py +2 -2
  24. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/Implements/Uvicorn/WebSocket.py +3 -3
  25. defessential-0.1.8/src/Adapter/Implements/__init__.py +3 -0
  26. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/RequestHandler.py +1 -1
  27. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/Server.py +4 -4
  28. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/WSGI.py +4 -4
  29. {defessential-0.1.7 → defessential-0.1.8}/src/Application.py +11 -11
  30. {defessential-0.1.7 → defessential-0.1.8}/src/CrossOriginResourceSharing.py +1 -1
  31. {defessential-0.1.7 → defessential-0.1.8}/src/Extension.py +8 -8
  32. {defessential-0.1.7 → defessential-0.1.8}/src/Extensions/File.py +1 -1
  33. {defessential-0.1.7 → defessential-0.1.8}/src/Extensions/FileSystem.py +2 -2
  34. {defessential-0.1.7 → defessential-0.1.8}/src/Extensions/Metrics.py +9 -8
  35. {defessential-0.1.7 → defessential-0.1.8}/src/Extensions/Ping.py +1 -1
  36. {defessential-0.1.7 → defessential-0.1.8}/src/Extensions/Specifications.py +1 -1
  37. {defessential-0.1.7 → defessential-0.1.8}/src/Extensions/Status.py +1 -1
  38. {defessential-0.1.7 → defessential-0.1.8}/src/Extensions/Swagger.py +1 -1
  39. {defessential-0.1.7 → defessential-0.1.8}/src/Extensions/Utils/Routes.py +1 -1
  40. {defessential-0.1.7 → defessential-0.1.8}/src/IO/RequestReader.py +2 -2
  41. {defessential-0.1.7 → defessential-0.1.8}/src/IO/ResponseWriter.py +5 -4
  42. {defessential-0.1.7 → defessential-0.1.8}/src/IO/WebSocket/WebSocket.py +10 -8
  43. {defessential-0.1.7 → defessential-0.1.8}/src/IO/WebSocket/WebSocketError.py +1 -1
  44. {defessential-0.1.7 → defessential-0.1.8}/src/IO/WebSocket/WebSocketFrame.py +1 -1
  45. {defessential-0.1.7 → defessential-0.1.8}/src/IO/WebSocket/WebSocketFrameReader.py +2 -2
  46. {defessential-0.1.7 → defessential-0.1.8}/src/IO/WebSocket/WebSocketHandshake.py +3 -3
  47. {defessential-0.1.7 → defessential-0.1.8}/src/RequestRunner.py +4 -4
  48. {defessential-0.1.7 → defessential-0.1.8}/src/Response.py +1 -1
  49. {defessential-0.1.7 → defessential-0.1.8}/src/Runners/RunExtension.py +2 -2
  50. {defessential-0.1.7 → defessential-0.1.8}/src/Runners/RunFactory.py +1 -1
  51. {defessential-0.1.7 → defessential-0.1.8}/src/Runners/RunRequest.py +1 -1
  52. {defessential-0.1.7 → defessential-0.1.8}/src/Startup.py +2 -2
  53. {defessential-0.1.7 → defessential-0.1.8}/src/Validators.py +1 -1
  54. {defessential-0.1.7 → defessential-0.1.8}/tests/test_application_hooks.py +1 -1
  55. {defessential-0.1.7 → defessential-0.1.8}/tests/test_exports.py +1 -1
  56. {defessential-0.1.7 → defessential-0.1.8}/tests/test_extension_hooks.py +1 -1
  57. {defessential-0.1.7 → defessential-0.1.8}/tests/test_samples.py +2 -2
  58. {defessential-0.1.7 → defessential-0.1.8}/tests/test_transport_conformance.py +3 -3
  59. {defessential-0.1.7 → defessential-0.1.8}/tests/test_websocket.py +3 -3
  60. {defessential-0.1.7 → defessential-0.1.8}/tests/test_writers.py +1 -1
  61. defessential-0.1.7/DefEssential.egg-info/PKG-INFO +0 -41
  62. defessential-0.1.7/PKG-INFO +0 -41
  63. defessential-0.1.7/README.md +0 -7
  64. defessential-0.1.7/samples/runners/__init__.py +0 -1
  65. defessential-0.1.7/src/Adapter/Implements/__init__.py +0 -3
  66. {defessential-0.1.7 → defessential-0.1.8}/.github/ISSUE_TEMPLATE/01.feature.yml +0 -0
  67. {defessential-0.1.7 → defessential-0.1.8}/.github/ISSUE_TEMPLATE/02.bug.yml +0 -0
  68. {defessential-0.1.7 → defessential-0.1.8}/.github/ISSUE_TEMPLATE/03.fix.yml +0 -0
  69. {defessential-0.1.7 → defessential-0.1.8}/.github/ISSUE_TEMPLATE/04.task.yml +0 -0
  70. {defessential-0.1.7 → defessential-0.1.8}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  71. {defessential-0.1.7 → defessential-0.1.8}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  72. {defessential-0.1.7 → defessential-0.1.8}/.github/workflows/ci.yml +0 -0
  73. {defessential-0.1.7 → defessential-0.1.8}/.gitignore +0 -0
  74. {defessential-0.1.7 → defessential-0.1.8}/DefEssential.egg-info/dependency_links.txt +0 -0
  75. {defessential-0.1.7 → defessential-0.1.8}/DefEssential.egg-info/requires.txt +0 -0
  76. {defessential-0.1.7 → defessential-0.1.8}/DefEssential.egg-info/top_level.txt +0 -0
  77. {defessential-0.1.7 → defessential-0.1.8}/LICENSE +0 -0
  78. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/2/ISSUE.md +0 -0
  79. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/2/README.md +0 -0
  80. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/2/REQUIREMENTS.md +0 -0
  81. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/3/IMPLEMENTS.md +0 -0
  82. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/3/ISSUE.md +0 -0
  83. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/3/README.md +0 -0
  84. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/3/REQUIREMENTS.md +0 -0
  85. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/4/IMPLEMENTS.md +0 -0
  86. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/4/ISSUE.md +0 -0
  87. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/4/PLAN.md +0 -0
  88. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/4/README.md +0 -0
  89. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/4/REQUIREMENTS.md +0 -0
  90. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/5/IMPLEMENTS.md +0 -0
  91. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/5/ISSUE.md +0 -0
  92. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/5/PLAN.md +0 -0
  93. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/5/README.md +0 -0
  94. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/5/REQUIREMENTS.md +0 -0
  95. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/6/IMPLEMENTS.md +0 -0
  96. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/6/ISSUE.md +0 -0
  97. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/6/PLAN.md +0 -0
  98. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/6/README.md +0 -0
  99. {defessential-0.1.7 → defessential-0.1.8}/issues/feature/6/REQUIREMENTS.md +0 -0
  100. {defessential-0.1.7 → defessential-0.1.8}/issues/task/8/IMPLEMENTS.md +0 -0
  101. {defessential-0.1.7 → defessential-0.1.8}/issues/task/8/ISSUE.md +0 -0
  102. {defessential-0.1.7 → defessential-0.1.8}/issues/task/8/PLAN.md +0 -0
  103. {defessential-0.1.7 → defessential-0.1.8}/issues/task/8/README.md +0 -0
  104. {defessential-0.1.7 → defessential-0.1.8}/issues/task/8/REQUIREMENTS.md +0 -0
  105. {defessential-0.1.7 → defessential-0.1.8}/samples/README.md +0 -0
  106. {defessential-0.1.7 → defessential-0.1.8}/samples/__init__.py +0 -0
  107. {defessential-0.1.7 → defessential-0.1.8}/samples/res/css/sample.css +0 -0
  108. {defessential-0.1.7 → defessential-0.1.8}/samples/res/favicon.ico +0 -0
  109. {defessential-0.1.7 → defessential-0.1.8}/samples/res/html/welcome.html +0 -0
  110. {defessential-0.1.7 → defessential-0.1.8}/samples/res/images/sample.jpg +0 -0
  111. {defessential-0.1.7 → defessential-0.1.8}/samples/res/images/sample.png +0 -0
  112. {defessential-0.1.7 → defessential-0.1.8}/samples/runners/Authentication.py +0 -0
  113. {defessential-0.1.7 → defessential-0.1.8}/samples/runners/ContentValidation.py +0 -0
  114. {defessential-0.1.7 → defessential-0.1.8}/samples/scripts/__init__.py +0 -0
  115. {defessential-0.1.7 → defessential-0.1.8}/setup.cfg +0 -0
  116. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/Implements/Gunicorn/__init__.py +0 -0
  117. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/Implements/Python/__init__.py +0 -0
  118. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/Implements/Uvicorn/__init__.py +0 -0
  119. {defessential-0.1.7 → defessential-0.1.8}/src/Adapter/__init__.py +0 -0
  120. {defessential-0.1.7 → defessential-0.1.8}/src/Body.py +0 -0
  121. {defessential-0.1.7 → defessential-0.1.8}/src/Content.py +0 -0
  122. {defessential-0.1.7 → defessential-0.1.8}/src/Credentials.py +0 -0
  123. {defessential-0.1.7 → defessential-0.1.8}/src/Descriptor/DataObject.py +0 -0
  124. {defessential-0.1.7 → defessential-0.1.8}/src/Descriptor/Types.py +0 -0
  125. {defessential-0.1.7 → defessential-0.1.8}/src/Descriptor/Value.py +0 -0
  126. {defessential-0.1.7 → defessential-0.1.8}/src/Descriptor/__init__.py +0 -0
  127. {defessential-0.1.7 → defessential-0.1.8}/src/Error.py +0 -0
  128. {defessential-0.1.7 → defessential-0.1.8}/src/Extensions/Status.html +0 -0
  129. {defessential-0.1.7 → defessential-0.1.8}/src/Extensions/Swagger.html +0 -0
  130. {defessential-0.1.7 → defessential-0.1.8}/src/Extensions/Utils/__init__.py +0 -0
  131. {defessential-0.1.7 → defessential-0.1.8}/src/Extensions/__init__.py +0 -0
  132. {defessential-0.1.7 → defessential-0.1.8}/src/IO/Readers/ChunkedStream.py +0 -0
  133. {defessential-0.1.7 → defessential-0.1.8}/src/IO/Readers/ContentReader.py +0 -0
  134. {defessential-0.1.7 → defessential-0.1.8}/src/IO/Readers/ContentReaders.py +0 -0
  135. {defessential-0.1.7 → defessential-0.1.8}/src/IO/Readers/__init__.py +0 -0
  136. {defessential-0.1.7 → defessential-0.1.8}/src/IO/WebSocket/__init__.py +0 -0
  137. {defessential-0.1.7 → defessential-0.1.8}/src/IO/Writers/ChunkedStreamWriter.py +0 -0
  138. {defessential-0.1.7 → defessential-0.1.8}/src/IO/Writers/ServerSentEvents.py +0 -0
  139. {defessential-0.1.7 → defessential-0.1.8}/src/IO/Writers/ServerSentEventsWriter.py +0 -0
  140. {defessential-0.1.7 → defessential-0.1.8}/src/IO/Writers/StreamWriter.py +0 -0
  141. {defessential-0.1.7 → defessential-0.1.8}/src/IO/Writers/__init__.py +0 -0
  142. {defessential-0.1.7 → defessential-0.1.8}/src/IO/__init__.py +0 -0
  143. {defessential-0.1.7 → defessential-0.1.8}/src/Request.py +0 -0
  144. {defessential-0.1.7 → defessential-0.1.8}/src/ResponseSpecification.py +0 -0
  145. {defessential-0.1.7 → defessential-0.1.8}/src/Responses/ResponseFile.py +0 -0
  146. {defessential-0.1.7 → defessential-0.1.8}/src/Responses/__init__.py +0 -0
  147. {defessential-0.1.7 → defessential-0.1.8}/src/Route.py +0 -0
  148. {defessential-0.1.7 → defessential-0.1.8}/src/Router.py +0 -0
  149. {defessential-0.1.7 → defessential-0.1.8}/src/Runners/RunOptions.py +0 -0
  150. {defessential-0.1.7 → defessential-0.1.8}/src/Runners/__init__.py +0 -0
  151. {defessential-0.1.7 → defessential-0.1.8}/src/Utils/FileSystemObject/Configuration.py +0 -0
  152. {defessential-0.1.7 → defessential-0.1.8}/src/Utils/FileSystemObject/Connection.py +0 -0
  153. {defessential-0.1.7 → defessential-0.1.8}/src/Utils/FileSystemObject/File.py +0 -0
  154. {defessential-0.1.7 → defessential-0.1.8}/src/Utils/FileSystemObject/Implements/FileSystem/Configuration.py +0 -0
  155. {defessential-0.1.7 → defessential-0.1.8}/src/Utils/FileSystemObject/Implements/FileSystem/Connection.py +0 -0
  156. {defessential-0.1.7 → defessential-0.1.8}/src/Utils/FileSystemObject/Implements/FileSystem/File.py +0 -0
  157. {defessential-0.1.7 → defessential-0.1.8}/src/Utils/FileSystemObject/Implements/FileSystem/__init__.py +0 -0
  158. {defessential-0.1.7 → defessential-0.1.8}/src/Utils/FileSystemObject/Implements/__init__.py +0 -0
  159. {defessential-0.1.7 → defessential-0.1.8}/src/Utils/FileSystemObject/__init__.py +0 -0
  160. {defessential-0.1.7 → defessential-0.1.8}/src/Utils/Loader.py +0 -0
  161. {defessential-0.1.7 → defessential-0.1.8}/src/Utils/__init__.py +0 -0
  162. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Pattern.py +0 -0
  163. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Patterns/Array.py +0 -0
  164. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Patterns/Common.py +0 -0
  165. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Patterns/Compare.py +0 -0
  166. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Patterns/Condition.py +0 -0
  167. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Patterns/DataObject.py +0 -0
  168. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Patterns/DateTime.py +0 -0
  169. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Patterns/Number.py +0 -0
  170. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Patterns/Object.py +0 -0
  171. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Patterns/Size.py +0 -0
  172. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Patterns/String.py +0 -0
  173. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Patterns/Type.py +0 -0
  174. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Patterns/__init__.py +0 -0
  175. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Validate.py +0 -0
  176. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/Validator.py +0 -0
  177. {defessential-0.1.7 → defessential-0.1.8}/src/Validator/__init__.py +0 -0
  178. {defessential-0.1.7 → defessential-0.1.8}/src/__init__.py +0 -0
  179. {defessential-0.1.7 → defessential-0.1.8}/tests/test_adapters.py +0 -0
  180. {defessential-0.1.7 → defessential-0.1.8}/tests/test_builtin_factories.py +0 -0
  181. {defessential-0.1.7 → defessential-0.1.8}/tests/test_content.py +0 -0
  182. {defessential-0.1.7 → defessential-0.1.8}/tests/test_core.py +0 -0
  183. {defessential-0.1.7 → defessential-0.1.8}/tests/test_extensions.py +0 -0
  184. {defessential-0.1.7 → defessential-0.1.8}/tests/test_features.py +0 -0
  185. {defessential-0.1.7 → defessential-0.1.8}/tests/test_files.py +0 -0
  186. {defessential-0.1.7 → defessential-0.1.8}/tests/test_independence.py +0 -0
  187. {defessential-0.1.7 → defessential-0.1.8}/tests/test_loading.py +0 -0
  188. {defessential-0.1.7 → defessential-0.1.8}/tests/test_logging.py +0 -0
  189. {defessential-0.1.7 → defessential-0.1.8}/tests/test_request_runner_hooks.py +0 -0
  190. {defessential-0.1.7 → defessential-0.1.8}/tests/test_server.py +0 -0
  191. {defessential-0.1.7 → defessential-0.1.8}/tests/test_sse.py +0 -0
  192. {defessential-0.1.7 → defessential-0.1.8}/tests/test_startup.py +0 -0
  193. {defessential-0.1.7 → defessential-0.1.8}/tests/test_uvicorn_transport.py +0 -0
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.4
2
+ Name: DefEssential
3
+ Version: 0.1.8
4
+ Summary: The Modern Synchronous Python Web Application Framework
5
+ Home-page: https://github.com/yong5eon/DefEssential
6
+ Author: Heo Yongseon
7
+ Project-URL: Source, https://github.com/yong5eon/DefEssential
8
+ Project-URL: Issues, https://github.com/yong5eon/DefEssential/issues
9
+ Project-URL: Releases, https://github.com/yong5eon/DefEssential/releases
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Provides-Extra: gunicorn
20
+ Requires-Dist: gunicorn>=23; extra == "gunicorn"
21
+ Provides-Extra: uvicorn
22
+ Requires-Dist: uvicorn>=0.30; extra == "uvicorn"
23
+ Requires-Dist: a2wsgi>=1.10; extra == "uvicorn"
24
+ Dynamic: author
25
+ Dynamic: classifier
26
+ Dynamic: description
27
+ Dynamic: description-content-type
28
+ Dynamic: home-page
29
+ Dynamic: license-file
30
+ Dynamic: project-url
31
+ Dynamic: provides-extra
32
+ Dynamic: requires-python
33
+ Dynamic: summary
34
+
35
+ # DefEssential
36
+
37
+ DefEssential is a synchronous Python web application framework for handling HTTP requests with ordinary Python methods. It provides route declarations, request validation, response helpers, streaming APIs, lifecycle hooks, and optional extensions without requiring `async` / `await`.
38
+
39
+ ## Requirements
40
+
41
+ - Python 3.9 or later
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install DefEssential
47
+ ```
48
+
49
+ The package includes a built-in Python HTTP server. Optional extras provide additional server adapters:
50
+
51
+ ```bash
52
+ pip install "DefEssential[Gunicorn]"
53
+ pip install "DefEssential[Uvicorn]"
54
+ ```
55
+
56
+ ## Quick start
57
+
58
+ ```python
59
+ from DefEssential import Application, Request, RequestRunner
60
+ from DefEssential.Adapter.Implements.Python import Server
61
+ from DefEssential.Responses import ResponseText
62
+
63
+
64
+ class Hello(RequestRunner, method='GET', url='/hello'):
65
+ def run(self, request: Request):
66
+ return ResponseText('Hello, world!')
67
+
68
+
69
+ application = Application()
70
+ application.add(Hello)
71
+ Server('127.0.0.1', 8000, application).run()
72
+ ```
73
+
74
+ The handler declares an HTTP method and path on its `RequestRunner` class. The application registers the handler, and the server runs the application. A `GET /hello` request returns a plain-text response.
75
+
76
+ ## Request handling
77
+
78
+ Define handlers as `RequestRunner` subclasses and implement `run()` with synchronous Python code. Configure path, query, header, and body validation in the class declaration. The framework also provides JSON, text, and file responses, direct streaming, Server-Sent Events, WebSocket support, and extensions for status checks, metrics, OpenAPI specifications, Swagger UI, and file serving.
79
+
80
+ ## License
81
+
82
+ See the `LICENSE` file included with the source distribution for license terms.
@@ -1,6 +1,8 @@
1
1
  .gitignore
2
2
  LICENSE
3
+ README.en.md
3
4
  README.md
5
+ README.setup.md
4
6
  setup.py
5
7
  .github/PULL_REQUEST_TEMPLATE.md
6
8
  .github/ISSUE_TEMPLATE/01.feature.yml
@@ -36,6 +38,11 @@ issues/feature/6/ISSUE.md
36
38
  issues/feature/6/PLAN.md
37
39
  issues/feature/6/README.md
38
40
  issues/feature/6/REQUIREMENTS.md
41
+ issues/task/14/ISSUE.md
42
+ issues/task/14/PLAN.md
43
+ issues/task/14/README.md
44
+ issues/task/14/REQUIREMENTS.md
45
+ issues/task/14/TASK.md
39
46
  issues/task/8/IMPLEMENTS.md
40
47
  issues/task/8/ISSUE.md
41
48
  issues/task/8/PLAN.md
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.4
2
+ Name: DefEssential
3
+ Version: 0.1.8
4
+ Summary: The Modern Synchronous Python Web Application Framework
5
+ Home-page: https://github.com/yong5eon/DefEssential
6
+ Author: Heo Yongseon
7
+ Project-URL: Source, https://github.com/yong5eon/DefEssential
8
+ Project-URL: Issues, https://github.com/yong5eon/DefEssential/issues
9
+ Project-URL: Releases, https://github.com/yong5eon/DefEssential/releases
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Provides-Extra: gunicorn
20
+ Requires-Dist: gunicorn>=23; extra == "gunicorn"
21
+ Provides-Extra: uvicorn
22
+ Requires-Dist: uvicorn>=0.30; extra == "uvicorn"
23
+ Requires-Dist: a2wsgi>=1.10; extra == "uvicorn"
24
+ Dynamic: author
25
+ Dynamic: classifier
26
+ Dynamic: description
27
+ Dynamic: description-content-type
28
+ Dynamic: home-page
29
+ Dynamic: license-file
30
+ Dynamic: project-url
31
+ Dynamic: provides-extra
32
+ Dynamic: requires-python
33
+ Dynamic: summary
34
+
35
+ # DefEssential
36
+
37
+ DefEssential is a synchronous Python web application framework for handling HTTP requests with ordinary Python methods. It provides route declarations, request validation, response helpers, streaming APIs, lifecycle hooks, and optional extensions without requiring `async` / `await`.
38
+
39
+ ## Requirements
40
+
41
+ - Python 3.9 or later
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install DefEssential
47
+ ```
48
+
49
+ The package includes a built-in Python HTTP server. Optional extras provide additional server adapters:
50
+
51
+ ```bash
52
+ pip install "DefEssential[Gunicorn]"
53
+ pip install "DefEssential[Uvicorn]"
54
+ ```
55
+
56
+ ## Quick start
57
+
58
+ ```python
59
+ from DefEssential import Application, Request, RequestRunner
60
+ from DefEssential.Adapter.Implements.Python import Server
61
+ from DefEssential.Responses import ResponseText
62
+
63
+
64
+ class Hello(RequestRunner, method='GET', url='/hello'):
65
+ def run(self, request: Request):
66
+ return ResponseText('Hello, world!')
67
+
68
+
69
+ application = Application()
70
+ application.add(Hello)
71
+ Server('127.0.0.1', 8000, application).run()
72
+ ```
73
+
74
+ The handler declares an HTTP method and path on its `RequestRunner` class. The application registers the handler, and the server runs the application. A `GET /hello` request returns a plain-text response.
75
+
76
+ ## Request handling
77
+
78
+ Define handlers as `RequestRunner` subclasses and implement `run()` with synchronous Python code. Configure path, query, header, and body validation in the class declaration. The framework also provides JSON, text, and file responses, direct streaming, Server-Sent Events, WebSocket support, and extensions for status checks, metrics, OpenAPI specifications, Swagger UI, and file serving.
79
+
80
+ ## License
81
+
82
+ See the `LICENSE` file included with the source distribution for license terms.
@@ -0,0 +1,133 @@
1
+ # DefEssential
2
+
3
+ The modern synchronous Python web application framework
4
+
5
+ **Just def.**<br>
6
+ **Let web apps do the work.**<br>
7
+ **You don't need to await this.**
8
+
9
+ [한국어](./README.md)
10
+
11
+ DefEssential is a synchronous web framework for handling HTTP requests with ordinary Python methods.
12
+ Configure routes, request validation, responses, and extensions without `async` / `await`.
13
+
14
+ - **Synchronous request handling**: Declare HTTP methods, paths, and handlers with `RequestRunner` classes.
15
+ - **Request validation**: Apply validators and converters to path, query, header, and body values.
16
+ - **Responses and streaming**: Support JSON, text, and file responses, streaming, Server-Sent Events, and WebSocket.
17
+ - **Extensions**: Combine health status, Ping, Metrics, OpenAPI specifications, Swagger UI, and file-serving features.
18
+ - **Server adapters**: Use the built-in Python server or optionally install the Gunicorn and Uvicorn adapters.
19
+ - **Lifecycle hooks**: Register hooks for application, extension, and request execution lifecycles.
20
+
21
+ ## Requirements and installation
22
+
23
+ - Python 3.9 or later
24
+
25
+ ```bash
26
+ pip install DefEssential
27
+ ```
28
+
29
+ The built-in Python server requires no additional server dependency. Install an optional extra to use another adapter.
30
+
31
+ ```bash
32
+ pip install "DefEssential[Gunicorn]"
33
+ pip install "DefEssential[Uvicorn]"
34
+ ```
35
+
36
+ ## Quick start
37
+
38
+ ```python
39
+ from DefEssential import Application, Request, RequestRunner
40
+ from DefEssential.Adapter.Implements.Python import Server
41
+ from DefEssential.Responses import ResponseText
42
+
43
+
44
+ class Hello(RequestRunner, method='GET', url='/hello'):
45
+ def run(self, request: Request):
46
+ return ResponseText('Hello, world!')
47
+
48
+
49
+ application = Application()
50
+ application.add(Hello)
51
+
52
+ Server('127.0.0.1', 8000, application).run()
53
+ ```
54
+
55
+ After starting the server, a `GET /hello` request returns `Hello, world!`. Each request is handled by a new handler instance.
56
+
57
+ ## Request handlers and validation
58
+
59
+ Declare `method` and `url` on a `RequestRunner` subclass and implement synchronous request handling in `run()`. Declare URL path parameters with the `:name` syntax and configure validation rules with `parameters`, `qs`, `headers`, and `body`.
60
+
61
+ ```python
62
+ from DefEssential import (
63
+ Parameters,
64
+ Request,
65
+ RequestRunner,
66
+ )
67
+ from DefEssential.Responses import ResponseJSON
68
+ from DefEssential.Validator.Patterns import (
69
+ IsGreaterThan,
70
+ ToInteger,
71
+ )
72
+
73
+
74
+ class ReadValue(
75
+ RequestRunner,
76
+ method='GET',
77
+ url='/values/:value',
78
+ parameters=Parameters({
79
+ 'value': ToInteger(IsGreaterThan(0)),
80
+ }),
81
+ ):
82
+ def run(self, request: Request):
83
+ return ResponseJSON({'value': request.parameters['value']})
84
+ ```
85
+
86
+ Validators and converters run before input is passed to the handler. Read request bodies as JSON, text, binary data, or streams through `Body` and content readers.
87
+
88
+ ## Responses, streaming, and protocols
89
+
90
+ - Create JSON, text, and file responses with `ResponseJSON`, `ResponseText`, and `ResponseFile`.
91
+ - Stream response bodies through `request.writer` and stream writers. In this mode, the handler writes the response directly and returns `None`.
92
+ - Send event streams with the Server-Sent Events writer.
93
+ - Use the `WebSocket` API to exchange text and binary messages after upgrading an HTTP connection.
94
+
95
+ Direct-output and streaming responses have different processing timing from ordinary returned responses. Configure response handling according to the relevant hook contracts and transport behavior.
96
+
97
+ ## Extensions and servers
98
+
99
+ Pass extensions to `Application(exts=...)`. Built-in extensions include:
100
+
101
+ - `Status`: provide a status page
102
+ - `Ping`: report the application's running state
103
+ - `Metrics`: expose request metrics as JSON or Prometheus
104
+ - `Specifications`: generate an OpenAPI 3.1 document from registered routes
105
+ - `Swagger`: provide Swagger UI
106
+ - `File`, `FileSystem`: serve fixed files or file-system content
107
+
108
+ The built-in server is `DefEssential.Adapter.Implements.Python.Server`. Install the `DefEssential[Gunicorn]` or `DefEssential[Uvicorn]` extra for the corresponding adapter. Supported environments and transport characteristics vary by adapter and worker type.
109
+
110
+ ## Lifecycle hooks and logging
111
+
112
+ `Application` accepts `on_startup`, `on_cleanup`, `on_request`, `on_request_response`, and `on_request_error` hooks. `Extension` supports startup, cleanup, request, response, and error hooks; `RequestRunner` supports request, response, and error hooks.
113
+
114
+ DefEssential uses standard `logging` loggers and does not configure application handlers or log levels. Configure the loggers and output policy required by your application.
115
+
116
+ ## Samples and tests
117
+
118
+ `samples/Sample.py` in the repository demonstrates requests, validation, authentication, files, streaming, WebSocket, and built-in extensions. Run the sample server from the project root:
119
+
120
+ ```bash
121
+ python samples/Sample.py
122
+ ```
123
+
124
+ Install the current checkout in editable mode from the project root, then run the tests:
125
+
126
+ ```bash
127
+ pip install -e .
128
+ python -m unittest discover -s tests
129
+ ```
130
+
131
+ ## License
132
+
133
+ See the `LICENSE` file in the repository for license terms.
@@ -0,0 +1,133 @@
1
+ # DefEssential
2
+
3
+ 동기식 Python 웹 애플리케이션 프레임워크
4
+
5
+ **Just def.**<br>
6
+ **Let web apps do the work.**<br>
7
+ **You don't need to await this.**
8
+
9
+ [English](./README.en.md)
10
+
11
+ DefEssential은 일반 Python 메서드로 HTTP 요청을 처리하는 동기식 웹 프레임워크입니다.
12
+ `async` / `await` 없이 라우트, 요청 검증, 응답, 확장 기능을 구성할 수 있습니다.
13
+
14
+ - **동기식 요청 처리**: `RequestRunner` 클래스로 HTTP 메서드와 경로, 핸들러를 선언합니다.
15
+ - **요청 검증**: 경로·쿼리·헤더·본문 값에 검증기와 변환기를 적용합니다.
16
+ - **응답과 스트리밍**: JSON·텍스트·파일 응답, 스트리밍, Server-Sent Events, WebSocket을 지원합니다.
17
+ - **확장 기능**: 상태 확인, Ping, Metrics, OpenAPI 명세와 Swagger UI, 파일 제공 기능을 조합할 수 있습니다.
18
+ - **서버 어댑터**: 기본 Python 서버를 제공하며 Gunicorn과 Uvicorn 어댑터를 선택적으로 설치할 수 있습니다.
19
+ - **생명주기 훅**: 애플리케이션, 확장, 요청 실행 단계에 훅을 등록할 수 있습니다.
20
+
21
+ ## 요구 사항 및 설치
22
+
23
+ - Python 3.9 이상
24
+
25
+ ```bash
26
+ pip install DefEssential
27
+ ```
28
+
29
+ 기본 Python 서버는 추가 서버 의존성 없이 사용할 수 있습니다. 선택적 어댑터가 필요한 경우 해당 추가 기능을 설치합니다.
30
+
31
+ ```bash
32
+ pip install "DefEssential[Gunicorn]"
33
+ pip install "DefEssential[Uvicorn]"
34
+ ```
35
+
36
+ ## 빠른 시작
37
+
38
+ ```python
39
+ from DefEssential import Application, Request, RequestRunner
40
+ from DefEssential.Adapter.Implements.Python import Server
41
+ from DefEssential.Responses import ResponseText
42
+
43
+
44
+ class Hello(RequestRunner, method='GET', url='/hello'):
45
+ def run(self, request: Request):
46
+ return ResponseText('Hello, world!')
47
+
48
+
49
+ application = Application()
50
+ application.add(Hello)
51
+
52
+ Server('127.0.0.1', 8000, application).run()
53
+ ```
54
+
55
+ 서버를 실행한 뒤 `GET /hello` 요청은 `Hello, world!`를 반환합니다. 각 요청은 새로운 핸들러 인스턴스에서 처리됩니다.
56
+
57
+ ## 요청 핸들러와 검증
58
+
59
+ `RequestRunner` 하위 클래스 선언에서 `method`와 `url`을 지정하고 `run()` 메서드에 동기식 처리 로직을 작성합니다. URL 경로 변수는 `:name` 형식으로 선언하며, `parameters`, `qs`, `headers`, `body` 설정에 검증 규칙을 지정할 수 있습니다.
60
+
61
+ ```python
62
+ from DefEssential import (
63
+ Parameters,
64
+ Request,
65
+ RequestRunner,
66
+ )
67
+ from DefEssential.Responses import ResponseJSON
68
+ from DefEssential.Validator.Patterns import (
69
+ IsGreaterThan,
70
+ ToInteger,
71
+ )
72
+
73
+
74
+ class ReadValue(
75
+ RequestRunner,
76
+ method='GET',
77
+ url='/values/:value',
78
+ parameters=Parameters({
79
+ 'value': ToInteger(IsGreaterThan(0)),
80
+ }),
81
+ ):
82
+ def run(self, request: Request):
83
+ return ResponseJSON({'value': request.parameters['value']})
84
+ ```
85
+
86
+ 검증기와 변환기는 요청 입력을 핸들러에 전달하기 전에 실행됩니다. 본문은 `Body`와 콘텐츠 리더를 통해 JSON, 텍스트, 바이너리 또는 스트리밍 방식으로 읽을 수 있습니다.
87
+
88
+ ## 응답, 스트리밍 및 프로토콜
89
+
90
+ - `ResponseJSON`, `ResponseText`, `ResponseFile`로 JSON, 텍스트, 파일 응답을 만들 수 있습니다.
91
+ - `request.writer`와 스트림 writer로 응답 본문을 직접 스트리밍할 수 있습니다. 이 방식에서는 핸들러가 응답을 직접 기록하고 `None`을 반환합니다.
92
+ - Server-Sent Events writer로 이벤트 스트림을 전송할 수 있습니다.
93
+ - `WebSocket` API는 HTTP 연결을 업그레이드한 뒤 text 및 binary 메시지를 송수신합니다.
94
+
95
+ 직접 출력 및 스트리밍 응답은 일반 반환 응답과 처리 시점이 다릅니다. 관련 훅 계약과 전송 동작에 맞춰 응답 처리를 구성하세요.
96
+
97
+ ## 확장 기능과 서버
98
+
99
+ 확장 기능은 `Application(exts=...)`에 전달해 사용합니다. 기본 제공 확장은 다음과 같습니다.
100
+
101
+ - `Status`: 상태 페이지 제공
102
+ - `Ping`: 애플리케이션 실행 상태 응답
103
+ - `Metrics`: JSON 또는 Prometheus 형식의 요청 통계 제공
104
+ - `Specifications`: 등록된 라우트로부터 OpenAPI 3.1 문서 생성
105
+ - `Swagger`: Swagger UI 제공
106
+ - `File`, `FileSystem`: 고정 파일 또는 파일 시스템 콘텐츠 제공
107
+
108
+ 기본 서버는 `DefEssential.Adapter.Implements.Python.Server`입니다. Gunicorn과 Uvicorn 어댑터는 각각 `DefEssential[Gunicorn]`, `DefEssential[Uvicorn]` 추가 기능으로 설치합니다. 어댑터와 worker 방식에 따라 지원 환경과 전송 특성이 다를 수 있습니다.
109
+
110
+ ## 생명주기 훅과 로깅
111
+
112
+ `Application`은 `on_startup`, `on_cleanup`, `on_request`, `on_request_response`, `on_request_error` 훅을 받을 수 있습니다. `Extension`은 시작·정리·요청·응답·오류 훅을, `RequestRunner`는 요청·응답·오류 훅을 지원합니다.
113
+
114
+ DefEssential은 표준 `logging` 로거를 사용하며 애플리케이션의 핸들러나 로그 레벨을 대신 설정하지 않습니다. 애플리케이션에서 필요한 로거와 출력 정책을 구성하세요.
115
+
116
+ ## 샘플 및 테스트
117
+
118
+ 저장소의 `samples/Sample.py`에는 요청, 검증, 인증, 파일, 스트리밍, WebSocket 및 기본 제공 확장을 포함한 실행 예제가 있습니다. 프로젝트 루트에서 다음 명령으로 샘플 서버를 실행할 수 있습니다.
119
+
120
+ ```bash
121
+ python samples/Sample.py
122
+ ```
123
+
124
+ 저장소 코드를 테스트하려면 프로젝트 루트에서 editable 설치를 한 뒤 다음 명령을 실행합니다.
125
+
126
+ ```bash
127
+ pip install -e .
128
+ python -m unittest discover -s tests
129
+ ```
130
+
131
+ ## 라이선스
132
+
133
+ 라이선스 조건은 저장소의 `LICENSE` 파일을 확인하세요.
@@ -0,0 +1,48 @@
1
+ # DefEssential
2
+
3
+ DefEssential is a synchronous Python web application framework for handling HTTP requests with ordinary Python methods. It provides route declarations, request validation, response helpers, streaming APIs, lifecycle hooks, and optional extensions without requiring `async` / `await`.
4
+
5
+ ## Requirements
6
+
7
+ - Python 3.9 or later
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pip install DefEssential
13
+ ```
14
+
15
+ The package includes a built-in Python HTTP server. Optional extras provide additional server adapters:
16
+
17
+ ```bash
18
+ pip install "DefEssential[Gunicorn]"
19
+ pip install "DefEssential[Uvicorn]"
20
+ ```
21
+
22
+ ## Quick start
23
+
24
+ ```python
25
+ from DefEssential import Application, Request, RequestRunner
26
+ from DefEssential.Adapter.Implements.Python import Server
27
+ from DefEssential.Responses import ResponseText
28
+
29
+
30
+ class Hello(RequestRunner, method='GET', url='/hello'):
31
+ def run(self, request: Request):
32
+ return ResponseText('Hello, world!')
33
+
34
+
35
+ application = Application()
36
+ application.add(Hello)
37
+ Server('127.0.0.1', 8000, application).run()
38
+ ```
39
+
40
+ The handler declares an HTTP method and path on its `RequestRunner` class. The application registers the handler, and the server runs the application. A `GET /hello` request returns a plain-text response.
41
+
42
+ ## Request handling
43
+
44
+ Define handlers as `RequestRunner` subclasses and implement `run()` with synchronous Python code. Configure path, query, header, and body validation in the class declaration. The framework also provides JSON, text, and file responses, direct streaming, Server-Sent Events, WebSocket support, and extensions for status checks, metrics, OpenAPI specifications, Swagger UI, and file serving.
45
+
46
+ ## License
47
+
48
+ See the `LICENSE` file included with the source distribution for license terms.
@@ -0,0 +1,30 @@
1
+ # DefEssential 문서 현지화 및 Python 설명 문구 영어화
2
+
3
+ ## 작업 목적
4
+
5
+ 공개 프로젝트의 사용자 문서를 한국어와 영어로 제공하고, 배포되는 Python 코드의 설명 및 예외 문구를 영어로 통일한다. 문서와 문구의 언어만 변경하며 기존 API와 실행 동작은 유지한다.
6
+
7
+ ## 작업 범위
8
+
9
+ ### 문서
10
+
11
+ - `README.md`: 설치, 빠른 시작, 주요 기능과 사용 방법을 포함하는 한국어 사용자 매뉴얼로 작성한다.
12
+ - `README.en.md`: `README.md`와 같은 범위와 구조를 갖는 영어 매뉴얼을 새로 작성한다.
13
+ - `README.setup.md`: PyPI 패키지 설명에 사용할 영어 문서를 새로 작성한다. PyPI 사용자에게 필요한 프로젝트 소개, 설치 방법, 빠른 시작을 포함하며 외부 링크를 넣지 않는다.
14
+ - `setup.py`: 패키지 메타데이터의 `long_description`이 `README.setup.md`를 읽도록 변경한다. PyPI 설명에 한국어 문서가 노출되지 않아야 한다.
15
+
16
+ ### Python 문구
17
+
18
+ - 대상은 DefEssential 프로젝트의 관리 대상 Python 파일이다: `src/`, `samples/`, `tests/` 아래의 `.py` 파일과 루트 `setup.py`.
19
+ - 대상 파일의 독스트링, 주석, `raise` 문에서 사용자에게 노출되는 예외 메시지를 자연스러운 영어로 작성한다.
20
+ - 식별자, API 이름, 예외 유형, 조건 및 처리 로직은 변경하지 않는다. 번역에 수반되는 메시지 문자열 변경 외의 동작 변경은 이 작업 범위에 포함하지 않는다.
21
+
22
+ ## 완료 기준
23
+
24
+ - `README.md`는 한국어 매뉴얼이며, `README.en.md`는 이에 대응하는 영어 매뉴얼이다.
25
+ - `README.setup.md`는 영어로 작성되고, `setup.py`가 이 문서를 패키지의 PyPI 설명으로 사용한다.
26
+ - `README.setup.md`에는 외부 URL 또는 외부 페이지로 연결되는 링크가 없다.
27
+ - 지정한 Python 파일의 독스트링과 주석에 한국어 설명 문구가 남아 있지 않다.
28
+ - `raise` 문에서 사용자에게 노출되는 예외 메시지가 영어이며, 메시지 변경으로 영향을 받는 테스트도 갱신되어 통과한다.
29
+ - 변경은 문서와 설명 문구에 한정되고, 공개 API와 기존 실행 동작이 유지된다.
30
+ - Python 파일의 한글 검색 결과를 검토하여 남은 한글이 있다면 대상 범위의 문구인지 확인한다. 테스트 데이터 등 번역 대상이 아닌 문자열은 불필요하게 변경하지 않는다.
@@ -0,0 +1,35 @@
1
+ # DefEssential 문서 현지화 및 Python 설명 문구 영어화 작업 계획
2
+
3
+ ## 목표
4
+
5
+ [요구사항 명세서](./REQUIREMENTS.md)에 따라 사용자 문서와 Python 설명 문구를 현지화하고, PyPI 패키지 설명이 독립적인 영어 문서로 제공되도록 한다. 기존 공개 API와 실행 동작은 유지한다.
6
+
7
+ ## 작업 단계
8
+
9
+ 1. **현행 문서와 기능 확인**
10
+ - `README.md`, 샘플, 공개 API 및 패키지 설정을 확인해 현재 사용법과 공개 기능을 정리한다.
11
+ - 기존 `README.md`가 한국어 매뉴얼 요구사항을 충족하는지 검토하고, 누락된 설치·빠른 시작·기능 설명을 식별한다.
12
+ 2. **사용자 문서 작성**
13
+ - `README.md`를 요구사항에 맞는 한국어 매뉴얼로 정리한다.
14
+ - `README.en.md`를 작성하고 한국어 매뉴얼과 주요 주제 및 기능 범위를 맞춘다.
15
+ - PyPI에서 독립적으로 읽을 수 있는 `README.setup.md`를 영어로 작성한다. 외부 링크와 일반 텍스트 URL이 포함되지 않도록 확인한다.
16
+ 3. **PyPI 설명 연결**
17
+ - `setup.py`가 `README.setup.md`를 `long_description` 원본으로 읽도록 변경한다.
18
+ - 마크다운 콘텐츠 형식 및 패키지 메타데이터에 설명 본문이 포함되는지 확인한다.
19
+ 4. **Python 문구 조사 및 번역**
20
+ - 대상 Python 파일에서 한글이 포함된 독스트링, 주석, `raise` 예외 메시지를 분류한다.
21
+ - 테스트 데이터, 사용자 입력 예시 등 번역 제외 항목은 보존하고, 해당 문구만 의미를 유지해 영어로 바꾼다.
22
+ - 번역된 예외 메시지를 검증하는 테스트가 있다면 새 메시지에 맞춰 기대값을 갱신한다.
23
+ 5. **검증 및 회귀 확인**
24
+ - 대상 Python 파일의 한글 검색 결과를 검토해 남은 항목이 요구사항의 제외 범위에 해당하는지 확인한다.
25
+ - `README.setup.md`의 URL 및 링크를 검사하고, 패키지 메타데이터가 이 문서를 사용하고 있는지 확인한다.
26
+ - 관련 테스트를 실행하고 공개 API, 예외 유형, 프로토콜 계약 및 런타임 동작에 변경이 없는지 확인한다.
27
+
28
+ ## 검증 기준
29
+
30
+ - `README.md`는 한국어, `README.en.md`와 `README.setup.md`는 영어로 작성되어 있다.
31
+ - 두 사용자 매뉴얼은 주요 주제와 기능 범위가 대응하며, 문서의 설명과 예제가 실제 구현과 일치한다.
32
+ - `README.setup.md`에 외부 URL이나 외부 페이지 링크가 없고, PyPI 설명 본문으로 사용된다.
33
+ - 대상 Python 파일의 독스트링과 주석에 한국어 설명 문구가 남아 있지 않다. 발견된 잔여 한글은 번역 제외 대상임을 확인한다.
34
+ - 대상 Python 파일의 사용자 노출 예외 메시지가 영어이며, 관련 테스트가 갱신되어 통과한다.
35
+ - 관련 테스트가 통과하고, 변경 범위 밖의 API와 런타임 동작에 회귀가 없다.
@@ -0,0 +1,7 @@
1
+ # DefEssential 문서 현지화
2
+
3
+ 이전에는 저장소에서 한국어 사용자 안내가 제한적이었고, PyPI 패키지 설명은 저장소 README를 그대로 사용했습니다. 이제 한국어 매뉴얼과 이에 대응하는 영어 매뉴얼을 제공하며, 패키지 설치 페이지에는 별도의 간결한 영어 안내가 표시됩니다.
4
+
5
+ Python 코드 설명도 영어로 통일했습니다. 공개 API와 애플리케이션의 실행 동작은 변경되지 않았으므로 기존 코드를 수정하거나 마이그레이션할 필요가 없습니다.
6
+
7
+ 설치와 빠른 시작은 PyPI 설명에서 바로 확인할 수 있습니다. 저장소의 전체 사용 안내는 한국어 [사용자 매뉴얼](../../../README.md)과 [영어 매뉴얼](../../../README.en.md)을 참고하세요.
@@ -0,0 +1,84 @@
1
+ # DefEssential 문서 현지화 및 Python 설명 문구 영어화 요구사항
2
+
3
+ ## 목적
4
+
5
+ DefEssential 사용자 문서를 한국어와 영어로 제공하고, 프로젝트의 관리 대상 Python 파일에서 독스트링, 주석, 사용자에게 노출되는 예외 메시지를 영어로 통일한다. PyPI에는 별도의 영어 설명 문서를 게시해 패키지 소개가 영어로 표시되도록 한다.
6
+
7
+ ## 범위
8
+
9
+ ### 대상
10
+
11
+ - `README.md`: 저장소의 한국어 사용자 매뉴얼
12
+ - `README.en.md`: 저장소의 영어 사용자 매뉴얼
13
+ - `README.setup.md`: PyPI 패키지 설명에 사용하는 영어 문서
14
+ - `setup.py`: PyPI 설명 문서의 경로를 지정하는 패키지 설정
15
+ - Python 문구 변경 대상:
16
+ - `src/`, `samples/`, `tests/` 아래의 Python 파일
17
+ - 프로젝트 루트의 `setup.py`
18
+
19
+ ### 제외
20
+
21
+ - 공개 API, 식별자, 예외 유형, 제어 흐름, 데이터 형식 및 런타임 동작 변경
22
+ - 독스트링·주석·예외 메시지 외의 사용자 인터페이스, 로그, 프로토콜 값, 테스트 입력 데이터 번역
23
+ - 명시된 대상 경로 밖의 프로젝트와 Python 파일 변경
24
+
25
+ ## 기능 요구사항
26
+
27
+ ### DOC-01: 한국어 사용자 매뉴얼
28
+
29
+ - `README.md`는 한국어로 작성한다.
30
+ - 설치 방법, 빠른 시작, 주요 기능과 사용 방법을 포함한다.
31
+ - 실제 프로젝트의 공개 기능 및 사용 방법과 일치해야 한다.
32
+
33
+ ### DOC-02: 영어 사용자 매뉴얼
34
+
35
+ - `README.en.md`를 새로 작성한다.
36
+ - `README.md`와 같은 주요 주제와 기능 범위를 다루는 영어 문서로 제공한다.
37
+ - 설명과 예제가 실제 프로젝트의 API 및 동작과 일치해야 한다.
38
+
39
+ ### DOC-03: PyPI 패키지 설명
40
+
41
+ - `README.setup.md`를 PyPI 패키지 페이지에 적합한 영어 문서로 새로 작성한다.
42
+ - 프로젝트 소개, 설치 방법, 빠른 시작을 포함한다.
43
+ - 문서에 외부 URL 또는 외부 웹 페이지로 연결되는 링크를 포함하지 않는다. 링크 형태의 외부 참조뿐 아니라 일반 텍스트로 표기한 외부 URL도 금지한다.
44
+ - PyPI에서 독립적으로 표시되어도 목적과 설치·시작 방법을 이해할 수 있도록 작성한다.
45
+
46
+ ### PKG-01: PyPI 설명 문서 연결
47
+
48
+ - `setup.py`의 `long_description`은 `README.setup.md` 내용을 읽어야 한다.
49
+ - `long_description_content_type`은 마크다운 형식을 유지한다.
50
+ - 패키지를 빌드했을 때 메타데이터의 설명 본문에 `README.setup.md` 내용이 포함되어야 한다.
51
+
52
+ ### PY-01: 독스트링과 주석
53
+
54
+ - 범위에 포함된 Python 파일에서 한국어로 작성된 독스트링과 주석을 영어로 작성한다.
55
+ - 문맥에 맞는 자연스러운 영어로 번역하되, 문서화 대상의 의미와 제약을 보존한다.
56
+ - 기존에 이미 영어인 문구는 불필요하게 다시 작성하지 않는다.
57
+
58
+ ### PY-02: 예외 메시지
59
+
60
+ - 범위에 포함된 Python 파일의 `raise` 문에서 사용자에게 노출되는 예외 메시지를 영어로 작성한다.
61
+ - 메시지의 의미, 오류 상황, 사용자에게 필요한 조치 정보가 있다면 이를 보존한다.
62
+ - 예외 유형, 발생 조건, 예외 체인 및 처리 동작은 변경하지 않는다.
63
+ - 메시지가 테스트에서 검증되는 경우 기대 문자열도 새 메시지에 맞춰 갱신한다.
64
+
65
+ ## 제약 및 호환성
66
+
67
+ - 변경은 문서 및 지정한 설명 문구에 한정한다.
68
+ - 공개 API, 함수 인자와 반환값, 예외 유형, 프로토콜 계약, 실행 결과는 기존과 동일해야 한다.
69
+ - 한국어가 포함된 테스트 데이터, 입력값, 임의의 사용자 콘텐츠는 번역 대상이 아니다. 검색 결과만을 기준으로 일괄 치환하지 않는다.
70
+ - `README.setup.md`의 외부 링크 금지는 이 문서에만 적용한다. `README.md`와 `README.en.md`의 링크 정책은 이 요구사항에서 변경하지 않는다.
71
+
72
+ ## 수용 기준
73
+
74
+ | ID | 기준 |
75
+ | --- | --- |
76
+ | AC-01 | `README.md`가 한국어로 설치, 빠른 시작, 주요 기능과 사용 방법을 설명한다. |
77
+ | AC-02 | `README.en.md`가 `README.md`와 같은 주요 주제 및 기능 범위를 영어로 설명한다. |
78
+ | AC-03 | `README.setup.md`가 영어로 프로젝트 소개, 설치 방법, 빠른 시작을 포함한다. |
79
+ | AC-04 | `README.setup.md`에 외부 URL 및 외부 웹 페이지 링크가 없다. |
80
+ | AC-05 | 패키지 설정이 `README.setup.md`를 마크다운 형식의 `long_description` 원본으로 사용한다. |
81
+ | AC-06 | 대상 Python 파일의 독스트링과 주석에 한국어 설명 문구가 남아 있지 않다. |
82
+ | AC-07 | 대상 Python 파일의 사용자 노출 예외 메시지가 영어이며, 변경한 메시지에 맞춰 관련 테스트가 갱신된다. |
83
+ | AC-08 | 변경 후 관련 테스트가 통과하고 공개 API, 예외 유형, 프로토콜 계약 및 런타임 동작에 회귀가 없다. |
84
+ | AC-09 | Python 파일의 한글 검색 결과를 검토해 남은 한글이 번역 제외 대상인지 확인한다. |