cloudcoil 0.2.2__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. cloudcoil-0.3.0/.github/workflows/pypi_publish.yml +47 -0
  2. cloudcoil-0.3.0/.github/workflows/update_repos.yml +30 -0
  3. cloudcoil-0.3.0/.gitignore +178 -0
  4. cloudcoil-0.3.0/Makefile +74 -0
  5. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/PKG-INFO +243 -3
  6. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/README.md +242 -2
  7. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/apimachinery.py +14 -14
  8. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/codegen/generator.py +160 -119
  9. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/codegen/templates/pydantic_v2/BaseModel.jinja2 +6 -6
  10. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/codegen/templates/pydantic_v2/RootModel.jinja2 +4 -4
  11. cloudcoil-0.3.0/cookiecutter/LICENSE +190 -0
  12. cloudcoil-0.3.0/cookiecutter/README.md +2 -0
  13. cloudcoil-0.3.0/cookiecutter/cookiecutter.json +11 -0
  14. cloudcoil-0.3.0/cookiecutter/hooks/post_gen_project.sh +10 -0
  15. cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}/.gitattributes +1 -0
  16. cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}/.github/workflows/ci.yml +52 -0
  17. cloudcoil-0.2.2/.github/workflows/pypi_publish.yml → cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}/.github/workflows/pypi_publish.yml +4 -2
  18. cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}/.github/workflows/test_pypi_publish.yml +45 -0
  19. cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}/.github/workflows/update_releases.yml +126 -0
  20. cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}/LICENSE +201 -0
  21. cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}/Makefile +39 -0
  22. cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}/README.md +3 -0
  23. cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}/mkdocs.yml +38 -0
  24. cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}/pyproject.toml +87 -0
  25. cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}/tests/test_import.py +8 -0
  26. cloudcoil-0.3.0/docs/api.md +3 -0
  27. cloudcoil-0.3.0/models/cert-manager/README.md +204 -0
  28. cloudcoil-0.3.0/models/cert-manager/cookiecutter.yaml +8 -0
  29. cloudcoil-0.3.0/models/cert-manager/pyproject.toml +3 -0
  30. cloudcoil-0.3.0/models/fluxcd/README.md +207 -0
  31. cloudcoil-0.3.0/models/fluxcd/cookiecutter.yaml +8 -0
  32. cloudcoil-0.3.0/models/fluxcd/pyproject.toml +4 -0
  33. cloudcoil-0.3.0/models/kubernetes/README.md +262 -0
  34. cloudcoil-0.3.0/models/kubernetes/cookiecutter.yaml +8 -0
  35. cloudcoil-0.3.0/models/kubernetes/pyproject.toml +8 -0
  36. cloudcoil-0.3.0/models/kyverno/README.md +206 -0
  37. cloudcoil-0.3.0/models/kyverno/cookiecutter.yaml +8 -0
  38. cloudcoil-0.3.0/models/kyverno/pyproject.toml +4 -0
  39. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/pyproject.toml +3 -2
  40. cloudcoil-0.3.0/tests/test_cli.py +0 -0
  41. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/tests/test_codegen.py +249 -0
  42. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/uv.lock +11 -6
  43. cloudcoil-0.2.2/Makefile +0 -39
  44. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/.gitattributes +0 -0
  45. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  46. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/.github/ISSUE_TEMPLATE//360/237/220/233-bug-report.md" +0 -0
  47. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/.github/ISSUE_TEMPLATE//360/237/224/214-model-request.md" +0 -0
  48. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/.github/ISSUE_TEMPLATE//360/237/232/200-feature-request.md" +0 -0
  49. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  50. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/.github/workflows/ci.yml +0 -0
  51. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/.github/workflows/docs.yml +0 -0
  52. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/.github/workflows/test_pypi_publish.yml +0 -0
  53. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/CODE_OF_CONDUCT.md +0 -0
  54. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/LICENSE +0 -0
  55. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/MEMBERS.md +0 -0
  56. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/SECURITY.md +0 -0
  57. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/_context.py +0 -0
  58. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/_pydantic.py +0 -0
  59. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/_testing/__init__.py +0 -0
  60. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/_testing/clusters.py +0 -0
  61. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/_testing/plugin.py +0 -0
  62. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/client/__init__.py +0 -0
  63. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/client/_api_client.py +0 -0
  64. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/client/_config.py +0 -0
  65. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/codegen/__init__.py +0 -0
  66. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/codegen/_tomllib/__init__.py +0 -0
  67. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/codegen/_tomllib/_parser.py +0 -0
  68. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/codegen/_tomllib/_re.py +0 -0
  69. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/codegen/_tomllib/_types.py +0 -0
  70. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/codegen/import_rewriter.py +0 -0
  71. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/codegen/ruff.toml +0 -0
  72. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/errors.py +0 -0
  73. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/models/py.typed +0 -0
  74. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/mypy.py +0 -0
  75. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/py.typed +0 -0
  76. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/pydantic.py +0 -0
  77. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/resources.py +0 -0
  78. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/cloudcoil/version.py +0 -0
  79. {cloudcoil-0.2.2 → cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}}/.gitignore +0 -0
  80. /cloudcoil-0.2.2/tests/test_cli.py → /cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}/cloudcoil/models/{{ cookiecutter.module_name }}/__init__.py +0 -0
  81. {cloudcoil-0.2.2 → cloudcoil-0.3.0/cookiecutter/models-{{ cookiecutter.model_name }}}/docs/api.md +0 -0
  82. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/docs/index.md +0 -0
  83. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/mkdocs.yml +0 -0
  84. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/tests/data/k8s-swagger.json +0 -0
  85. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/tests/test_config.py +0 -0
  86. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/tests/test_context.py +0 -0
  87. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/tests/test_e2e.py +0 -0
  88. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/tests/test_fluent.py +0 -0
  89. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/tests/test_import_rewriter.py +0 -0
  90. {cloudcoil-0.2.2 → cloudcoil-0.3.0}/tests/test_resources.py +0 -0
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: PyPI publish
3
+
4
+ on:
5
+ release:
6
+ types: [released]
7
+
8
+ jobs:
9
+ build:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ # IMPORTANT: this permission is mandatory for Trusted Publishing
13
+ id-token: write
14
+ steps:
15
+ - name: Checkout code
16
+ uses: actions/checkout@v3
17
+
18
+ - name: Setup Python
19
+ uses: actions/setup-python@v4
20
+ with:
21
+ python-version: "3.10"
22
+
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v4
25
+ with:
26
+ python-version: "3.10"
27
+ enable-cache: true
28
+ cache-dependency-glob: "**/uv.lock"
29
+
30
+ - name: Install dependencies
31
+ run: uv sync --extra all --dev
32
+
33
+ - name: Bump version number
34
+ run: |
35
+ sed -i "s/version = \".*\"/version = \"${{ github.event.release.tag_name }}\"/" pyproject.toml
36
+
37
+ - name: Build package
38
+ run: uv build
39
+
40
+ - name: Publish package distributions to PyPI
41
+ uses: pypa/gh-action-pypi-publish@release/v1
42
+
43
+ # Trigger a workflow dispatch in the same repository
44
+ - name: Trigger update-repos workflow
45
+ uses: peter-evans/repository-dispatch@v1
46
+ with:
47
+ event-type: update-repos
@@ -0,0 +1,30 @@
1
+
2
+ name: Update Versions
3
+
4
+ on:
5
+ push:
6
+ branches:
7
+ - main
8
+ repository_dispatch:
9
+ types: [update-repos]
10
+ jobs:
11
+ update-repos:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ with:
16
+ token: ${{ secrets.CI_GITHUB_TOKEN }}
17
+
18
+ - name: Install uv and set python
19
+ uses: astral-sh/setup-uv@v4
20
+ with:
21
+ python-version: '3.10'
22
+ enable-cache: true
23
+ cache-dependency-glob: "**/uv.lock"
24
+
25
+ - name: Update all repos
26
+ env:
27
+ GITHUB_TOKEN: ${{ secrets.CI_GITHUB_TOKEN }}
28
+ run: |
29
+ gh auth setup-git
30
+ make -j8 publish-all-repos
@@ -0,0 +1,178 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+
110
+ # pdm
111
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
112
+ #pdm.lock
113
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
114
+ # in version control.
115
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
116
+ .pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
121
+ __pypackages__/
122
+
123
+ # Celery stuff
124
+ celerybeat-schedule
125
+ celerybeat.pid
126
+
127
+ # SageMath parsed files
128
+ *.sage.py
129
+
130
+ # Environments
131
+ .env
132
+ .venv
133
+ env/
134
+ venv/
135
+ ENV/
136
+ env.bak/
137
+ venv.bak/
138
+
139
+ # Spyder project settings
140
+ .spyderproject
141
+ .spyproject
142
+
143
+ # Rope project settings
144
+ .ropeproject
145
+
146
+ # mkdocs documentation
147
+ /site
148
+
149
+ # mypy
150
+ .mypy_cache/
151
+ .dmypy.json
152
+ dmypy.json
153
+ .*cache
154
+ # Pyre type checker
155
+ .pyre/
156
+
157
+ # pytype static type analyzer
158
+ .pytype/
159
+
160
+ # Cython debug symbols
161
+ cython_debug/
162
+
163
+ # PyCharm
164
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
165
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
166
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
167
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
168
+ #.idea/
169
+
170
+ # PyPI configuration file
171
+ .pypirc
172
+ processed_swagger.json
173
+ extra_data.json
174
+ .DS_Store
175
+ .vscode
176
+ junit.xml
177
+ /output
178
+ /tmp
@@ -0,0 +1,74 @@
1
+ .PHONY: test
2
+ test:
3
+ uv run --frozen pytest
4
+
5
+ .PHONY: lint
6
+ lint:
7
+ uv run --frozen ruff check cloudcoil tests
8
+ uv run --frozen ruff format --check cloudcoil tests
9
+ uv run --frozen mypy -p cloudcoil
10
+
11
+ .PHONY: fix-lint
12
+ fix-lint:
13
+ uv run --frozen ruff format cloudcoil tests
14
+ uv run --frozen ruff check --fix --unsafe-fixes cloudcoil tests
15
+
16
+ .PHONY: docs-deploy
17
+ docs-deploy:
18
+ rm -rf docs/index.md
19
+ cp README.md docs/index.md
20
+ uv run --frozen mkdocs gh-deploy --force
21
+
22
+ .PHONY: docs-serve
23
+ docs-serve:
24
+ rm -rf docs/index.md
25
+ cp README.md docs/index.md
26
+ uv run --frozen mkdocs serve
27
+
28
+ .PHONY: prepare-for-pr
29
+ prepare-for-pr: fix-lint lint test
30
+ @echo "========"
31
+ @echo "It looks good! :)"
32
+ @echo "Make sure to commit all changes!"
33
+ @echo "========"
34
+
35
+ .PHONY: gen-models
36
+ gen-models:
37
+ rm -rf cloudcoil/apimachinery.py
38
+ uv run --frozen cloudcoil-model-codegen
39
+ $(MAKE) fix-lint
40
+
41
+
42
+ REPOS := $(shell ls models | sed 's/\/$$//')
43
+
44
+ gen-all-repos: $(addprefix gen-repo-,$(REPOS))
45
+
46
+ publish-all-repos: $(addprefix publish-repo-,$(REPOS))
47
+
48
+ gen-repo-%:
49
+ rm -rf output/models-$*
50
+ uvx cookiecutter --no-input --output-dir=output --config-file=models/$*/cookiecutter.yaml cookiecutter _config_dir=$$PWD/models/$*
51
+
52
+ # publish-repo-% creates a repo in cloudcoil/models-$* if it doesn't exist, and pushes the generated code to it
53
+ # It should not force push to the repo and instead change all the existing files in the repo to match the generated code
54
+ # Check if the repo exists using gh
55
+ # If it doesn't exist, create it
56
+ # If it does exist, change all the existing files in the repo to match the generated code
57
+ # Push the generated code to the repo
58
+ publish-repo-%: gen-repo-%
59
+ @echo "Publishing to cloudcoil/models-$*"
60
+ @if ! gh repo view cloudcoil/models-$* >/dev/null 2>&1; then \
61
+ gh repo create cloudcoil/models-$* --public --description "Generated model repository for $*"; \
62
+ fi
63
+ @rm -rf tmp/models-$*
64
+ @mkdir -p tmp/models-$*
65
+ @cd tmp/models-$* && \
66
+ git clone https://github.com/cloudcoil/models-$*.git . || git init && \
67
+ git remote add origin https://github.com/cloudcoil/models-$*.git || true && \
68
+ git rm -rf . && \
69
+ git config user.name "github-actions[bot]" && \
70
+ git config user.email "github-actions[bot]@users.noreply.github.com" && \
71
+ cp -a ../../output/models-$*/. . && \
72
+ git add -A && \
73
+ git diff --cached --quiet || git commit -m "Update generated code" && \
74
+ git push -u origin HEAD:main
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudcoil
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary: Cloud native made easy with Python
5
5
  Project-URL: Homepage, https://github.com/cloudcoil/cloudcoil
