py-serverless-kit 0.1.1__tar.gz → 0.1.3__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.
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/.gitignore +29 -28
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/CHANGELOG.md +52 -34
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/CONTRIBUTING.md +13 -13
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/LICENSE +21 -21
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/PKG-INFO +1 -1
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/deploy_docs/CONTRIBUTING.md +158 -158
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/docs/README.md +22 -22
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/docs/cli.md +175 -175
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/docs/configuration.md +245 -245
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/docs/dashboard.md +44 -44
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/docs/events.md +213 -213
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/docs/getting-started.md +176 -176
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/docs/handlers.md +219 -219
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/docs/local-development.md +98 -98
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/docs/migrating-from-aws.md +98 -98
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/docs/providers.md +358 -354
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/docs/workflows.md +180 -180
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/01-hello-http/README.md +53 -53
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/01-hello-http/app/handlers.py +15 -15
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/01-hello-http/requirements.txt +1 -1
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/02-rest-api/README.md +77 -77
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/02-rest-api/app/handlers.py +116 -116
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/02-rest-api/app/store.py +50 -50
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/02-rest-api/pskit.yml +82 -82
- {py_serverless_kit-0.1.1/examples/05-storage-events → py_serverless_kit-0.1.3/examples/02-rest-api}/requirements.txt +1 -1
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/03-scheduled-jobs/README.md +56 -56
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/03-scheduled-jobs/app/jobs.py +51 -51
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/03-scheduled-jobs/pskit.yml +49 -49
- {py_serverless_kit-0.1.1/examples/02-rest-api → py_serverless_kit-0.1.3/examples/03-scheduled-jobs}/requirements.txt +1 -1
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/04-queue-worker/README.md +80 -80
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/04-queue-worker/app/worker.py +75 -75
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/04-queue-worker/pskit.yml +39 -39
- {py_serverless_kit-0.1.1/examples/03-scheduled-jobs → py_serverless_kit-0.1.3/examples/04-queue-worker}/requirements.txt +1 -1
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/05-storage-events/README.md +58 -58
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/05-storage-events/app/files.py +51 -51
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/05-storage-events/pskit.yml +54 -54
- {py_serverless_kit-0.1.1/examples/04-queue-worker → py_serverless_kit-0.1.3/examples/05-storage-events}/requirements.txt +1 -1
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/06-pubsub-topic/README.md +62 -62
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/06-pubsub-topic/app/subscribers.py +41 -41
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/06-pubsub-topic/pskit.yml +27 -27
- py_serverless_kit-0.1.3/examples/06-pubsub-topic/requirements.txt +1 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/07-workflow-orders/README.md +110 -110
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/07-workflow-orders/app/orders.py +84 -84
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/07-workflow-orders/events/b2b.json +5 -5
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/07-workflow-orders/events/declined.json +5 -5
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/07-workflow-orders/events/happy.json +9 -9
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/07-workflow-orders/pskit.yml +99 -99
- py_serverless_kit-0.1.3/examples/07-workflow-orders/requirements.txt +1 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/08-multi-cloud/README.md +71 -71
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/08-multi-cloud/app/handlers.py +45 -45
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/08-multi-cloud/pskit.aws.yml +15 -15
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/08-multi-cloud/pskit.azure.yml +12 -12
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/08-multi-cloud/pskit.gcp.yml +11 -11
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/08-multi-cloud/pskit.yml +90 -90
- py_serverless_kit-0.1.3/examples/08-multi-cloud/requirements.txt +1 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/09-function-invoke/README.md +61 -61
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/09-function-invoke/app/quotes.py +44 -44
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/09-function-invoke/pskit.yml +41 -41
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/09-function-invoke/requirements.txt +1 -1
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/10-stages-and-config/.env.example +5 -5
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/10-stages-and-config/README.md +78 -78
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/10-stages-and-config/app/handlers.py +17 -17
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/10-stages-and-config/app/settings.py +37 -37
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/10-stages-and-config/config/limits.json +5 -5
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/10-stages-and-config/pskit.yml +58 -58
- py_serverless_kit-0.1.3/examples/10-stages-and-config/requirements.txt +1 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/11-custom-terraform/README.md +83 -83
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/11-custom-terraform/app/handlers.py +21 -21
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/11-custom-terraform/app/repository.py +56 -56
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/11-custom-terraform/pskit.yml +64 -64
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/11-custom-terraform/requirements.txt +1 -1
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/11-custom-terraform/scripts/smoke_test.py +26 -26
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/11-custom-terraform/tests/test_orders.py +11 -11
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/12-async-and-context/README.md +61 -61
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/12-async-and-context/app/handlers.py +65 -65
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/12-async-and-context/pskit.yml +30 -30
- py_serverless_kit-0.1.3/examples/12-async-and-context/requirements.txt +1 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/13-migrate-from-aws-lambda/README.md +120 -120
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/13-migrate-from-aws-lambda/after/app/orders.py +57 -57
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/13-migrate-from-aws-lambda/after/pskit.yml +55 -55
- py_serverless_kit-0.1.3/examples/13-migrate-from-aws-lambda/after/requirements.txt +1 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/13-migrate-from-aws-lambda/before/lambda_function.py +67 -67
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/13-migrate-from-aws-lambda/before/state_machine.asl.json +25 -25
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/13-migrate-from-aws-lambda/before/template.yaml +36 -36
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/14-testing/README.md +45 -45
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/14-testing/app/handlers.py +44 -44
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/14-testing/ci.github-workflow.yml +43 -43
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/14-testing/pskit.yml +39 -39
- py_serverless_kit-0.1.3/examples/14-testing/requirements.txt +1 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/14-testing/tests/conftest.py +20 -20
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/14-testing/tests/test_handlers.py +62 -62
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/14-testing/tests/test_workflow.py +31 -31
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/15-ci-cd-deploy/README.md +64 -64
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/15-ci-cd-deploy/app/handlers.py +12 -12
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/15-ci-cd-deploy/deploy.github-workflow.yml +100 -100
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/15-ci-cd-deploy/pskit.yml +50 -50
- py_serverless_kit-0.1.3/examples/15-ci-cd-deploy/requirements.txt +1 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/README.md +39 -39
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/pyproject.toml +95 -95
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/__main__.py +3 -3
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/_version.py +1 -1
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/cli/templates.py +212 -212
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/config/__init__.py +12 -12
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/core/deployer.py +180 -180
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/core/describe.py +112 -112
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/dashboard/__init__.py +3 -3
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/dashboard/template.html +248 -248
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/local/__init__.py +3 -3
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/packaging/__init__.py +3 -3
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/packaging/builder.py +252 -252
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/__init__.py +15 -15
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/aws.py +567 -508
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/cloudflare.py +264 -264
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/digitalocean.py +211 -211
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/oracle.py +304 -304
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/tencent.py +275 -275
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/__init__.py +6 -6
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/adapters/__init__.py +18 -18
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/adapters/_httpfn.py +91 -91
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/adapters/base.py +86 -86
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/adapters/gcp.py +1 -1
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/batch.py +47 -47
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/context.py +45 -45
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/errors.py +83 -83
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/event.py +267 -267
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/log.py +69 -69
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/terraform/__init__.py +3 -3
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/terraform/runner.py +104 -104
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/workflows/__init__.py +35 -35
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/workflows/asl.py +170 -170
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/config/test_schema.py +79 -79
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/conftest.py +129 -129
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/local/test_server.py +110 -110
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/providers/test_alibaba.py +137 -137
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/providers/test_aws.py +218 -182
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/providers/test_azure.py +104 -104
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/providers/test_cloudflare.py +110 -110
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/providers/test_huawei.py +94 -94
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/providers/test_schedule.py +59 -59
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/test_adapter_alibaba.py +142 -142
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/test_adapter_aws.py +184 -184
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/test_adapter_azure.py +146 -146
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/test_adapter_digitalocean.py +82 -82
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/test_adapter_gcp.py +165 -165
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/test_adapter_huawei.py +146 -146
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/test_adapter_tencent.py +134 -134
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/test_dispatch.py +146 -146
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/test_models.py +161 -161
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/test_workflow_engine.py +174 -174
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/test_cli.py +169 -169
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/test_dashboard.py +37 -37
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/test_examples.py +182 -182
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/test_packaging.py +133 -133
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/workflows/test_compilers.py +141 -141
- py_serverless_kit-0.1.1/examples/06-pubsub-topic/requirements.txt +0 -1
- py_serverless_kit-0.1.1/examples/07-workflow-orders/requirements.txt +0 -1
- py_serverless_kit-0.1.1/examples/08-multi-cloud/requirements.txt +0 -1
- py_serverless_kit-0.1.1/examples/10-stages-and-config/requirements.txt +0 -1
- py_serverless_kit-0.1.1/examples/12-async-and-context/requirements.txt +0 -1
- py_serverless_kit-0.1.1/examples/13-migrate-from-aws-lambda/after/requirements.txt +0 -1
- py_serverless_kit-0.1.1/examples/14-testing/requirements.txt +0 -1
- py_serverless_kit-0.1.1/examples/15-ci-cd-deploy/requirements.txt +0 -1
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/README.md +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/docs/architecture.md +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/docs/troubleshooting.md +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/01-hello-http/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/01-hello-http/pskit.yml +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/02-rest-api/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/03-scheduled-jobs/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/04-queue-worker/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/05-storage-events/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/06-pubsub-topic/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/07-workflow-orders/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/08-multi-cloud/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/09-function-invoke/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/10-stages-and-config/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/11-custom-terraform/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/12-async-and-context/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/13-migrate-from-aws-lambda/after/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/14-testing/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/examples/15-ci-cd-deploy/app/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/cli/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/cli/main.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/config/loader.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/config/schema.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/core/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/core/project.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/dashboard/generator.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/local/runner.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/local/server.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/alibaba.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/azure.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/base.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/gcp.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/huawei.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/ibm.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/registry.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/schedule.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/providers/terraform_doc.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/adapters/alibaba.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/adapters/aws.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/adapters/azure.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/adapters/cloudflare.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/adapters/digitalocean.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/adapters/huawei.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/adapters/ibm.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/adapters/oracle.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/adapters/tencent.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/dispatch.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/invoke.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/manifest.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/response.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/routing.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/runtime/workflow.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/src/py_serverless_kit/workflows/gcp.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/config/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/config/test_loader.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/local/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/providers/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/providers/test_digitalocean.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/providers/test_gcp.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/providers/test_ibm.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/providers/test_oracle.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/providers/test_tencent.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/__init__.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/test_adapter_cloudflare.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/test_adapter_ibm.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/runtime/test_adapter_oracle.py +0 -0
- {py_serverless_kit-0.1.1 → py_serverless_kit-0.1.3}/tests/workflows/__init__.py +0 -0
|
@@ -1,28 +1,29 @@
|
|
|
1
|
-
# Python
|
|
2
|
-
__pycache__/
|
|
3
|
-
*.py[cod]
|
|
4
|
-
*.egg-info/
|
|
5
|
-
.venv/
|
|
6
|
-
venv/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
.
|
|
11
|
-
.
|
|
12
|
-
.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
.
|
|
18
|
-
|
|
19
|
-
*.tfstate
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
.
|
|
28
|
-
.
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.venv/
|
|
6
|
+
venv/
|
|
7
|
+
CLAUDE.md
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
.pytest_cache/
|
|
11
|
+
.mypy_cache/
|
|
12
|
+
.ruff_cache/
|
|
13
|
+
.coverage
|
|
14
|
+
htmlcov/
|
|
15
|
+
.pypirc
|
|
16
|
+
# py-serverless-kit working dirs (local terraform state, artifacts)
|
|
17
|
+
.pskit/
|
|
18
|
+
.terraform/
|
|
19
|
+
*.tfstate
|
|
20
|
+
*.tfstate.*
|
|
21
|
+
|
|
22
|
+
# Secrets
|
|
23
|
+
.env
|
|
24
|
+
.pypirc
|
|
25
|
+
|
|
26
|
+
# Editors / OS
|
|
27
|
+
.idea/
|
|
28
|
+
.vscode/
|
|
29
|
+
.DS_Store
|
|
@@ -1,34 +1,52 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses [Semantic Versioning](https://semver.org/).
|
|
4
|
-
|
|
5
|
-
> The function runtime is bundled into every deployment. After upgrading `py-serverless-kit`, run `pskit deploy` again to pick up runtime fixes.
|
|
6
|
-
|
|
7
|
-
## [Unreleased]
|
|
8
|
-
|
|
9
|
-
## [0.1.
|
|
10
|
-
|
|
11
|
-
###
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- `
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses [Semantic Versioning](https://semver.org/).
|
|
4
|
+
|
|
5
|
+
> The function runtime is bundled into every deployment. After upgrading `py-serverless-kit`, run `pskit deploy` again to pick up runtime fixes.
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.3] - 2026-10-15
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- AWS: `pskit deploy` failed with `creating Lambda Function ...: decomposing request: bufio.Scanner: token too long` once the bundle (e.g. with vendored dependencies) got large, because the zip was sent inline in every `CreateFunction` request. The artifact is now uploaded once to S3 (`aws_s3_object`) and each Lambda function references it via `s3_bucket`/`s3_key`. This also lifts the 50 MB inline upload limit.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- AWS options `artifact_bucket` (use an existing bucket for code uploads instead of the private `<service>-<stage>-code-*` bucket pskit creates) and `artifact_upload: s3 | direct` (`direct` restores the old inline upload).
|
|
16
|
+
|
|
17
|
+
No runtime changes. Existing AWS deployments get a new code bucket on the next `pskit deploy`; Lambda functions are updated in place.
|
|
18
|
+
|
|
19
|
+
## [0.1.2] - 2026-10-15
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- Python 3.9 support: `pskit package`/`deploy` (and the Cloudflare provider) crashed with `TypeError: write_text() got an unexpected keyword argument 'newline'`, because `Path.write_text(newline=...)` only exists on Python 3.10+. Generated files are now written as UTF-8 bytes with `\n` line endings on every Python version.
|
|
23
|
+
- GCP adapter: the storage object `size` check now narrows `None` explicitly, so mypy passes on Python 3.9 CI. Runtime behavior is unchanged.
|
|
24
|
+
|
|
25
|
+
No runtime behavior changes: functions deployed with 0.1.1 don't need to be redeployed.
|
|
26
|
+
|
|
27
|
+
## [0.1.1] - 2026-10-15
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- Author and maintainer set to Asif Khan @ Kavion.ai (`py_serverless_kit.__author__`, package metadata, LICENSE).
|
|
31
|
+
- Project URLs (homepage, docs, issues, changelog) now point to https://github.com/ak9347128658/serverless_kit.
|
|
32
|
+
- README links are absolute so they work on the PyPI project page; added CI/PyPI/license badges.
|
|
33
|
+
- `scripts/validate_all_providers.py` explains that Terraform is optional instead of printing a traceback when it isn't installed.
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
- `deploy_docs/How_to_deploy.md`: short PyPI release guide with PowerShell commands and troubleshooting (e.g. TestPyPI `403`).
|
|
37
|
+
- `deploy_docs/HOW_TO_INSTALL_TERRAFORM.md`: installing Terraform on Windows.
|
|
38
|
+
|
|
39
|
+
No runtime changes: functions deployed with 0.1.0 don't need to be redeployed.
|
|
40
|
+
|
|
41
|
+
## [0.1.0] - 2026-10-15
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
- Portable handler API: `Event`, `HttpRequest`, `Record`, `Headers`, `Context`, `Response`, HTTP error classes, `BatchResult`, `invoke()`.
|
|
45
|
+
- `pskit.yml` configuration with `extends:`, `providers:` and `stages:` overrides, and `${env:}`, `${opt:}`, `${self:}`, `${file()}` and `${tf:}` variables.
|
|
46
|
+
- Providers: AWS (stable), Google Cloud (stable), Azure (stable), Alibaba Cloud (beta), Huawei Cloud (beta), Tencent Cloud (beta), DigitalOcean (beta), IBM Cloud (beta), Oracle Cloud (experimental), Cloudflare Workers (experimental).
|
|
47
|
+
- Triggers: HTTP (path params, CORS, auth), schedule (rate/cron), queue, storage, topic.
|
|
48
|
+
- Workflows: native AWS Step Functions and Google Cloud Workflows compilers, plus an embedded engine for the other providers and local runs.
|
|
49
|
+
- CLI: `init`, `validate`, `package`, `plan`, `deploy`, `remove`, `info`, `dashboard`, `dev`, `invoke`, `workflow run|show`, `providers`, `tf`.
|
|
50
|
+
- Deployment dashboard (self-contained HTML).
|
|
51
|
+
- Local dev server with hot reload, and `LocalRunner` for tests.
|
|
52
|
+
- `scripts/validate_all_providers.py`, which runs `terraform validate` for every provider.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
# Contributing
|
|
2
|
-
|
|
3
|
-
The full contributor guide lives in [deploy_docs/CONTRIBUTING.md](deploy_docs/CONTRIBUTING.md). It covers the project layout, dev setup, how to add providers and options, and how to verify Terraform.
|
|
4
|
-
|
|
5
|
-
Maintainers releasing to PyPI: see [deploy_docs/PUBLISHING_TO_PYPI.md](deploy_docs/PUBLISHING_TO_PYPI.md).
|
|
6
|
-
|
|
7
|
-
Quick start:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
|
|
11
|
-
pip install -e ".[dev]"
|
|
12
|
-
pytest && ruff check src tests && mypy
|
|
13
|
-
```
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
The full contributor guide lives in [deploy_docs/CONTRIBUTING.md](deploy_docs/CONTRIBUTING.md). It covers the project layout, dev setup, how to add providers and options, and how to verify Terraform.
|
|
4
|
+
|
|
5
|
+
Maintainers releasing to PyPI: see [deploy_docs/PUBLISHING_TO_PYPI.md](deploy_docs/PUBLISHING_TO_PYPI.md).
|
|
6
|
+
|
|
7
|
+
Quick start:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
|
|
11
|
+
pip install -e ".[dev]"
|
|
12
|
+
pytest && ruff check src tests && mypy
|
|
13
|
+
```
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Asif Khan @ Kavion.ai
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Asif Khan @ Kavion.ai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: py-serverless-kit
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Write a Python serverless function once and deploy it to AWS, Azure, GCP and 7 more clouds with one YAML file, powered by Terraform.
|
|
5
5
|
Project-URL: Homepage, https://github.com/ak9347128658/serverless_kit
|
|
6
6
|
Project-URL: Documentation, https://github.com/ak9347128658/serverless_kit/tree/main/docs
|
|
@@ -1,158 +1,158 @@
|
|
|
1
|
-
# Contributing to py-serverless-kit
|
|
2
|
-
|
|
3
|
-
Thanks for helping! This guide explains how the project is organised, how to set up a dev environment, the rules every change has to follow, and step-by-step recipes for the most common contributions: a new event option, a new cloud provider, docs and examples.
|
|
4
|
-
|
|
5
|
-
## Ground rules
|
|
6
|
-
|
|
7
|
-
1. **Handler code must never need to change between clouds.** Every feature is designed around this promise. If something can't be portable, it goes under a provider's `options:` and is documented as provider-specific.
|
|
8
|
-
2. **The runtime is standard-library only and Python 3.9 compatible.** Everything in `src/py_serverless_kit/runtime/` is copied into every deployment bundle and runs on clouds we don't control. No third-party imports, no `match` statements, and no `X | Y` type syntax evaluated at runtime. `tests/test_packaging.py::test_vendored_runtime_is_stdlib_only` enforces this.
|
|
9
|
-
3. **Generated Terraform must be real.** Never guess a resource type or argument. Validate with `terraform validate` against the actual provider plugin (see *Verifying Terraform* below).
|
|
10
|
-
4. **Be honest about limits.** If a provider can't do something, raise a clear validation `Issue` and document it. Don't silently skip it.
|
|
11
|
-
5. **Tests come with every change.** Bug fixes need a regression test.
|
|
12
|
-
|
|
13
|
-
## Project layout
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
src/py_serverless_kit/
|
|
17
|
-
runtime/ # shipped inside every function bundle (stdlib only)
|
|
18
|
-
event.py # Event / HttpRequest / Record / Headers
|
|
19
|
-
response.py # Response + coercion of handler return values
|
|
20
|
-
context.py # Context (request id, logger, remaining time)
|
|
21
|
-
dispatch.py # calls the user handler: routing, CORS, error mapping
|
|
22
|
-
workflow.py # embedded state-machine engine
|
|
23
|
-
invoke.py # portable function-to-function invoke()
|
|
24
|
-
adapters/<cloud>.py # native event/response <-> portable model
|
|
25
|
-
config/ # pskit.yml schema (pydantic) + loader (extends, overrides, variables)
|
|
26
|
-
providers/ # one Terraform renderer per cloud + base class + registry
|
|
27
|
-
workflows/ # compilers: ASL (AWS Step Functions), Google Cloud Workflows
|
|
28
|
-
packaging/ # deterministic zip builder
|
|
29
|
-
terraform/ # terraform/tofu subprocess wrapper
|
|
30
|
-
core/ # Project (config + provider), Deployer, deployment record
|
|
31
|
-
local/ # LocalRunner (invoke/workflows) + `pskit dev` server
|
|
32
|
-
dashboard/ # static HTML dashboard generator
|
|
33
|
-
cli/ # click CLI + `pskit init` templates
|
|
34
|
-
tests/ # mirrors the package layout
|
|
35
|
-
examples/ # runnable scenario projects (tested by tests/test_examples.py)
|
|
36
|
-
docs/ # user documentation
|
|
37
|
-
deploy_docs/ # maintainer docs (publishing, contributing)
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
### How a deploy flows through the code
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
pskit deploy
|
|
44
|
-
-> config.loader.load_config read YAML, extends, providers:/stages: overrides, ${...} variables
|
|
45
|
-
-> core.project.Project pick provider, add embedded-workflow orchestrator functions
|
|
46
|
-
-> Provider.validate capability / limit checks -> Issues
|
|
47
|
-
-> packaging.build_artifact sources + vendored runtime + manifest + provider shim -> artifact.zip
|
|
48
|
-
-> Provider.render TerraformDoc -> .pskit/<provider>-<stage>/main.tf.json
|
|
49
|
-
-> terraform init/apply TerraformRunner
|
|
50
|
-
-> core.describe.build_record terraform outputs -> deployment.json
|
|
51
|
-
-> dashboard.write_dashboard .pskit/dashboard/index.html
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
At runtime in the cloud:
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
platform -> shim (e.g. pskit_entry.handler) -> runtime.adapters.<cloud> -> runtime.dispatch.execute -> your handler
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Development setup
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
git clone https://github.com/ak9347128658/serverless_kit.git
|
|
64
|
-
cd serverless_kit
|
|
65
|
-
python -m venv .venv
|
|
66
|
-
source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
|
|
67
|
-
pip install -e ".[dev]"
|
|
68
|
-
pytest # whole suite, no cloud access needed
|
|
69
|
-
ruff check src tests
|
|
70
|
-
mypy
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Optional tools:
|
|
74
|
-
|
|
75
|
-
- **Terraform ≥ 1.5** or **OpenTofu**, for `terraform validate` and real deploys.
|
|
76
|
-
- Cloud CLIs/credentials, only if you want to run a real deploy of the examples.
|
|
77
|
-
|
|
78
|
-
## Workflow
|
|
79
|
-
|
|
80
|
-
1. Open an issue first for anything non-trivial (new provider, config changes) so we can agree on the design.
|
|
81
|
-
2. Fork and branch from `main`: `feat/<short-name>`, `fix/<short-name>`, `docs/<short-name>`.
|
|
82
|
-
3. Keep PRs focused. One provider or one feature per PR.
|
|
83
|
-
4. Use [Conventional Commits](https://www.conventionalcommits.org/) messages: `feat(gcp): support Cloud Tasks queues`, `fix(runtime): keep multi-value headers`.
|
|
84
|
-
5. Add an entry under **Unreleased** in `CHANGELOG.md`.
|
|
85
|
-
6. Make sure CI is green: tests on Python 3.9 to 3.13, ruff, mypy, and `terraform validate` for every provider.
|
|
86
|
-
7. A maintainer reviews the PR. Expect questions about portability and failure modes.
|
|
87
|
-
|
|
88
|
-
## Recipes
|
|
89
|
-
|
|
90
|
-
### Add a new option to an existing event type
|
|
91
|
-
|
|
92
|
-
Example: `queue.max_concurrency`.
|
|
93
|
-
|
|
94
|
-
1. Add the field to the model in `config/schema.py` (with a sensible default and validation).
|
|
95
|
-
2. Implement it in every provider that can support it (`providers/<cloud>.py`). Where a provider can't, either ignore it with a `doc.warnings.append(...)` or return an `Issue("error", ...)` from `extra_validation` if ignoring it would be dangerous.
|
|
96
|
-
3. Add tests in `tests/config/test_schema.py` and the relevant `tests/providers/test_<cloud>.py`.
|
|
97
|
-
4. Document it in `docs/configuration.md` and, if it differs per provider, in `docs/providers.md`.
|
|
98
|
-
|
|
99
|
-
### Add a new cloud provider
|
|
100
|
-
|
|
101
|
-
1. **Research.** Find the Terraform provider and the exact resources for: a function from a zip (or image), an HTTP endpoint, and triggers. Write down the native event payload shapes and the entrypoint signature.
|
|
102
|
-
2. **Adapter:** create `runtime/adapters/<cloud>.py` with:
|
|
103
|
-
- `to_event(native, native_ctx) -> Event`: handle HTTP, every trigger type, and `__pskit` envelopes (`adapters.base.unwrap_envelope`);
|
|
104
|
-
- a function that turns the result into the native response (for HTTP use `Response.render_for_gateway()`);
|
|
105
|
-
- an entrypoint that calls `runtime.dispatch.execute`.
|
|
106
|
-
3. **Provider:** create `providers/<cloud>.py` subclassing `providers.base.Provider`:
|
|
107
|
-
- class attributes: `name`, `display_name`, `tier` (`experimental` until it has been deployed for real), `terraform_source`, `default_region`, `capabilities`, `runtimes`, `max_timeout`, `vendor_dependencies`, naming rules;
|
|
108
|
-
- `shim_files()`: the files at the bundle root that the platform calls;
|
|
109
|
-
- `render_resources(doc, ctx)`: emit resources, and **always** the `pskit` output (`functions`, `workflows`, `endpoint`);
|
|
110
|
-
- `extra_validation()` for provider-specific limits.
|
|
111
|
-
4. **Register** it in `providers/registry.py` (`BUILTIN`) and add its name to `PROVIDERS` in `config/schema.py`. Third-party packages can instead register through the `py_serverless_kit.providers` entry-point group without changing this repo:
|
|
112
|
-
|
|
113
|
-
```toml
|
|
114
|
-
[project.entry-points."py_serverless_kit.providers"]
|
|
115
|
-
mycloud = "pskit_mycloud:MyCloudProvider"
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
5. **Tests:** `tests/providers/test_<cloud>.py` (render, outputs, validation errors) and `tests/runtime/test_adapter_<cloud>.py` (realistic native payloads, recorded from the real platform when possible).
|
|
119
|
-
6. **Verify Terraform** (below), then update `docs/providers.md`, the README matrix, and `cli/templates.py` (`DEFAULT_REGIONS`, `PROVIDER_OPTIONS`).
|
|
120
|
-
|
|
121
|
-
### Add an example
|
|
122
|
-
|
|
123
|
-
Create `examples/NN-name/` with `pskit.yml`, handler code and a `README.md`. `tests/test_examples.py` picks it up automatically and validates and packages it.
|
|
124
|
-
|
|
125
|
-
## Verifying Terraform
|
|
126
|
-
|
|
127
|
-
Unit tests check the *shape* of the generated JSON. Only Terraform itself can say whether the resources and arguments exist. For any provider change:
|
|
128
|
-
|
|
129
|
-
```bash
|
|
130
|
-
cd examples/08-multi-cloud
|
|
131
|
-
pskit package --skip-deps --provider <cloud>
|
|
132
|
-
cd .pskit/<cloud>-dev
|
|
133
|
-
terraform init -backend=false
|
|
134
|
-
terraform validate # must print: Success! The configuration is valid.
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
To look up a resource's exact schema:
|
|
138
|
-
|
|
139
|
-
```bash
|
|
140
|
-
terraform providers schema -json | python -c "import json,sys; s=json.load(sys.stdin); \
|
|
141
|
-
print(json.dumps(next(iter(s['provider_schemas'].values()))['resource_schemas']['aws_lambda_function'], indent=1))"
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
## Coding style
|
|
145
|
-
|
|
146
|
-
- `ruff` for linting and import order, line length 120.
|
|
147
|
-
- Type hints everywhere. `mypy` must pass.
|
|
148
|
-
- Comments explain *why*, not *what*. Match the density of the surrounding code.
|
|
149
|
-
- User-facing errors say what's wrong **and** how to fix it.
|
|
150
|
-
|
|
151
|
-
## Reporting bugs and security issues
|
|
152
|
-
|
|
153
|
-
- Bugs: open a GitHub issue with `pskit --version`, the provider, the relevant part of `pskit.yml` (remove secrets) and the full error.
|
|
154
|
-
- Security vulnerabilities: **don't** open a public issue. Follow `SECURITY.md`.
|
|
155
|
-
|
|
156
|
-
## Releasing
|
|
157
|
-
|
|
158
|
-
Maintainers: see [PUBLISHING_TO_PYPI.md](PUBLISHING_TO_PYPI.md).
|
|
1
|
+
# Contributing to py-serverless-kit
|
|
2
|
+
|
|
3
|
+
Thanks for helping! This guide explains how the project is organised, how to set up a dev environment, the rules every change has to follow, and step-by-step recipes for the most common contributions: a new event option, a new cloud provider, docs and examples.
|
|
4
|
+
|
|
5
|
+
## Ground rules
|
|
6
|
+
|
|
7
|
+
1. **Handler code must never need to change between clouds.** Every feature is designed around this promise. If something can't be portable, it goes under a provider's `options:` and is documented as provider-specific.
|
|
8
|
+
2. **The runtime is standard-library only and Python 3.9 compatible.** Everything in `src/py_serverless_kit/runtime/` is copied into every deployment bundle and runs on clouds we don't control. No third-party imports, no `match` statements, and no `X | Y` type syntax evaluated at runtime. `tests/test_packaging.py::test_vendored_runtime_is_stdlib_only` enforces this.
|
|
9
|
+
3. **Generated Terraform must be real.** Never guess a resource type or argument. Validate with `terraform validate` against the actual provider plugin (see *Verifying Terraform* below).
|
|
10
|
+
4. **Be honest about limits.** If a provider can't do something, raise a clear validation `Issue` and document it. Don't silently skip it.
|
|
11
|
+
5. **Tests come with every change.** Bug fixes need a regression test.
|
|
12
|
+
|
|
13
|
+
## Project layout
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
src/py_serverless_kit/
|
|
17
|
+
runtime/ # shipped inside every function bundle (stdlib only)
|
|
18
|
+
event.py # Event / HttpRequest / Record / Headers
|
|
19
|
+
response.py # Response + coercion of handler return values
|
|
20
|
+
context.py # Context (request id, logger, remaining time)
|
|
21
|
+
dispatch.py # calls the user handler: routing, CORS, error mapping
|
|
22
|
+
workflow.py # embedded state-machine engine
|
|
23
|
+
invoke.py # portable function-to-function invoke()
|
|
24
|
+
adapters/<cloud>.py # native event/response <-> portable model
|
|
25
|
+
config/ # pskit.yml schema (pydantic) + loader (extends, overrides, variables)
|
|
26
|
+
providers/ # one Terraform renderer per cloud + base class + registry
|
|
27
|
+
workflows/ # compilers: ASL (AWS Step Functions), Google Cloud Workflows
|
|
28
|
+
packaging/ # deterministic zip builder
|
|
29
|
+
terraform/ # terraform/tofu subprocess wrapper
|
|
30
|
+
core/ # Project (config + provider), Deployer, deployment record
|
|
31
|
+
local/ # LocalRunner (invoke/workflows) + `pskit dev` server
|
|
32
|
+
dashboard/ # static HTML dashboard generator
|
|
33
|
+
cli/ # click CLI + `pskit init` templates
|
|
34
|
+
tests/ # mirrors the package layout
|
|
35
|
+
examples/ # runnable scenario projects (tested by tests/test_examples.py)
|
|
36
|
+
docs/ # user documentation
|
|
37
|
+
deploy_docs/ # maintainer docs (publishing, contributing)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### How a deploy flows through the code
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
pskit deploy
|
|
44
|
+
-> config.loader.load_config read YAML, extends, providers:/stages: overrides, ${...} variables
|
|
45
|
+
-> core.project.Project pick provider, add embedded-workflow orchestrator functions
|
|
46
|
+
-> Provider.validate capability / limit checks -> Issues
|
|
47
|
+
-> packaging.build_artifact sources + vendored runtime + manifest + provider shim -> artifact.zip
|
|
48
|
+
-> Provider.render TerraformDoc -> .pskit/<provider>-<stage>/main.tf.json
|
|
49
|
+
-> terraform init/apply TerraformRunner
|
|
50
|
+
-> core.describe.build_record terraform outputs -> deployment.json
|
|
51
|
+
-> dashboard.write_dashboard .pskit/dashboard/index.html
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
At runtime in the cloud:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
platform -> shim (e.g. pskit_entry.handler) -> runtime.adapters.<cloud> -> runtime.dispatch.execute -> your handler
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Development setup
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
git clone https://github.com/ak9347128658/serverless_kit.git
|
|
64
|
+
cd serverless_kit
|
|
65
|
+
python -m venv .venv
|
|
66
|
+
source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
|
|
67
|
+
pip install -e ".[dev]"
|
|
68
|
+
pytest # whole suite, no cloud access needed
|
|
69
|
+
ruff check src tests
|
|
70
|
+
mypy
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Optional tools:
|
|
74
|
+
|
|
75
|
+
- **Terraform ≥ 1.5** or **OpenTofu**, for `terraform validate` and real deploys.
|
|
76
|
+
- Cloud CLIs/credentials, only if you want to run a real deploy of the examples.
|
|
77
|
+
|
|
78
|
+
## Workflow
|
|
79
|
+
|
|
80
|
+
1. Open an issue first for anything non-trivial (new provider, config changes) so we can agree on the design.
|
|
81
|
+
2. Fork and branch from `main`: `feat/<short-name>`, `fix/<short-name>`, `docs/<short-name>`.
|
|
82
|
+
3. Keep PRs focused. One provider or one feature per PR.
|
|
83
|
+
4. Use [Conventional Commits](https://www.conventionalcommits.org/) messages: `feat(gcp): support Cloud Tasks queues`, `fix(runtime): keep multi-value headers`.
|
|
84
|
+
5. Add an entry under **Unreleased** in `CHANGELOG.md`.
|
|
85
|
+
6. Make sure CI is green: tests on Python 3.9 to 3.13, ruff, mypy, and `terraform validate` for every provider.
|
|
86
|
+
7. A maintainer reviews the PR. Expect questions about portability and failure modes.
|
|
87
|
+
|
|
88
|
+
## Recipes
|
|
89
|
+
|
|
90
|
+
### Add a new option to an existing event type
|
|
91
|
+
|
|
92
|
+
Example: `queue.max_concurrency`.
|
|
93
|
+
|
|
94
|
+
1. Add the field to the model in `config/schema.py` (with a sensible default and validation).
|
|
95
|
+
2. Implement it in every provider that can support it (`providers/<cloud>.py`). Where a provider can't, either ignore it with a `doc.warnings.append(...)` or return an `Issue("error", ...)` from `extra_validation` if ignoring it would be dangerous.
|
|
96
|
+
3. Add tests in `tests/config/test_schema.py` and the relevant `tests/providers/test_<cloud>.py`.
|
|
97
|
+
4. Document it in `docs/configuration.md` and, if it differs per provider, in `docs/providers.md`.
|
|
98
|
+
|
|
99
|
+
### Add a new cloud provider
|
|
100
|
+
|
|
101
|
+
1. **Research.** Find the Terraform provider and the exact resources for: a function from a zip (or image), an HTTP endpoint, and triggers. Write down the native event payload shapes and the entrypoint signature.
|
|
102
|
+
2. **Adapter:** create `runtime/adapters/<cloud>.py` with:
|
|
103
|
+
- `to_event(native, native_ctx) -> Event`: handle HTTP, every trigger type, and `__pskit` envelopes (`adapters.base.unwrap_envelope`);
|
|
104
|
+
- a function that turns the result into the native response (for HTTP use `Response.render_for_gateway()`);
|
|
105
|
+
- an entrypoint that calls `runtime.dispatch.execute`.
|
|
106
|
+
3. **Provider:** create `providers/<cloud>.py` subclassing `providers.base.Provider`:
|
|
107
|
+
- class attributes: `name`, `display_name`, `tier` (`experimental` until it has been deployed for real), `terraform_source`, `default_region`, `capabilities`, `runtimes`, `max_timeout`, `vendor_dependencies`, naming rules;
|
|
108
|
+
- `shim_files()`: the files at the bundle root that the platform calls;
|
|
109
|
+
- `render_resources(doc, ctx)`: emit resources, and **always** the `pskit` output (`functions`, `workflows`, `endpoint`);
|
|
110
|
+
- `extra_validation()` for provider-specific limits.
|
|
111
|
+
4. **Register** it in `providers/registry.py` (`BUILTIN`) and add its name to `PROVIDERS` in `config/schema.py`. Third-party packages can instead register through the `py_serverless_kit.providers` entry-point group without changing this repo:
|
|
112
|
+
|
|
113
|
+
```toml
|
|
114
|
+
[project.entry-points."py_serverless_kit.providers"]
|
|
115
|
+
mycloud = "pskit_mycloud:MyCloudProvider"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
5. **Tests:** `tests/providers/test_<cloud>.py` (render, outputs, validation errors) and `tests/runtime/test_adapter_<cloud>.py` (realistic native payloads, recorded from the real platform when possible).
|
|
119
|
+
6. **Verify Terraform** (below), then update `docs/providers.md`, the README matrix, and `cli/templates.py` (`DEFAULT_REGIONS`, `PROVIDER_OPTIONS`).
|
|
120
|
+
|
|
121
|
+
### Add an example
|
|
122
|
+
|
|
123
|
+
Create `examples/NN-name/` with `pskit.yml`, handler code and a `README.md`. `tests/test_examples.py` picks it up automatically and validates and packages it.
|
|
124
|
+
|
|
125
|
+
## Verifying Terraform
|
|
126
|
+
|
|
127
|
+
Unit tests check the *shape* of the generated JSON. Only Terraform itself can say whether the resources and arguments exist. For any provider change:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
cd examples/08-multi-cloud
|
|
131
|
+
pskit package --skip-deps --provider <cloud>
|
|
132
|
+
cd .pskit/<cloud>-dev
|
|
133
|
+
terraform init -backend=false
|
|
134
|
+
terraform validate # must print: Success! The configuration is valid.
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
To look up a resource's exact schema:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
terraform providers schema -json | python -c "import json,sys; s=json.load(sys.stdin); \
|
|
141
|
+
print(json.dumps(next(iter(s['provider_schemas'].values()))['resource_schemas']['aws_lambda_function'], indent=1))"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Coding style
|
|
145
|
+
|
|
146
|
+
- `ruff` for linting and import order, line length 120.
|
|
147
|
+
- Type hints everywhere. `mypy` must pass.
|
|
148
|
+
- Comments explain *why*, not *what*. Match the density of the surrounding code.
|
|
149
|
+
- User-facing errors say what's wrong **and** how to fix it.
|
|
150
|
+
|
|
151
|
+
## Reporting bugs and security issues
|
|
152
|
+
|
|
153
|
+
- Bugs: open a GitHub issue with `pskit --version`, the provider, the relevant part of `pskit.yml` (remove secrets) and the full error.
|
|
154
|
+
- Security vulnerabilities: **don't** open a public issue. Follow `SECURITY.md`.
|
|
155
|
+
|
|
156
|
+
## Releasing
|
|
157
|
+
|
|
158
|
+
Maintainers: see [PUBLISHING_TO_PYPI.md](PUBLISHING_TO_PYPI.md).
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
# py-serverless-kit documentation
|
|
2
|
-
|
|
3
|
-
Write a Python function once, describe its triggers in `pskit.yml`, and deploy it to any of 10 clouds with Terraform. Moving to another cloud means changing `provider.name`. The handler code stays the same.
|
|
4
|
-
|
|
5
|
-
| Page | What it covers |
|
|
6
|
-
|---|---|
|
|
7
|
-
| [Getting started](getting-started.md) | Install, scaffold a project, run it locally, set up cloud credentials, deploy, inspect, remove |
|
|
8
|
-
| [Configuration reference](configuration.md) | Every `pskit.yml` key, `extends:`, `providers:`/`stages:` overrides, variables, escape hatches |
|
|
9
|
-
| [Events (triggers)](events.md) | `http`, `schedule`, `queue`, `storage`, `topic`, with shorthand forms and per-provider support |
|
|
10
|
-
| [Handler API](handlers.md) | `Event`, `HttpRequest`, `Record`, `Context`, `Response`, errors, `BatchResult`, `invoke()`, logging |
|
|
11
|
-
| [Workflows](workflows.md) | State machines: native AWS Step Functions / GCP Workflows, or the embedded engine anywhere |
|
|
12
|
-
| [Providers](providers.md) | Capability matrix plus one section per cloud: options, credentials, resources, limits |
|
|
13
|
-
| [CLI reference](cli.md) | Every `pskit` command and flag |
|
|
14
|
-
| [Local development](local-development.md) | `pskit dev`, `pskit invoke`, `.env`, testing with `LocalRunner` |
|
|
15
|
-
| [Dashboard](dashboard.md) | The generated HTML index of everything you deployed |
|
|
16
|
-
| [Architecture](architecture.md) | How config becomes Terraform and how the runtime dispatches events; third-party providers |
|
|
17
|
-
| [Migrating from AWS](migrating-from-aws.md) | Moving existing Lambda functions and Step Functions to pskit, then to other clouds |
|
|
18
|
-
| [Troubleshooting & FAQ](troubleshooting.md) | Common errors, provider gotchas, security notes |
|
|
19
|
-
|
|
20
|
-
Runnable examples for every scenario live in [`../examples`](../examples/README.md).
|
|
21
|
-
|
|
22
|
-
Maintainers: see [`../deploy_docs/PUBLISHING_TO_PYPI.md`](../deploy_docs/PUBLISHING_TO_PYPI.md) and [`../deploy_docs/CONTRIBUTING.md`](../deploy_docs/CONTRIBUTING.md).
|
|
1
|
+
# py-serverless-kit documentation
|
|
2
|
+
|
|
3
|
+
Write a Python function once, describe its triggers in `pskit.yml`, and deploy it to any of 10 clouds with Terraform. Moving to another cloud means changing `provider.name`. The handler code stays the same.
|
|
4
|
+
|
|
5
|
+
| Page | What it covers |
|
|
6
|
+
|---|---|
|
|
7
|
+
| [Getting started](getting-started.md) | Install, scaffold a project, run it locally, set up cloud credentials, deploy, inspect, remove |
|
|
8
|
+
| [Configuration reference](configuration.md) | Every `pskit.yml` key, `extends:`, `providers:`/`stages:` overrides, variables, escape hatches |
|
|
9
|
+
| [Events (triggers)](events.md) | `http`, `schedule`, `queue`, `storage`, `topic`, with shorthand forms and per-provider support |
|
|
10
|
+
| [Handler API](handlers.md) | `Event`, `HttpRequest`, `Record`, `Context`, `Response`, errors, `BatchResult`, `invoke()`, logging |
|
|
11
|
+
| [Workflows](workflows.md) | State machines: native AWS Step Functions / GCP Workflows, or the embedded engine anywhere |
|
|
12
|
+
| [Providers](providers.md) | Capability matrix plus one section per cloud: options, credentials, resources, limits |
|
|
13
|
+
| [CLI reference](cli.md) | Every `pskit` command and flag |
|
|
14
|
+
| [Local development](local-development.md) | `pskit dev`, `pskit invoke`, `.env`, testing with `LocalRunner` |
|
|
15
|
+
| [Dashboard](dashboard.md) | The generated HTML index of everything you deployed |
|
|
16
|
+
| [Architecture](architecture.md) | How config becomes Terraform and how the runtime dispatches events; third-party providers |
|
|
17
|
+
| [Migrating from AWS](migrating-from-aws.md) | Moving existing Lambda functions and Step Functions to pskit, then to other clouds |
|
|
18
|
+
| [Troubleshooting & FAQ](troubleshooting.md) | Common errors, provider gotchas, security notes |
|
|
19
|
+
|
|
20
|
+
Runnable examples for every scenario live in [`../examples`](../examples/README.md).
|
|
21
|
+
|
|
22
|
+
Maintainers: see [`../deploy_docs/PUBLISHING_TO_PYPI.md`](../deploy_docs/PUBLISHING_TO_PYPI.md) and [`../deploy_docs/CONTRIBUTING.md`](../deploy_docs/CONTRIBUTING.md).
|