DefChord 0.1.11__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.
- defchord-0.1.11/.dev/scripts/editable_view.py +287 -0
- defchord-0.1.11/.dev/scripts/tests/__init__.py +0 -0
- defchord-0.1.11/.dev/scripts/tests/test_editable_view.py +496 -0
- defchord-0.1.11/.distribution-target +1 -0
- defchord-0.1.11/.github/ISSUE_TEMPLATE/01.feature.yml +37 -0
- defchord-0.1.11/.github/ISSUE_TEMPLATE/02.bug.yml +62 -0
- defchord-0.1.11/.github/ISSUE_TEMPLATE/03.fix.yml +55 -0
- defchord-0.1.11/.github/ISSUE_TEMPLATE/04.task.yml +38 -0
- defchord-0.1.11/.github/ISSUE_TEMPLATE/config.yml +1 -0
- defchord-0.1.11/.github/PULL_REQUEST_TEMPLATE.md +24 -0
- defchord-0.1.11/.github/scripts/build_backend.py +138 -0
- defchord-0.1.11/.github/scripts/build_distributions.py +64 -0
- defchord-0.1.11/.github/scripts/check_distributions.py +598 -0
- defchord-0.1.11/.github/scripts/create-issues-from-reviews.mjs +564 -0
- defchord-0.1.11/.github/scripts/create-pr-from-issue.mjs +529 -0
- defchord-0.1.11/.github/scripts/prepare_upload.py +104 -0
- defchord-0.1.11/.github/scripts/tests/__init__.py +0 -0
- defchord-0.1.11/.github/scripts/tests/create-issues-from-reviews.test.mjs +636 -0
- defchord-0.1.11/.github/scripts/tests/create-pr-from-issue.test.mjs +975 -0
- defchord-0.1.11/.github/scripts/tests/test_build_backend.py +120 -0
- defchord-0.1.11/.github/scripts/tests/test_distributions.py +117 -0
- defchord-0.1.11/.github/scripts/tests/test_release.py +239 -0
- defchord-0.1.11/.github/workflows/ci.yml +431 -0
- defchord-0.1.11/.github/workflows/create-issues-from-reviews.yml +55 -0
- defchord-0.1.11/.github/workflows/create-pr-from-issue.yml +78 -0
- defchord-0.1.11/.gitignore +56 -0
- defchord-0.1.11/LICENSE +674 -0
- defchord-0.1.11/PKG-INFO +80 -0
- defchord-0.1.11/README.en.md +61 -0
- defchord-0.1.11/README.md +61 -0
- defchord-0.1.11/README.setup.md +47 -0
- defchord-0.1.11/build/core/DefChord.egg-info/SOURCES.txt +301 -0
- defchord-0.1.11/docs/ErrorHandling.en.md +209 -0
- defchord-0.1.11/docs/ErrorHandling.md +209 -0
- defchord-0.1.11/docs/ExtensionsAndServers.en.md +98 -0
- defchord-0.1.11/docs/ExtensionsAndServers.md +98 -0
- defchord-0.1.11/docs/GettingStarted.en.md +130 -0
- defchord-0.1.11/docs/GettingStarted.md +130 -0
- defchord-0.1.11/docs/Lifecycle.en.md +145 -0
- defchord-0.1.11/docs/Lifecycle.md +145 -0
- defchord-0.1.11/docs/Packaging.en.md +80 -0
- defchord-0.1.11/docs/Packaging.md +80 -0
- defchord-0.1.11/docs/README.en.md +50 -0
- defchord-0.1.11/docs/README.md +50 -0
- defchord-0.1.11/docs/RoutingAndRequests.en.md +327 -0
- defchord-0.1.11/docs/RoutingAndRequests.md +327 -0
- defchord-0.1.11/docs/StreamingAndWebSockets.en.md +197 -0
- defchord-0.1.11/docs/StreamingAndWebSockets.md +197 -0
- defchord-0.1.11/instructions/CODE.instructions.md +32 -0
- defchord-0.1.11/instructions/DOCS.instructions.md +55 -0
- defchord-0.1.11/instructions/README.instructions.md +36 -0
- defchord-0.1.11/issues/feature/2/ISSUE.md +11 -0
- defchord-0.1.11/issues/feature/2/README.md +182 -0
- defchord-0.1.11/issues/feature/2/REQUIREMENTS.md +212 -0
- defchord-0.1.11/issues/feature/21/CHANGELOG.md +9 -0
- defchord-0.1.11/issues/feature/21/IMPLEMENTS.md +44 -0
- defchord-0.1.11/issues/feature/21/PLAN.md +143 -0
- defchord-0.1.11/issues/feature/21/README.md +115 -0
- defchord-0.1.11/issues/feature/21/REQUIREMENTS.md +116 -0
- defchord-0.1.11/issues/feature/21/tasks/001./354/230/244/353/245/230/354/235/221/353/213/265/352/265/254/355/230/204.md +38 -0
- defchord-0.1.11/issues/feature/21/tasks/002./354/230/244/353/245/230/354/235/221/353/213/265/354/203/230/355/224/214.md +28 -0
- defchord-0.1.11/issues/feature/3/IMPLEMENTS.md +118 -0
- defchord-0.1.11/issues/feature/3/ISSUE.md +9 -0
- defchord-0.1.11/issues/feature/3/README.md +48 -0
- defchord-0.1.11/issues/feature/3/REQUIREMENTS.md +332 -0
- defchord-0.1.11/issues/feature/4/IMPLEMENTS.md +51 -0
- defchord-0.1.11/issues/feature/4/ISSUE.md +13 -0
- defchord-0.1.11/issues/feature/4/PLAN.md +111 -0
- defchord-0.1.11/issues/feature/4/README.md +25 -0
- defchord-0.1.11/issues/feature/4/REQUIREMENTS.md +196 -0
- defchord-0.1.11/issues/feature/5/IMPLEMENTS.md +116 -0
- defchord-0.1.11/issues/feature/5/ISSUE.md +13 -0
- defchord-0.1.11/issues/feature/5/PLAN.md +128 -0
- defchord-0.1.11/issues/feature/5/README.md +54 -0
- defchord-0.1.11/issues/feature/5/REQUIREMENTS.md +182 -0
- defchord-0.1.11/issues/feature/6/IMPLEMENTS.md +160 -0
- defchord-0.1.11/issues/feature/6/ISSUE.md +14 -0
- defchord-0.1.11/issues/feature/6/PLAN.md +209 -0
- defchord-0.1.11/issues/feature/6/README.md +47 -0
- defchord-0.1.11/issues/feature/6/REQUIREMENTS.md +259 -0
- defchord-0.1.11/issues/fix/25/CHANGELOG.md +31 -0
- defchord-0.1.11/issues/fix/25/IMPLEMENTS.md +47 -0
- defchord-0.1.11/issues/fix/25/PLAN.md +33 -0
- defchord-0.1.11/issues/fix/25/README.md +90 -0
- defchord-0.1.11/issues/fix/25/REQUIREMENTS.md +43 -0
- defchord-0.1.11/issues/fix/25/TASKS.md +66 -0
- defchord-0.1.11/issues/fix/25/implements/1793294516718.md +7 -0
- defchord-0.1.11/issues/fix/25/implements/1793295445977.md +7 -0
- defchord-0.1.11/issues/fix/25/implements/1793295838894.md +7 -0
- defchord-0.1.11/issues/fix/25/implements/1793296500294.md +5 -0
- defchord-0.1.11/issues/fix/25/implements/1793299630934.md +13 -0
- defchord-0.1.11/issues/fix/25/implements/1793301537857.md +9 -0
- defchord-0.1.11/issues/fix/25/implements/1793302547667.md +7 -0
- defchord-0.1.11/issues/fix/25/implements/1793303776533.md +7 -0
- defchord-0.1.11/issues/fix/25/implements/1793327181553.md +11 -0
- defchord-0.1.11/issues/fix/25/implements/1793329241418.md +9 -0
- defchord-0.1.11/issues/fix/25/implements/1793516005513.md +11 -0
- defchord-0.1.11/issues/fix/25/implements/1793516879579.md +5 -0
- defchord-0.1.11/issues/fix/25/implements/1793518878749.md +7 -0
- defchord-0.1.11/issues/fix/25/tasks/1793294230193.md +7 -0
- defchord-0.1.11/issues/fix/25/tasks/1793295445974.md +15 -0
- defchord-0.1.11/issues/fix/25/tasks/1793295838891.md +16 -0
- defchord-0.1.11/issues/fix/25/tasks/1793296500297.md +3 -0
- defchord-0.1.11/issues/fix/25/tasks/1793297795665.md +9 -0
- defchord-0.1.11/issues/fix/25/tasks/1793299630937.md +15 -0
- defchord-0.1.11/issues/fix/25/tasks/1793301829544.md +21 -0
- defchord-0.1.11/issues/fix/25/tasks/1793302844697.md +15 -0
- defchord-0.1.11/issues/fix/25/tasks/1793303776534.md +26 -0
- defchord-0.1.11/issues/fix/25/tasks/1793327181554.md +16 -0
- defchord-0.1.11/issues/fix/25/tasks/1793327685705.md +10 -0
- defchord-0.1.11/issues/fix/25/tasks/1793328011410.md +7 -0
- defchord-0.1.11/issues/fix/25/tasks/1793329241419.md +9 -0
- defchord-0.1.11/issues/fix/25/tasks/1793515509173.md +7 -0
- defchord-0.1.11/issues/fix/25/tasks/1793516005514.md +11 -0
- defchord-0.1.11/issues/fix/25/tasks/1793516879580.md +9 -0
- defchord-0.1.11/issues/fix/25/tasks/1793518878750.md +11 -0
- defchord-0.1.11/issues/fix/28/CHANGELOG.md +13 -0
- defchord-0.1.11/issues/fix/28/IMPLEMENTS.md +17 -0
- defchord-0.1.11/issues/fix/28/PLAN.md +14 -0
- defchord-0.1.11/issues/fix/28/README.md +66 -0
- defchord-0.1.11/issues/fix/28/REQUIREMENTS.md +20 -0
- defchord-0.1.11/issues/fix/28/TASKS.md +13 -0
- defchord-0.1.11/issues/fix/28/implements/1793542993332.md +7 -0
- defchord-0.1.11/issues/fix/28/implements/1793546326099.md +5 -0
- defchord-0.1.11/issues/fix/28/tasks/1793542326080.md +15 -0
- defchord-0.1.11/issues/fix/28/tasks/1793542490156.md +12 -0
- defchord-0.1.11/issues/fix/28/tasks/1793543293299.md +13 -0
- defchord-0.1.11/issues/fix/28/tasks/1793544105753.md +10 -0
- defchord-0.1.11/issues/fix/28/tasks/1793546326100.md +10 -0
- defchord-0.1.11/issues/task/14/ISSUE.md +30 -0
- defchord-0.1.11/issues/task/14/PLAN.md +35 -0
- defchord-0.1.11/issues/task/14/README.md +7 -0
- defchord-0.1.11/issues/task/14/REQUIREMENTS.md +84 -0
- defchord-0.1.11/issues/task/14/TASK.md +22 -0
- defchord-0.1.11/issues/task/17/CHANGELOG.md +3 -0
- defchord-0.1.11/issues/task/17/IMPLEMENTS.md +24 -0
- defchord-0.1.11/issues/task/17/PLAN.md +37 -0
- defchord-0.1.11/issues/task/17/README.md +51 -0
- defchord-0.1.11/issues/task/17/REQUIREMENTS.md +73 -0
- defchord-0.1.11/issues/task/19/CHANGELOG.md +11 -0
- defchord-0.1.11/issues/task/19/IMPLEMENTS.md +79 -0
- defchord-0.1.11/issues/task/19/PLAN.md +59 -0
- defchord-0.1.11/issues/task/19/README.md +49 -0
- defchord-0.1.11/issues/task/19/REQUIREMENTS.md +79 -0
- defchord-0.1.11/issues/task/19/tasks/001.Origin/352/263/274/354/235/270/354/246/235.md +24 -0
- defchord-0.1.11/issues/task/19/tasks/002./354/235/221/353/213/265/355/233/205/352/263/274/354/235/270/354/246/235/355/201/264/353/236/230/354/212/244.md +25 -0
- defchord-0.1.11/issues/task/19/tasks/003./353/247/244/353/211/264/354/226/274/352/265/254/354/204/261/354/236/254/355/216/270.md +27 -0
- defchord-0.1.11/issues/task/19/tasks/004./354/235/221/353/213/265/354/230/210/354/240/234/353/263/264/352/260/225.md +23 -0
- defchord-0.1.11/issues/task/19/tasks/005./353/247/244/353/211/264/354/226/274/354/240/234/353/252/251/354/210/230/354/240/225.md +21 -0
- defchord-0.1.11/issues/task/19/tasks/006./354/235/221/353/213/265/355/233/205/354/230/210/354/240/234.md +22 -0
- defchord-0.1.11/issues/task/23/CHANGELOG.md +9 -0
- defchord-0.1.11/issues/task/23/IMPLEMENTS.md +27 -0
- defchord-0.1.11/issues/task/23/PLAN.md +24 -0
- defchord-0.1.11/issues/task/23/README.md +55 -0
- defchord-0.1.11/issues/task/23/REQUIREMENTS.md +38 -0
- defchord-0.1.11/issues/task/23/TASKS.md +10 -0
- defchord-0.1.11/issues/task/23/docs/CopilotReviewIssues.md +76 -0
- defchord-0.1.11/issues/task/23/docs/CopilotReviewIssuesSetup.md +56 -0
- defchord-0.1.11/issues/task/23/implements/1793291844133.md +10 -0
- defchord-0.1.11/issues/task/23/tasks/1793291844134.md +24 -0
- defchord-0.1.11/issues/task/23/tasks/1793292234123.md +5 -0
- defchord-0.1.11/issues/task/8/IMPLEMENTS.md +39 -0
- defchord-0.1.11/issues/task/8/ISSUE.md +20 -0
- defchord-0.1.11/issues/task/8/PLAN.md +20 -0
- defchord-0.1.11/issues/task/8/README.md +7 -0
- defchord-0.1.11/issues/task/8/REQUIREMENTS.md +58 -0
- defchord-0.1.11/pyproject.toml +4 -0
- defchord-0.1.11/samples/README.md +173 -0
- defchord-0.1.11/samples/Sample.py +316 -0
- defchord-0.1.11/samples/__init__.py +1 -0
- defchord-0.1.11/samples/res/css/sample.css +28 -0
- defchord-0.1.11/samples/res/favicon.ico +0 -0
- defchord-0.1.11/samples/res/html/welcome.html +452 -0
- defchord-0.1.11/samples/res/images/sample.jpg +0 -0
- defchord-0.1.11/samples/res/images/sample.png +0 -0
- defchord-0.1.11/samples/runners/Authentication.py +293 -0
- defchord-0.1.11/samples/runners/ContentValidation.py +112 -0
- defchord-0.1.11/samples/runners/Requests.py +430 -0
- defchord-0.1.11/samples/runners/Streaming.py +228 -0
- defchord-0.1.11/samples/runners/__init__.py +1 -0
- defchord-0.1.11/samples/scripts/DescriptionToFile.py +36 -0
- defchord-0.1.11/samples/scripts/__init__.py +1 -0
- defchord-0.1.11/setup.cfg +4 -0
- defchord-0.1.11/setup.py +300 -0
- defchord-0.1.11/src/Adapter/Implements/Gunicorn/Server.py +152 -0
- defchord-0.1.11/src/Adapter/Implements/Gunicorn/Transport.py +171 -0
- defchord-0.1.11/src/Adapter/Implements/Gunicorn/__init__.py +5 -0
- defchord-0.1.11/src/Adapter/Implements/Python/Server.py +273 -0
- defchord-0.1.11/src/Adapter/Implements/Python/__init__.py +5 -0
- defchord-0.1.11/src/Adapter/Implements/Uvicorn/HTTP.py +256 -0
- defchord-0.1.11/src/Adapter/Implements/Uvicorn/Portal.py +65 -0
- defchord-0.1.11/src/Adapter/Implements/Uvicorn/Server.py +137 -0
- defchord-0.1.11/src/Adapter/Implements/Uvicorn/WebSocket.py +222 -0
- defchord-0.1.11/src/Adapter/Implements/Uvicorn/__init__.py +5 -0
- defchord-0.1.11/src/Adapter/Implements/__init__.py +3 -0
- defchord-0.1.11/src/Adapter/RequestHandler.py +109 -0
- defchord-0.1.11/src/Adapter/Server.py +54 -0
- defchord-0.1.11/src/Adapter/WSGI.py +219 -0
- defchord-0.1.11/src/Adapter/__init__.py +5 -0
- defchord-0.1.11/src/Application.py +696 -0
- defchord-0.1.11/src/Body.py +50 -0
- defchord-0.1.11/src/Content.py +18 -0
- defchord-0.1.11/src/Credentials.py +245 -0
- defchord-0.1.11/src/CrossOriginResourceSharing.py +107 -0
- defchord-0.1.11/src/Descriptor/DataObject.py +409 -0
- defchord-0.1.11/src/Descriptor/Types.py +248 -0
- defchord-0.1.11/src/Descriptor/Value.py +188 -0
- defchord-0.1.11/src/Descriptor/__init__.py +172 -0
- defchord-0.1.11/src/Error.py +66 -0
- defchord-0.1.11/src/Extension.py +191 -0
- defchord-0.1.11/src/Extensions/File.py +95 -0
- defchord-0.1.11/src/Extensions/FileSystem.py +195 -0
- defchord-0.1.11/src/Extensions/Metrics.py +511 -0
- defchord-0.1.11/src/Extensions/Ping.py +93 -0
- defchord-0.1.11/src/Extensions/Specifications.py +342 -0
- defchord-0.1.11/src/Extensions/Status.html +207 -0
- defchord-0.1.11/src/Extensions/Status.py +110 -0
- defchord-0.1.11/src/Extensions/Swagger.html +77 -0
- defchord-0.1.11/src/Extensions/Swagger.py +117 -0
- defchord-0.1.11/src/Extensions/Utils/Routes.py +42 -0
- defchord-0.1.11/src/Extensions/Utils/__init__.py +43 -0
- defchord-0.1.11/src/Extensions/__init__.py +21 -0
- defchord-0.1.11/src/IO/Readers/ChunkedStream.py +106 -0
- defchord-0.1.11/src/IO/Readers/ContentReader.py +36 -0
- defchord-0.1.11/src/IO/Readers/ContentReaders.py +241 -0
- defchord-0.1.11/src/IO/Readers/__init__.py +25 -0
- defchord-0.1.11/src/IO/RequestReader.py +125 -0
- defchord-0.1.11/src/IO/ResponseWriter.py +242 -0
- defchord-0.1.11/src/IO/WebSocket/WebSocket.py +288 -0
- defchord-0.1.11/src/IO/WebSocket/WebSocketError.py +17 -0
- defchord-0.1.11/src/IO/WebSocket/WebSocketFrame.py +68 -0
- defchord-0.1.11/src/IO/WebSocket/WebSocketFrameReader.py +98 -0
- defchord-0.1.11/src/IO/WebSocket/WebSocketHandshake.py +94 -0
- defchord-0.1.11/src/IO/WebSocket/__init__.py +13 -0
- defchord-0.1.11/src/IO/Writers/ChunkedStreamWriter.py +19 -0
- defchord-0.1.11/src/IO/Writers/ServerSentEvents.py +41 -0
- defchord-0.1.11/src/IO/Writers/ServerSentEventsWriter.py +67 -0
- defchord-0.1.11/src/IO/Writers/StreamWriter.py +57 -0
- defchord-0.1.11/src/IO/Writers/__init__.py +11 -0
- defchord-0.1.11/src/IO/__init__.py +7 -0
- defchord-0.1.11/src/Request.py +110 -0
- defchord-0.1.11/src/RequestRunner.py +261 -0
- defchord-0.1.11/src/Response.py +89 -0
- defchord-0.1.11/src/ResponseSpecification.py +23 -0
- defchord-0.1.11/src/Responses/ResponseFile.py +108 -0
- defchord-0.1.11/src/Responses/__init__.py +63 -0
- defchord-0.1.11/src/Route.py +55 -0
- defchord-0.1.11/src/Router.py +48 -0
- defchord-0.1.11/src/Runners/RunExtension.py +129 -0
- defchord-0.1.11/src/Runners/RunFactory.py +26 -0
- defchord-0.1.11/src/Runners/RunOptions.py +77 -0
- defchord-0.1.11/src/Runners/RunRequest.py +208 -0
- defchord-0.1.11/src/Runners/__init__.py +5 -0
- defchord-0.1.11/src/Startup.py +106 -0
- defchord-0.1.11/src/Utils/FileSystemObject/Configuration.py +15 -0
- defchord-0.1.11/src/Utils/FileSystemObject/Connection.py +57 -0
- defchord-0.1.11/src/Utils/FileSystemObject/File.py +41 -0
- defchord-0.1.11/src/Utils/FileSystemObject/Implements/FileSystem/Configuration.py +15 -0
- defchord-0.1.11/src/Utils/FileSystemObject/Implements/FileSystem/Connection.py +115 -0
- defchord-0.1.11/src/Utils/FileSystemObject/Implements/FileSystem/File.py +77 -0
- defchord-0.1.11/src/Utils/FileSystemObject/Implements/FileSystem/__init__.py +11 -0
- defchord-0.1.11/src/Utils/FileSystemObject/Implements/__init__.py +3 -0
- defchord-0.1.11/src/Utils/FileSystemObject/__init__.py +11 -0
- defchord-0.1.11/src/Utils/Loader.py +81 -0
- defchord-0.1.11/src/Utils/__init__.py +3 -0
- defchord-0.1.11/src/Validator/Pattern.py +36 -0
- defchord-0.1.11/src/Validator/Patterns/Array.py +30 -0
- defchord-0.1.11/src/Validator/Patterns/Common.py +92 -0
- defchord-0.1.11/src/Validator/Patterns/Compare.py +180 -0
- defchord-0.1.11/src/Validator/Patterns/Condition.py +60 -0
- defchord-0.1.11/src/Validator/Patterns/DataObject.py +85 -0
- defchord-0.1.11/src/Validator/Patterns/DateTime.py +111 -0
- defchord-0.1.11/src/Validator/Patterns/Number.py +43 -0
- defchord-0.1.11/src/Validator/Patterns/Object.py +150 -0
- defchord-0.1.11/src/Validator/Patterns/Size.py +110 -0
- defchord-0.1.11/src/Validator/Patterns/String.py +85 -0
- defchord-0.1.11/src/Validator/Patterns/Type.py +350 -0
- defchord-0.1.11/src/Validator/Patterns/__init__.py +137 -0
- defchord-0.1.11/src/Validator/Validate.py +29 -0
- defchord-0.1.11/src/Validator/Validator.py +30 -0
- defchord-0.1.11/src/Validator/__init__.py +11 -0
- defchord-0.1.11/src/Validators.py +255 -0
- defchord-0.1.11/src/__init__.py +83 -0
- defchord-0.1.11/tests/test_adapters.py +893 -0
- defchord-0.1.11/tests/test_application_hooks.py +466 -0
- defchord-0.1.11/tests/test_builtin_factories.py +639 -0
- defchord-0.1.11/tests/test_content.py +250 -0
- defchord-0.1.11/tests/test_core.py +538 -0
- defchord-0.1.11/tests/test_exports.py +95 -0
- defchord-0.1.11/tests/test_extension_hooks.py +869 -0
- defchord-0.1.11/tests/test_extensions.py +731 -0
- defchord-0.1.11/tests/test_features.py +409 -0
- defchord-0.1.11/tests/test_files.py +250 -0
- defchord-0.1.11/tests/test_independence.py +111 -0
- defchord-0.1.11/tests/test_loading.py +61 -0
- defchord-0.1.11/tests/test_logging.py +873 -0
- defchord-0.1.11/tests/test_request_runner_hooks.py +1197 -0
- defchord-0.1.11/tests/test_samples.py +711 -0
- defchord-0.1.11/tests/test_server.py +266 -0
- defchord-0.1.11/tests/test_sse.py +178 -0
- defchord-0.1.11/tests/test_startup.py +296 -0
- defchord-0.1.11/tests/test_transport_conformance.py +504 -0
- defchord-0.1.11/tests/test_uvicorn_transport.py +90 -0
- defchord-0.1.11/tests/test_websocket.py +512 -0
- defchord-0.1.11/tests/test_writers.py +914 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
from errno import (
|
|
2
|
+
EACCES,
|
|
3
|
+
EAGAIN,
|
|
4
|
+
EEXIST,
|
|
5
|
+
ENOTEMPTY,
|
|
6
|
+
EPERM,
|
|
7
|
+
)
|
|
8
|
+
from importlib.metadata import distributions
|
|
9
|
+
from json import (
|
|
10
|
+
dumps,
|
|
11
|
+
loads,
|
|
12
|
+
)
|
|
13
|
+
from os import (
|
|
14
|
+
link,
|
|
15
|
+
symlink,
|
|
16
|
+
)
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
import sys
|
|
19
|
+
from tempfile import TemporaryDirectory
|
|
20
|
+
from time import (
|
|
21
|
+
monotonic,
|
|
22
|
+
sleep,
|
|
23
|
+
)
|
|
24
|
+
from typing import BinaryIO
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def relative_path(
|
|
28
|
+
value: str,
|
|
29
|
+
project: str,
|
|
30
|
+
) -> Path:
|
|
31
|
+
path: Path = Path(value)
|
|
32
|
+
if path.is_absolute() or '..' in path.parts or not path.parts or path.parts[0] != project:
|
|
33
|
+
raise ValueError('Invalid editable product path: {!r}'.format(value))
|
|
34
|
+
return path
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def collect_files(
|
|
38
|
+
site: Path,
|
|
39
|
+
project: str,
|
|
40
|
+
names: tuple[str, ...],
|
|
41
|
+
) -> dict[str, str]:
|
|
42
|
+
selected = {
|
|
43
|
+
dist.metadata['Name']: dist
|
|
44
|
+
for dist in distributions(path=[str(site)])
|
|
45
|
+
if dist.metadata['Name'] in names
|
|
46
|
+
}
|
|
47
|
+
if project not in selected:
|
|
48
|
+
raise RuntimeError('Editable {} requires its core distribution'.format(project))
|
|
49
|
+
core = selected[project]
|
|
50
|
+
if core.read_text('editable-selection.json') is not None:
|
|
51
|
+
conflicts: list[str] = [name for name in selected if name != project]
|
|
52
|
+
if conflicts:
|
|
53
|
+
raise RuntimeError('Remove legacy implementation distributions before using EXTRAS editable selection: {}'.format(
|
|
54
|
+
', '.join(conflicts),
|
|
55
|
+
))
|
|
56
|
+
if core.read_text('editable-files.json') is None:
|
|
57
|
+
raise RuntimeError('Install the {} core with pip install -e . before its editable implementations'.format(project))
|
|
58
|
+
files: dict[str, str] = {}
|
|
59
|
+
for name, dist in selected.items():
|
|
60
|
+
if dist.version != core.version:
|
|
61
|
+
raise RuntimeError('Editable distribution version mismatch: {}'.format(name))
|
|
62
|
+
manifest = dist.read_text('editable-files.json')
|
|
63
|
+
if manifest is not None:
|
|
64
|
+
mapping: dict[str, str] = loads(manifest)
|
|
65
|
+
else:
|
|
66
|
+
if dist.files is None:
|
|
67
|
+
raise RuntimeError('Missing installed file record: {}'.format(name))
|
|
68
|
+
mapping = {
|
|
69
|
+
str(path).replace(
|
|
70
|
+
'\\',
|
|
71
|
+
'/',
|
|
72
|
+
): str(Path(str(dist.locate_file(path))).resolve())
|
|
73
|
+
for path in dist.files
|
|
74
|
+
if path.parts[0] == project and '__pycache__' not in path.parts
|
|
75
|
+
}
|
|
76
|
+
for relative, source in mapping.items():
|
|
77
|
+
relative_path(
|
|
78
|
+
relative,
|
|
79
|
+
project,
|
|
80
|
+
)
|
|
81
|
+
if relative in files:
|
|
82
|
+
raise RuntimeError('Duplicate editable file ownership: {}'.format(relative))
|
|
83
|
+
if not Path(source).is_absolute() or not Path(source).is_file():
|
|
84
|
+
raise FileNotFoundError('Editable source is missing; reinstall its distribution: {}'.format(source))
|
|
85
|
+
files[relative] = source
|
|
86
|
+
return files
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def create_link(
|
|
90
|
+
source: Path,
|
|
91
|
+
destination: Path,
|
|
92
|
+
) -> None:
|
|
93
|
+
try:
|
|
94
|
+
symlink(
|
|
95
|
+
source,
|
|
96
|
+
destination,
|
|
97
|
+
)
|
|
98
|
+
except OSError as error:
|
|
99
|
+
if error.errno not in (
|
|
100
|
+
EACCES,
|
|
101
|
+
EPERM,
|
|
102
|
+
) and getattr(
|
|
103
|
+
error,
|
|
104
|
+
'winerror',
|
|
105
|
+
None,
|
|
106
|
+
) != 1314:
|
|
107
|
+
raise
|
|
108
|
+
link(
|
|
109
|
+
source,
|
|
110
|
+
destination,
|
|
111
|
+
)
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def write_state(
|
|
116
|
+
state: Path,
|
|
117
|
+
files: dict[str, str],
|
|
118
|
+
) -> None:
|
|
119
|
+
temporary: Path = state.with_suffix('.new')
|
|
120
|
+
temporary.write_text(
|
|
121
|
+
dumps(
|
|
122
|
+
files,
|
|
123
|
+
sort_keys=True,
|
|
124
|
+
),
|
|
125
|
+
encoding='utf-8',
|
|
126
|
+
)
|
|
127
|
+
temporary.replace(state)
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def invalidate_bytecode(path: Path) -> None:
|
|
132
|
+
if path.suffix == '.py':
|
|
133
|
+
cache: Path = path.parent / '__pycache__'
|
|
134
|
+
if cache.is_dir():
|
|
135
|
+
for bytecode in cache.glob(path.stem + '.*.pyc'):
|
|
136
|
+
bytecode.unlink()
|
|
137
|
+
return
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def refresh(
|
|
141
|
+
view: Path,
|
|
142
|
+
project: str,
|
|
143
|
+
files: dict[str, str],
|
|
144
|
+
) -> None:
|
|
145
|
+
state: Path = view / 'files.json'
|
|
146
|
+
previous: dict[str, str] = loads(state.read_text(encoding='utf-8')) if state.is_file() else {}
|
|
147
|
+
if files == previous and all(
|
|
148
|
+
(view / relative).is_file() and (view / relative).samefile(source)
|
|
149
|
+
for relative, source in files.items()
|
|
150
|
+
):
|
|
151
|
+
return
|
|
152
|
+
paths: dict[str, Path] = {}
|
|
153
|
+
for relative in previous.keys() | files.keys():
|
|
154
|
+
paths[relative] = view / relative_path(
|
|
155
|
+
relative,
|
|
156
|
+
project,
|
|
157
|
+
)
|
|
158
|
+
touched: set[Path] = set()
|
|
159
|
+
directories: set[Path] = set()
|
|
160
|
+
# Record ownership before adding links so interrupted refreshes remain recoverable.
|
|
161
|
+
ownership: dict[str, str] = {
|
|
162
|
+
**previous,
|
|
163
|
+
**files,
|
|
164
|
+
}
|
|
165
|
+
if ownership != previous:
|
|
166
|
+
write_state(
|
|
167
|
+
state,
|
|
168
|
+
ownership,
|
|
169
|
+
)
|
|
170
|
+
for relative, source in files.items():
|
|
171
|
+
path: Path = paths[relative]
|
|
172
|
+
if path.is_file() and path.samefile(source):
|
|
173
|
+
continue
|
|
174
|
+
path.parent.mkdir(
|
|
175
|
+
parents=True,
|
|
176
|
+
exist_ok=True,
|
|
177
|
+
)
|
|
178
|
+
with TemporaryDirectory(dir=path.parent) as staging:
|
|
179
|
+
replacement: Path = Path(staging) / path.name
|
|
180
|
+
create_link(
|
|
181
|
+
Path(source),
|
|
182
|
+
replacement,
|
|
183
|
+
)
|
|
184
|
+
invalidate_bytecode(path)
|
|
185
|
+
replacement.replace(path)
|
|
186
|
+
if path.suffix == '.py' and (path.parent / '__pycache__').is_dir():
|
|
187
|
+
directories.add(path.parent / '__pycache__')
|
|
188
|
+
for relative in previous.keys() - files.keys():
|
|
189
|
+
path = paths[relative]
|
|
190
|
+
if path.exists() or path.is_symlink():
|
|
191
|
+
path.unlink()
|
|
192
|
+
touched.add(path)
|
|
193
|
+
directories.update(parent for parent in path.parents if parent != view and view in parent.parents)
|
|
194
|
+
for path in touched:
|
|
195
|
+
invalidate_bytecode(path)
|
|
196
|
+
if path.suffix == '.py':
|
|
197
|
+
cache: Path = path.parent / '__pycache__'
|
|
198
|
+
if cache.is_dir():
|
|
199
|
+
directories.add(cache)
|
|
200
|
+
for directory in sorted(
|
|
201
|
+
directories,
|
|
202
|
+
key=lambda path: len(path.parts),
|
|
203
|
+
reverse=True,
|
|
204
|
+
):
|
|
205
|
+
if directory.exists():
|
|
206
|
+
try:
|
|
207
|
+
directory.rmdir()
|
|
208
|
+
except OSError as error:
|
|
209
|
+
if error.errno not in (
|
|
210
|
+
ENOTEMPTY,
|
|
211
|
+
EEXIST,
|
|
212
|
+
):
|
|
213
|
+
raise
|
|
214
|
+
write_state(
|
|
215
|
+
state,
|
|
216
|
+
files,
|
|
217
|
+
)
|
|
218
|
+
return
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def acquire_lock(
|
|
222
|
+
stream: BinaryIO,
|
|
223
|
+
path: Path,
|
|
224
|
+
) -> None:
|
|
225
|
+
deadline: float = monotonic() + 30
|
|
226
|
+
while True:
|
|
227
|
+
try:
|
|
228
|
+
if sys.platform == 'win32':
|
|
229
|
+
from msvcrt import (
|
|
230
|
+
LK_NBLCK,
|
|
231
|
+
locking,
|
|
232
|
+
)
|
|
233
|
+
locking(
|
|
234
|
+
stream.fileno(),
|
|
235
|
+
LK_NBLCK,
|
|
236
|
+
1,
|
|
237
|
+
)
|
|
238
|
+
else:
|
|
239
|
+
from fcntl import (
|
|
240
|
+
LOCK_EX,
|
|
241
|
+
LOCK_NB,
|
|
242
|
+
flock,
|
|
243
|
+
)
|
|
244
|
+
flock(
|
|
245
|
+
stream.fileno(),
|
|
246
|
+
LOCK_EX | LOCK_NB,
|
|
247
|
+
)
|
|
248
|
+
return
|
|
249
|
+
except OSError as error:
|
|
250
|
+
if error.errno not in (
|
|
251
|
+
EACCES,
|
|
252
|
+
EAGAIN,
|
|
253
|
+
):
|
|
254
|
+
raise
|
|
255
|
+
if monotonic() >= deadline:
|
|
256
|
+
raise TimeoutError('Editable view is locked: {}'.format(path)) from error
|
|
257
|
+
sleep(0.05)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def activate(
|
|
261
|
+
project: str,
|
|
262
|
+
names: tuple[str, ...],
|
|
263
|
+
) -> None:
|
|
264
|
+
"""Expose only installed files through a static, environment-local import root."""
|
|
265
|
+
site: Path = Path(__file__).resolve().parent
|
|
266
|
+
view: Path = site / ('__editable_{}_view'.format(project.lower()))
|
|
267
|
+
lock: Path = view.with_suffix('.lock')
|
|
268
|
+
with lock.open('a+b') as stream:
|
|
269
|
+
if stream.tell() == 0:
|
|
270
|
+
stream.write(b'\0')
|
|
271
|
+
stream.flush()
|
|
272
|
+
stream.seek(0)
|
|
273
|
+
acquire_lock(
|
|
274
|
+
stream,
|
|
275
|
+
lock,
|
|
276
|
+
)
|
|
277
|
+
view.mkdir(exist_ok=True)
|
|
278
|
+
refresh(
|
|
279
|
+
view,
|
|
280
|
+
project,
|
|
281
|
+
collect_files(
|
|
282
|
+
site,
|
|
283
|
+
project,
|
|
284
|
+
names,
|
|
285
|
+
),
|
|
286
|
+
)
|
|
287
|
+
return
|
|
File without changes
|