6
6
  Project-URL: Documentation, https://cloudcoil.github.io/cloudcoil
@@ -53,7 +53,7 @@ Description-Content-Type: text/markdown
53
53
 
54
54
  ## ✨ Features
55
55
 
56
- - 🔥 **Elegant, Pythonic API** - Feels natural to Python developers
56
+ - 🔥 **Elegant, Pythonic API** - Feels natural to Python developers including fluent and context manager style resource builders
57
57
  - ⚡ **Async First** - Native async/await support for high performance
58
58
  - 🛡️ **Type Safe** - Full mypy support and runtime validation
59
59
  - 🧪 **Testing Ready** - Built-in pytest fixtures for K8s integration tests
@@ -114,6 +114,246 @@ for pod in k8s.core.v1.Pod.list(namespace="default"):
114
114
  async for pod in await k8s.core.v1.Pod.async_list():
115
115
  print(f"Found pod: {pod.metadata.name}")
116
116
  ```
117
+ ### Building resources
118
+
119
+ #### Using Models
120
+
121
+ ```python
122
+ from cloudcoil import apimachinery
123
+ import cloudcoil.models.kubernetes.core.v1 as k8score
124
+ import cloudcoil.models.kubernetes.apps.v1 as k8sapps
125
+
126
+ # Create a Deployment
127
+ deployment = k8sapps.Deployment(
128
+ metadata=apimachinery.ObjectMeta(name="nginx"),
129
+ spec=k8sapps.DeploymentSpec(
130
+ replicas=3,
131
+ selector=apimachinery.LabelSelector(
132
+ match_labels={"app": "nginx"}
133
+ ),
134
+ template=k8score.PodTemplateSpec(
135
+ metadata=apimachinery.ObjectMeta(
136
+ labels={"app": "nginx"}
137
+ ),
138
+ spec=k8score.PodSpec(
139
+ containers=[
140
+ k8score.Container(
141
+ name="nginx",
142
+ image="nginx:latest",
143
+ ports=[k8score.ContainerPort(container_port=80)]
144
+ )
145
+ ]
146
+ )
147
+ )
148
+ )
149
+ ).create()
150
+
151
+ # Create a Service
152
+ service = k8score.Service(
153
+ metadata=apimachinery.ObjectMeta(name="nginx"),
154
+ spec=k8score.ServiceSpec(
155
+ selector={"app": "nginx"},
156
+ ports=[k8score.ServicePort(port=80, target_port=80)]
157
+ )
158
+ ).create()
159
+
160
+ # List Deployments
161
+ for deploy in k8sapps.Deployment.list():
162
+ print(f"Found deployment: {deploy.metadata.name}")
163
+
164
+ # Update a Deployment
165
+ deployment.spec.replicas = 5
166
+ deployment.save()
167
+
168
+ # Delete resources
169
+ k8score.Service.delete("nginx")
170
+ k8sapps.Deployment.delete("nginx")
171
+ ```
172
+
173
+ #### Using the Fluent Builder API
174
+
175
+ Cloudcoil provides a powerful fluent builder API for Kubernetes resources with full IDE support and rich autocomplete capabilities:
176
+
177
+ ```python
178
+ from cloudcoil.models.kubernetes.apps.v1 import Deployment
179
+ from cloudcoil.models.kubernetes.core.v1 import Service
180
+
181
+ # Create a Deployment using the fluent builder
182
+ # The fluent style is great for one-liners and simple configurations
183
+ nginx_deployment = (
184
+ Deployment.builder()
185
+ # Metadata can be configured in a single chain for simple objects
186
+ .metadata(lambda metadata: metadata
187
+ .name("nginx")
188
+ .namespace("default")
189
+ )
190
+ # Complex nested structures can be built using nested lambda functions
191
+ .spec(lambda deployment_spec: deployment_spec
192
+ .replicas(3)
193
+ # Each level of nesting gets its own lambda for clarity
194
+ .selector(lambda label_selector: label_selector
195
+ .match_labels({"app": "nginx"})
196
+ )
197
+ .template(lambda pod_template: pod_template
198
+ .metadata(lambda pod_metadata: pod_metadata
199
+ .labels({"app": "nginx"})
200
+ )
201
+ .spec(lambda pod_spec: pod_spec
202
+ # Lists can be built using array literals with lambda items
203
+ .containers([
204
+ lambda container: container
205
+ .name("nginx")
206
+ .image("nginx:latest")
207
+ # Nested collections can use the add() helper
208
+ .ports(lambda port_list: port_list.add(
209
+ lambda port: port.container_port(80)
210
+ ))
211
+ ])
212
+ )
213
+ )
214
+ )
215
+ .build()
216
+ )
217
+
218
+ # Create a Service using the builder
219
+ service = (
220
+ Service.builder()
221
+ .metadata(lambda m: m
222
+ .name("nginx")
223
+ .namespace("default")
224
+ )
225
+ .spec(lambda s: s
226
+ .selector({"app": "nginx"})
227
+ .ports(lambda ports: ports.add(lambda p: p.container_port(80)))
228
+ )
229
+ .build()
230
+ )
231
+ ```
232
+
233
+ The fluent builder provides:
234
+ - ✨ Full IDE support with detailed type information
235
+ - 🔍 Rich autocomplete for all fields and nested objects
236
+ - ⚡ Compile-time validation of your configuration
237
+ - 🎯 Clear and chainable API that guides you through resource creation
238
+
239
+ #### Using the Context Manager Builder API
240
+
241
+ For complex nested resources, Cloudcoil also provides a context manager-based builder pattern that can make the structure more clear:
242
+
243
+ ```python
244
+ from cloudcoil.models.kubernetes.apps.v1 import Deployment
245
+ from cloudcoil.models.kubernetes.core.v1 import Service
246
+
247
+ # Create a deployment using context managers
248
+ # Context managers are ideal for deeply nested structures
249
+ with Deployment.new() as nginx_deployment:
250
+ # Each context creates a clear visual scope
251
+ with nginx_deployment.metadata() as deployment_metadata:
252
+ deployment_metadata.name("nginx")
253
+ deployment_metadata.namespace("default")
254
+
255
+ with nginx_deployment.spec() as deployment_spec:
256
+ # Simple fields can be set directly
257
+ deployment_spec.replicas(3)
258
+
259
+ # Each nested object gets its own context
260
+ with deployment_spec.selector() as label_selector:
261
+ label_selector.match_labels({"app": "nginx"})
262
+
263
+ with deployment_spec.template() as pod_template:
264
+ with pod_template.metadata() as pod_metadata:
265
+ pod_metadata.labels({"app": "nginx"})
266
+
267
+ with pod_template.spec() as pod_spec:
268
+ # Collections use a parent context for the list
269
+ with pod_spec.containers() as container_list:
270
+ # And child contexts for each item
271
+ with container_list.add() as nginx_container:
272
+ nginx_container.name("nginx")
273
+ nginx_container.image("nginx:latest")
274
+ # Ports can be added one by one
275
+ with nginx_container.add_port() as container_port:
276
+ container_port.container_port(80)
277
+
278
+ final_deployment = nginx_deployment.build()
279
+
280
+ # Create a service using context managers
281
+ with Service.new() as nginx_service:
282
+ # Context managers make the structure very clear
283
+ with nginx_service.metadata() as service_metadata:
284
+ service_metadata.name("nginx")
285
+ service_metadata.namespace("default")
286
+
287
+ with nginx_service.spec() as service_spec:
288
+ # Simple fields can still be set directly
289
+ service_spec.selector({"app": "nginx"})
290
+ # Port configuration is more readable with contexts
291
+ with service_spec.add_port() as service_port:
292
+ service_port.port(80)
293
+ service_port.target_port(80)
294
+
295
+ final_service = nginx_service.build()
296
+ ```
297
+
298
+ The context manager builder provides:
299
+ - 🎭 Clear visual nesting of resource structure
300
+ - 🔒 Automatic resource cleanup
301
+ - 🎯 Familiar Python context manager pattern
302
+ - ✨ Same great IDE support as the fluent builder
303
+
304
+ #### Mixing Builder Styles
305
+
306
+ CloudCoil's intelligent builder system automatically detects which style you're using and provides appropriate IDE support:
307
+
308
+ ```python
309
+ from cloudcoil.models.kubernetes.apps.v1 import Deployment
310
+ from cloudcoil import apimachinery
311
+
312
+ # Mixing styles lets you choose the best approach for each part
313
+ # The IDE automatically adapts to your chosen style at each level
314
+ with Deployment.new() as nginx_deployment:
315
+ # Direct object initialization with full type checking
316
+ nginx_deployment.metadata(apimachinery.ObjectMeta(
317
+ name="nginx",
318
+ namespace="default",
319
+ labels={"app": "nginx"}
320
+ ))
321
+
322
+ with nginx_deployment.spec() as deployment_spec:
323
+ # IDE shows all available fields with types
324
+ deployment_spec.replicas(3)
325
+ # Fluent style with rich autocomplete
326
+ deployment_spec.selector(lambda sel: sel.match_labels({"app": "nginx"}))
327
+
328
+ # Context manager style with full type hints
329
+ with deployment_spec.template() as pod_template:
330
+ # Mix and match freely - IDE adjusts automatically
331
+ pod_template.metadata(apimachinery.ObjectMeta(labels={"app": "nginx"}))
332
+ with pod_template.spec() as pod_spec:
333
+ with pod_spec.containers() as container_list:
334
+ with container_list.add() as nginx_container:
335
+ # Complete IDE support regardless of style
336
+ nginx_container.name("nginx")
337
+ nginx_container.image("nginx:latest")
338
+ # Switch styles any time
339
+ nginx_container.ports(lambda ports: ports
340
+ .add(lambda p: p.container_port(80))
341
+ .add(lambda p: p.container_port(443))
342
+ )
343
+
344
+ final_deployment = nginx_deployment.build()
345
+ ```
346
+
347
+ This flexibility allows you to:
348
+ - 🔀 Choose the most appropriate style for each part of your configuration
349
+ - 📖 Maximize readability for both simple and complex structures
350
+ - 🎨 Format your code according to your team's preferences
351
+ - 🧠 Get full IDE support with automatic style detection
352
+ - ✨ Enjoy rich autocomplete in all styles
353
+ - ⚡ Benefit from type checking across mixed styles
354
+ - 🎯 Receive immediate feedback on type errors
355
+ - 🔍 See documentation for all fields regardless of style
356
+
117
357
 
118
358
  ### Creating Resources
119
359
 
@@ -388,7 +628,7 @@ Cloudcoil supports generating typed models from CustomResourceDefinitions (CRDs)
388
628
 
389
629
  ### Using the Cookiecutter Template
390
630
 
391
- The fastest way to get started is using our cookiecutter template: [cloudcoil-models-cookiecutter](https://github.com/cloudcoil/cloudcoil-models-cookiecutter)
631
+ The fastest way to get started is using our cookiecutter template: [cloudcoil-models-cookiecutter](https://github.com/cloudcoil/cloudcoil/tree/main/cookiecutter)
392
632
 
393
633
  ### Codegen Config
394
634