cosmodol 0.0.2__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.
@@ -0,0 +1,179 @@
1
+ ---
2
+ name: cosmodol
3
+ description: Use when developing, reviewing, or extending the cosmodol package (Azure Cosmos DB NoSQL/Core API as dol Mapping interfaces). Triggers on edits under i/cosmodol/, on imports of `cosmodol`, when adding new Cosmos store variants, codecs, or credential paths, when reasoning about partition keys / RU costs / consistency levels, when writing tests against the Cosmos DB emulator, and when answering "how do I use Cosmos DB from Python the dol way".
4
+ ---
5
+
6
+ # cosmodol — Developer & Agent Skill
7
+
8
+ `cosmodol` exposes the **NoSQL (Core/SQL) API of Azure Cosmos DB** as `dol`-style
9
+ `Mapping` / `MutableMapping` interfaces. This skill is the working memory: when modifying
10
+ or extending the package, read this first, then dive into the
11
+ [misc/docs/](../../../misc/docs/) trio that this file distills.
12
+
13
+ **Source of truth** (always defer to these):
14
+
15
+ - `misc/docs/architecture.md` — the layered design and class hierarchy.
16
+ - `misc/docs/cosmos_db_reference.md` — Cosmos service + `azure-cosmos` SDK facts.
17
+ - `misc/docs/design_decisions.md` — every defaulted choice with rationale.
18
+
19
+ ---
20
+
21
+ ## Mental model in one diagram
22
+
23
+ ```
24
+ cosmodol.recipes ← cosmos_store(...) factory, codec layers
25
+ cosmodol.trees ← CosmosAccount, CosmosDatabase (mappings of children)
26
+ cosmodol.stores ← CosmosItems (one partition), CosmosPartitionedItems (whole container)
27
+ cosmodol.base ← free functions: point_get/upsert/replace/delete, query, batch
28
+ cosmodol.connection ← CosmosConnection: credential cascade, lazy CosmosClient
29
+ cosmodol.errors ← @translate_cosmos_errors decorator, custom KeyError subclasses
30
+ cosmodol.testing ← vNext emulator fixture, FakeContainerProxy for unit tests
31
+ ```
32
+
33
+ The two primary stores live in `stores.py`. Pick the right one:
34
+
35
+ | You have… | Use |
36
+ |---|---|
37
+ | A fixed partition-key value | `CosmosItems(container, partition_key_value=...)` — keys are id strings |
38
+ | The whole container | `CosmosPartitionedItems(container, partition_key_path=...)` — keys are `(pk_value, id)` tuples |
39
+
40
+ ## Non-negotiable rules
41
+
42
+ 1. **Scope is `azure-cosmos` (NoSQL API) only.** Cosmos-for-MongoDB accounts are not addressable through this SDK — route those users to `pymongo` + `mongodol`. The README must remain explicit about this.
43
+ 2. **Class names are `Cosmos*` prefixed.** "Container" / "Database" collide with Blob's terminology and with generic Python — always say `CosmosContainer`-something or `CosmosDatabase`-something.
44
+ 3. **`dol`-house base classes only.** Subclass `KvReader` / `KvPersister` from `dol.base`, never `Mapping` / `MutableMapping` directly.
45
+ 4. **`__getitem__` and `__contains__` are ALWAYS point reads** (`read_item` with `partition_key=`). Never a query. ~1 RU vs ≥ 2.3 RU + result-size charge.
46
+ 5. **`__len__` on `CosmosPartitionedItems` is NOT implemented by default.** Opt-in via `len_via_query=True`. `CosmosItems.__len__` (single-partition) is OK and implemented.
47
+ 6. **`__iter__` on a full-container store emits a `UserWarning`** on first call (silence with `silent_full_scan=True`). Cross-partition scans are an economic land mine.
48
+ 7. **All Cosmos-exception catches happen in `errors.py`.** `@translate_cosmos_errors` is the only path; auth/throttle errors never translate to "key absent".
49
+ 8. **`__setitem__` auto-injects `id` (and `partition_key`) into the body.** If user-provided body already has those fields and they *disagree* with the inferred values, raise `KeyMismatchError` — never silently overwrite user dicts.
50
+ 9. **Container/database creation is NEVER through `__setitem__`.** Use explicit `add_container(name, partition_key_path=..., throughput=..., ...)` and `add_database(name, throughput=...)`. Too parameter-rich for one-arg dict assignment.
51
+ 10. **`del tree_store[name]` refuses non-empty children.** `tree_store.delete(name, force=True)` is the explicit purge.
52
+ 11. **No silent destruction. No silent expensive ops. No silent partition crossing.** Every potentially expensive call has either a fixed-cost path (point read) or an explicit cost-aware opt-in flag.
53
+ 12. **`id` is validated on writes** — string, ≤255 chars, no `/ \ ? #`. Cosmos may accept invalid ids but the item then becomes unreachable from the SDK.
54
+
55
+ ## RU observability — required, not optional
56
+
57
+ Every Layer A function returns `(value, ResponseHeaders)` where `ResponseHeaders` carries
58
+ `request_charge` (RU) and `etag`. Every Layer B store exposes `store.last_request_charge`
59
+ (an `Optional[float]`) after each op and accepts a `record_ru` callback:
60
+
61
+ ```python
62
+ items = CosmosItems(container, partition_key_value="t",
63
+ record_ru=lambda op, ru: prom.observe(op, ru))
64
+ items["k1"]
65
+ items.last_request_charge # → float (RU consumed)
66
+ ```
67
+
68
+ If you add a new operation, **route it through the metal-layer free functions** so it
69
+ collects RU automatically. Don't call `container.read_item(...)` directly from the store.
70
+
71
+ ## Partition-key playbook
72
+
73
+ The defining design fact in Cosmos. cosmodol exposes three idiomatic shapes; pick the
74
+ right one in your example/test:
75
+
76
+ | User has… | Recommended cosmodol class | Notes |
77
+ |---|---|---|
78
+ | One logical bucket of items (single tenant, single session) | `CosmosItems(container, partition_key_value="tenant-X")` | Simplest dict surface. Keys = `id`. |
79
+ | A multi-tenant container, each item is its own partition | `CosmosPartitionedItems(container, partition_key_path="/id")` | **Recommended default** for new containers. Best write distribution. Cross-partition queries needed for non-id WHERE clauses. |
80
+ | An existing container with a custom partition scheme | `CosmosPartitionedItems(container, partition_key_path="/whatever")` | Keys = `(pk_value, id)` tuples. |
81
+ | A view scoped to one partition of an existing partitioned container | `partitioned.partition(pk_value)` → `CosmosItems` | Zero round-trip narrowing. |
82
+
83
+ **Never** invent a 4th shape with a separator-joined string key (`"tenant42::user99"`) —
84
+ escaping the separator is more trouble than the tuple is worth. Users who want flat
85
+ strings compose `wrap_kvs` on top.
86
+
87
+ ## Adding a new value codec / key transform
88
+
89
+ Layer C only. Never subclass `CosmosItems` to add a codec — use `dol`'s composition tools:
90
+
91
+ ```python
92
+ from dol import wrap_kvs, ValueCodecs
93
+ from cosmodol.stores import CosmosItems
94
+
95
+ # Right way: compose
96
+ CosmosBytesStore = wrap_kvs(
97
+ CosmosItems,
98
+ value_codec=ValueCodecs.pickle_b64_in_property('_blob'),
99
+ )
100
+
101
+ # Wrong way: subclass
102
+ class CosmosBytesStore(CosmosItems): # don't do this
103
+ def __getitem__(self, k):
104
+ return base64.b64decode(super().__getitem__(k)['_blob'])
105
+ ```
106
+
107
+ When the codec wraps the user's value into a Cosmos-shaped envelope `{"_blob": "..."}`,
108
+ make sure your `data_of_obj` does NOT overwrite `id` or the partition-key property —
109
+ those are injected by the store layer.
110
+
111
+ ## Adding a new connection path / credential type
112
+
113
+ `cosmodol.connection.resolve_credential(...)` is the single place. Extend its cascade,
114
+ update `design_decisions.md` §14, and add a test in `tests/test_connection.py` that
115
+ exercises the new branch.
116
+
117
+ Document order of precedence in `architecture.md` Layer 0.
118
+
119
+ ## Adding to the metal layer (when a new SDK feature lands)
120
+
121
+ Add a free function in `base.py` (not a method on a store). Wrap it with
122
+ `@translate_cosmos_errors` for any path that touches an item. Return
123
+ `(value, ResponseHeaders)` so RU charges are observable. Then surface it at Layer B if it's
124
+ genuinely Mapping-shaped, or as a top-level method on the relevant store otherwise.
125
+
126
+ ## Testing protocol
127
+
128
+ 1. **Unit tests** use `FakeContainerProxy` from `cosmodol.testing` — a dict-of-dicts-backed mock implementing the subset of `ContainerProxy` methods the metal layer uses. Fast, no Docker.
129
+ 2. **Integration tests** use the Linux vNext emulator via the `cosmos_emulator` fixture (Docker-backed). Skipped with a clear message when Docker unavailable.
130
+ 3. **Skip RU-charge assertions** when running against the emulator — the emulator does NOT populate `x-ms-request-charge`. The fixture sets a marker flag the tests can check.
131
+ 4. **Doctests** in module docstrings stay runnable (`NORMALIZE_WHITESPACE` + `ELLIPSIS` enabled).
132
+ 5. **Live-Azure tests** gated by env var `AZURE_COSMOS_LIVE_TEST_ENDPOINT`; never run in CI by default.
133
+
134
+ ## Spinning up the Cosmos emulator locally (Mac/ARM friendly)
135
+
136
+ ```bash
137
+ docker pull mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview
138
+ docker run --detach \
139
+ --publish 8081:8081 --publish 8080:8080 --publish 1234:1234 \
140
+ mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview
141
+ ```
142
+
143
+ Well-known credentials (same on every emulator instance):
144
+
145
+ ```
146
+ Endpoint: https://localhost:8081
147
+ Key: C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==
148
+ ```
149
+
150
+ Use `--protocol http` if the HTTPS cert dance is painful.
151
+
152
+ Emulator **does not** support: stored procs/triggers/UDFs, parallel cross-partition
153
+ queries, offers/permissions/users, custom indexing policies (accepted but no-op), RU
154
+ accounting (header missing). Don't write tests that depend on those features.
155
+
156
+ ## Common operations cheatsheet
157
+
158
+ | Want to... | Use |
159
+ |---|---|
160
+ | Dict over one partition | `CosmosItems(container, partition_key_value="X")` |
161
+ | Dict over the whole container, tuple keys | `CosmosPartitionedItems(container, partition_key_path="/_pk")` |
162
+ | Narrow a partitioned store to one partition | `partitioned.partition("X")` → `CosmosItems` |
163
+ | Narrow with a WHERE clause | `items.with_filter("c.status = 'active'")` |
164
+ | List databases | `for name in CosmosAccount(connection): ...` |
165
+ | List containers | `for name in CosmosDatabase(connection, "mydb"): ...` |
166
+ | Create a new container | `db_store.add_container("mycoll", partition_key_path="/id")` |
167
+ | Run a SQL query | `items.query("SELECT * FROM c WHERE c.age > @a", parameters=[{"name":"@a","value":18}])` |
168
+ | Transactional batch (one partition) | `items.batch([("upsert", {"id":"k","v":1}), ("delete", "k2"), ...])` |
169
+ | Conditional replace via ETag | `items.replace("k", new_body, etag=items.last_response_headers.etag)` |
170
+ | One-call factory | `recipes.cosmos_store(connection_string=..., database=..., container=..., partition_key_value=...)` |
171
+
172
+ ## When in doubt
173
+
174
+ - Defaults always lean cost-visible (no auto-len, no implicit cross-partition).
175
+ - Defaults always lean Mapping-faithful (KeyError on missing, point reads for contains/get).
176
+ - Surface always leans `dol`-composable (wrap_kvs over subclasses, codecs over methods).
177
+
178
+ When changing a default, update `design_decisions.md` in the **same** PR. The doc IS the
179
+ contract.
@@ -0,0 +1,234 @@
1
+ name: Continuous Integration (uv)
2
+ # MIGRATION NOTE: Old CI uses pylint - new CI uses ruff for linting
3
+ # MIGRATION NOTE: PyPI auth changed: set secrets.PYPI_PASSWORD to a PyPI API token (uv publish uses UV_PUBLISH_TOKEN, mapped from PYPI_PASSWORD)
4
+ on: [push, pull_request]
5
+
6
+ # Workflow-level env vars from [tool.wads.ci.env] in pyproject.toml.
7
+ # Populated by wads-migrate / wads init via template substitution.
8
+ # Includes PROJECT_NAME, literal defaults from env.defaults, and secret-
9
+ # backed vars from required_envvars / test_envvars / extra_envvars,
10
+ # rendered as `KEY: secrets.KEY || ''` so missing secrets don't fail parsing.
11
+ env:
12
+ PROJECT_NAME: cosmodol
13
+
14
+ jobs:
15
+ # First job: Read configuration from pyproject.toml
16
+ setup:
17
+ name: Read Configuration
18
+ runs-on: ubuntu-latest
19
+ outputs:
20
+ project-name: ${{ steps.config.outputs.project-name }}
21
+ python-versions: ${{ steps.config.outputs.python-versions }}
22
+ pytest-args: ${{ steps.config.outputs.pytest-args }}
23
+ coverage-enabled: ${{ steps.config.outputs.coverage-enabled }}
24
+ exclude-paths: ${{ steps.config.outputs.exclude-paths }}
25
+ test-on-windows: ${{ steps.config.outputs.test-on-windows }}
26
+ build-sdist: ${{ steps.config.outputs.build-sdist }}
27
+ build-wheel: ${{ steps.config.outputs.build-wheel }}
28
+ metrics-enabled: ${{ steps.config.outputs.metrics-enabled }}
29
+ metrics-config-path: ${{ steps.config.outputs.metrics-config-path }}
30
+ metrics-storage-branch: ${{ steps.config.outputs.metrics-storage-branch }}
31
+ metrics-python-version: ${{ steps.config.outputs.metrics-python-version }}
32
+ metrics-force-run: ${{ steps.config.outputs.metrics-force-run }}
33
+ ruff-enabled: ${{ steps.config.outputs.ruff-enabled }}
34
+ black-enabled: ${{ steps.config.outputs.black-enabled }}
35
+ mypy-enabled: ${{ steps.config.outputs.mypy-enabled }}
36
+ docs-enabled: ${{ steps.config.outputs.docs-enabled }}
37
+
38
+ steps:
39
+ - uses: actions/checkout@v6
40
+
41
+ - name: Set up uv
42
+ uses: astral-sh/setup-uv@v7
43
+
44
+ - name: Set up Python
45
+ run: uv python install 3.11
46
+
47
+ - name: Read CI Config
48
+ id: config
49
+ uses: i2mint/wads/actions/read-ci-config@master
50
+ with:
51
+ pyproject-path: .
52
+
53
+ # Second job: Validation using the config
54
+ validation:
55
+ name: Validation
56
+ if: "!contains(github.event.head_commit.message, '[skip ci]')"
57
+ needs: setup
58
+ runs-on: ubuntu-latest
59
+ strategy:
60
+ matrix:
61
+ python-version: ${{ fromJson(needs.setup.outputs.python-versions) }}
62
+
63
+ steps:
64
+ - uses: actions/checkout@v6
65
+
66
+ - name: Set up uv
67
+ uses: astral-sh/setup-uv@v7
68
+ with:
69
+ enable-cache: true
70
+
71
+ - name: Set up Python ${{ matrix.python-version }}
72
+ uses: i2mint/wads/actions/setup-python-uv@master
73
+ with:
74
+ python-version: ${{ matrix.python-version }}
75
+
76
+ - name: Install System Dependencies
77
+ uses: i2mint/wads/actions/install-system-deps@master
78
+ with:
79
+ pyproject-path: .
80
+
81
+ - name: Install Dependencies
82
+ uses: i2mint/wads/actions/install-deps-uv@master
83
+
84
+ - name: Format Source Code
85
+ if: needs.setup.outputs.ruff-enabled != 'false'
86
+ run: uvx ruff format .
87
+
88
+ - name: Format Source Code (black)
89
+ if: needs.setup.outputs.black-enabled == 'true'
90
+ run: uvx black .
91
+
92
+ - name: Lint Validation
93
+ if: needs.setup.outputs.ruff-enabled != 'false'
94
+ run: uvx ruff check --output-format=github ${{ needs.setup.outputs.project-name }}
95
+
96
+ - name: Type Check (mypy)
97
+ if: needs.setup.outputs.mypy-enabled == 'true'
98
+ run: uvx mypy ${{ needs.setup.outputs.project-name }}
99
+
100
+ - name: Run Tests
101
+ uses: i2mint/wads/actions/run-tests-uv@master
102
+ with:
103
+ root-dir: ${{ needs.setup.outputs.project-name }}
104
+ pytest-args: ${{ needs.setup.outputs.pytest-args }}
105
+ exclude-paths: ${{ needs.setup.outputs.exclude-paths }}
106
+ coverage: ${{ needs.setup.outputs.coverage-enabled }}
107
+
108
+ - name: Track Code Metrics
109
+ if: needs.setup.outputs.metrics-enabled == 'true'
110
+ uses: i2mint/umpyre/actions/track-metrics@master
111
+ continue-on-error: true
112
+ with:
113
+ github-token: ${{ secrets.GITHUB_TOKEN }}
114
+ config-path: ${{ needs.setup.outputs.metrics-config-path }}
115
+ storage-branch: ${{ needs.setup.outputs.metrics-storage-branch }}
116
+ python-version: ${{ needs.setup.outputs.metrics-python-version }}
117
+ force-run: ${{ needs.setup.outputs.metrics-force-run }}
118
+
119
+ # Optional Windows testing (if enabled in config)
120
+ windows-validation:
121
+ name: Windows Tests
122
+ if: "!contains(github.event.head_commit.message, '[skip ci]') && needs.setup.outputs.test-on-windows == 'true'"
123
+ needs: setup
124
+ runs-on: windows-latest
125
+ continue-on-error: true
126
+
127
+ steps:
128
+ - uses: actions/checkout@v6
129
+
130
+ - name: Set up uv
131
+ uses: astral-sh/setup-uv@v7
132
+ with:
133
+ enable-cache: true
134
+
135
+ - name: Set up Python
136
+ uses: i2mint/wads/actions/setup-python-uv@master
137
+ with:
138
+ python-version: ${{ fromJson(needs.setup.outputs.python-versions)[0] }}
139
+
140
+ - name: Install System Dependencies
141
+ uses: i2mint/wads/actions/install-system-deps@master
142
+ with:
143
+ pyproject-path: .
144
+
145
+ - name: Install Dependencies
146
+ uses: i2mint/wads/actions/install-deps-uv@master
147
+
148
+ - name: Run Tests
149
+ uses: i2mint/wads/actions/run-tests-uv@master
150
+ with:
151
+ root-dir: ${{ needs.setup.outputs.project-name }}
152
+ pytest-args: ${{ needs.setup.outputs.pytest-args }}
153
+ exclude-paths: ${{ needs.setup.outputs.exclude-paths }}
154
+
155
+ # Publishing job
156
+ publish:
157
+ name: Publish
158
+ permissions:
159
+ contents: write
160
+ if: "!contains(github.event.head_commit.message, '[skip ci]') && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main')"
161
+ needs: [setup, validation]
162
+ runs-on: ubuntu-latest
163
+
164
+ steps:
165
+ - uses: actions/checkout@v6
166
+ with:
167
+ fetch-depth: 0
168
+ token: ${{ secrets.GITHUB_TOKEN }}
169
+
170
+ - name: Set up uv
171
+ uses: astral-sh/setup-uv@v7
172
+
173
+ - name: Set up Python
174
+ uses: i2mint/wads/actions/setup-python-uv@master
175
+ with:
176
+ python-version: ${{ fromJson(needs.setup.outputs.python-versions)[0] }}
177
+ create-venv: "false"
178
+
179
+ - name: Format Source Code
180
+ if: needs.setup.outputs.ruff-enabled != 'false'
181
+ run: uvx ruff format .
182
+
183
+ - name: Format Source Code (black)
184
+ if: needs.setup.outputs.black-enabled == 'true'
185
+ run: uvx black .
186
+
187
+ - name: Update Version Number
188
+ id: version
189
+ uses: i2mint/isee/actions/bump-version-number@master
190
+
191
+ - name: Build Distribution
192
+ uses: i2mint/wads/actions/build-dist-uv@master
193
+ with:
194
+ sdist: ${{ needs.setup.outputs.build-sdist }}
195
+ wheel: ${{ needs.setup.outputs.build-wheel }}
196
+
197
+ - name: Publish to PyPI
198
+ uses: i2mint/wads/actions/pypi-publish-uv@master
199
+ with:
200
+ pypi-token: ${{ secrets.PYPI_PASSWORD }}
201
+
202
+ - name: Force SSH for git remote
203
+ run: git remote set-url origin git@github.com:${{ github.repository }}.git
204
+
205
+ - name: Commit Changes
206
+ uses: i2mint/wads/actions/git-commit@master
207
+ with:
208
+ commit-message: "**CI** Formatted code + Updated version to ${{ env.VERSION }} [skip ci]"
209
+ ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
210
+ push: true
211
+
212
+ - name: Tag Repository
213
+ uses: i2mint/wads/actions/git-tag@master
214
+ with:
215
+ tag: ${{ env.VERSION }}
216
+ message: "Release version ${{ env.VERSION }}"
217
+ push: true
218
+
219
+ # Optional GitHub Pages (skipped when [tool.wads.ci.docs].enabled = false)
220
+ github-pages:
221
+ name: Publish GitHub Pages
222
+ permissions:
223
+ contents: write
224
+ pages: write
225
+ id-token: write
226
+ if: "!contains(github.event.head_commit.message, '[skip ci]') && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && needs.setup.outputs.docs-enabled != 'false'"
227
+ needs: [setup, publish]
228
+ runs-on: ubuntu-latest
229
+
230
+ steps:
231
+ - uses: i2mint/epythet/actions/publish-github-pages@master
232
+ with:
233
+ github-token: ${{ secrets.GITHUB_TOKEN }}
234
+ ignore: "tests/,scrap/,examples/"
@@ -0,0 +1,138 @@
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
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
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
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+ *.ipynb
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ .python-version
87
+
88
+ # pipenv
89
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
90
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
91
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
92
+ # install all needed dependencies.
93
+ #Pipfile.lock
94
+
95
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
96
+ __pypackages__/
97
+
98
+ # Celery stuff
99
+ celerybeat-schedule
100
+ celerybeat.pid
101
+
102
+ # SageMath parsed files
103
+ *.sage.py
104
+
105
+ # Environments
106
+ .env
107
+ .venv
108
+ env/
109
+ venv/
110
+ ENV/
111
+ env.bak/
112
+ venv.bak/
113
+
114
+ # Spyder project settings
115
+ .spyderproject
116
+ .spyproject
117
+
118
+ # Rope project settings
119
+ .ropeproject
120
+
121
+ # mkdocs documentation
122
+ /site
123
+
124
+ # mypy
125
+ .mypy_cache/
126
+ .dmypy.json
127
+ dmypy.json
128
+
129
+ # Pyre type checker
130
+ .pyre/
131
+
132
+ # IDE
133
+ .idea
134
+
135
+ # Azurite
136
+ __azurite*
137
+ __blobstorage__/
138
+ __queuestorage__/