Skip to content

Commit 6deb5cb

Browse files
committed
general: cleanup/sync CI files/switch to hatch for publishing
1 parent 4586450 commit 6deb5cb

File tree

23 files changed

+171
-145
lines changed

23 files changed

+171
-145
lines changed

.bandit.yml

Lines changed: 0 additions & 6 deletions
This file was deleted.

.github/workflows/main.yml

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ on:
66
branches: '*'
77
tags: 'v[0-9]+.*' # only trigger on 'release' tags for PyPi
88
# Ideally I would put this in the pypi job... but github syntax doesn't allow for regexes there :shrug:
9-
# P.S. fuck made up yaml DSLs.
109
pull_request: # needed to trigger on others' PRs
1110
# Note that people who fork it need to go to "Actions" tab on their fork and click "I understand my workflows, go ahead and enable them".
1211
workflow_dispatch: # needed to trigger workflows manually
@@ -31,10 +30,18 @@ jobs:
3130

3231
runs-on: ${{ matrix.platform }}
3332

33+
# useful for 'optional' pipelines
34+
# continue-on-error: ${{ matrix.platform == 'windows-latest' }}
35+
3436
steps:
3537
# ugh https://github.com/actions/toolkit/blob/main/docs/commands.md#path-manipulation
3638
- run: echo "$HOME/.local/bin" >> $GITHUB_PATH
3739

40+
- uses: actions/checkout@v4
41+
with:
42+
submodules: recursive
43+
fetch-depth: 0 # nicer to have all git history when debugging/for tests
44+
3845
- uses: actions/setup-python@v5
3946
with:
4047
python-version: ${{ matrix.python-version }}
@@ -43,11 +50,6 @@ jobs:
4350
with:
4451
enable-cache: false # we don't have lock files, so can't use them as cache key
4552

46-
- uses: actions/checkout@v4
47-
with:
48-
submodules: recursive
49-
fetch-depth: 0 # nicer to have all git history when debugging/for tests
50-
5153
- uses: mxschmitt/action-tmate@v3
5254
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
5355

@@ -72,6 +74,10 @@ jobs:
7274
# ugh https://github.com/actions/toolkit/blob/main/docs/commands.md#path-manipulation
7375
- run: echo "$HOME/.local/bin" >> $GITHUB_PATH
7476

77+
- uses: actions/checkout@v4
78+
with:
79+
submodules: recursive
80+
7581
- uses: actions/setup-python@v5
7682
with:
7783
python-version: '3.10'
@@ -80,10 +86,6 @@ jobs:
8086
with:
8187
enable-cache: false # we don't have lock files, so can't use them as cache key
8288

83-
- uses: actions/checkout@v4
84-
with:
85-
submodules: recursive
86-
8789
- name: 'release to test pypi'
8890
# always deploy merged master to test pypi
8991
if: github.event_name != 'pull_request' && github.event.ref == 'refs/heads/master'

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,5 @@ dmypy.json
179179
.pyre/
180180

181181
# End of https://www.gitignore.io/api/python,emacs
182+
183+
untracked/

README.ipynb

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,31 @@
1616
},
1717
"outputs": [],
1818
"source": [
19-
"from pathlib import Path\n",
20-
"import sys; sys.path.insert(0, str(Path('src').absolute()))\n",
21-
"import os\n",
22-
"cwd =os.getcwd()\n",
19+
"from __future__ import annotations\n",
2320
"\n",
2421
"import ast\n",
2522
"import inspect\n",
23+
"import sys\n",
24+
"from pathlib import Path\n",
2625
"\n",
2726
"from IPython.display import Markdown as md\n",
2827
"\n",
29-
"def flink(title: str, name: str=None):\n",
28+
"##\n",
29+
"sys.path.insert(0, str(Path('src').absolute()))\n",
30+
"import cachew # isort: skip\n",
31+
"import cachew.extra # isort: skip\n",
32+
"import cachew.marshall.cachew # isort: skip\n",
33+
"import cachew.tests.test_cachew as tests # isort: skip\n",
34+
"sys.modules['tests'] = tests # meh\n",
35+
"##\n",
36+
"\n",
37+
"_CWD = Path.cwd()\n",
38+
"\n",
39+
"\n",
40+
"def flink(title: str, name: str | None = None) -> str:\n",
3041
" # name is method name\n",
3142
" if name is None:\n",
32-
" name = title.replace('`', '') # meh\n",
43+
" name = title.replace('`', '') # meh\n",
3344
" split = name.rsplit('.', maxsplit=1)\n",
3445
" if len(split) == 1:\n",
3546
" modname = split[0]\n",
@@ -38,7 +49,7 @@
3849
" [modname, fname] = split\n",
3950
" module = sys.modules[modname]\n",
4051
"\n",
41-
" file = Path(module.__file__).relative_to(cwd)\n",
52+
" file = Path(module.__file__).relative_to(_CWD)\n",
4253
"\n",
4354
" if fname is not None:\n",
4455
" func = module\n",
@@ -50,13 +61,8 @@
5061
" numbers = ''\n",
5162
" return f'[{title}]({file}{numbers})'\n",
5263
"\n",
53-
"dmd = lambda x: display(md(x.strip()))\n",
5464
"\n",
55-
"import cachew\n",
56-
"import cachew.extra\n",
57-
"import cachew.marshall.cachew\n",
58-
"import cachew.tests.test_cachew as tests\n",
59-
"sys.modules['tests'] = tests # meh"
65+
"dmd = lambda x: display(md(x.strip()))"
6066
]
6167
},
6268
{
@@ -72,10 +78,10 @@
7278
},
7379
"outputs": [],
7480
"source": [
75-
"dmd(f'''\n",
81+
"dmd('''\n",
7682
"<!--\n",
7783
"THIS FILE IS AUTOGENERATED BY README.ipynb.\n",
78-
"Ideally you should edit README.ipynb and use 'generate-readme' to produce README.md. \n",
84+
"Ideally you should edit README.ipynb and use 'generate-readme' to produce README.md.\n",
7985
"But it's okay to edit README.md too directly if you want to fix something -- I can run generate-readme myself later.\n",
8086
"-->\n",
8187
"''')"
@@ -221,21 +227,21 @@
221227
"outputs": [],
222228
"source": [
223229
"[composite] = [x\n",
224-
" for x in ast.walk(ast.parse(inspect.getsource(cachew))) \n",
230+
" for x in ast.walk(ast.parse(inspect.getsource(cachew)))\n",
225231
" if isinstance(x, ast.FunctionDef) and x.name == 'composite_hash'\n",
226232
"]\n",
227233
"\n",
228-
"link = f'{Path(cachew.__file__).relative_to(cwd)}:#L{composite.lineno}'\n",
234+
"link = f'{Path(cachew.__file__).relative_to(_CWD)}:#L{composite.lineno}'\n",
229235
"\n",
230236
"dmd(f'''\n",
231237
"# How it works\n",
232238
"\n",
233-
"- first your objects get {flink('converted', 'cachew.marshall.cachew.CachewMarshall')} into a simpler JSON-like representation \n",
239+
"- first your objects get {flink('converted', 'cachew.marshall.cachew.CachewMarshall')} into a simpler JSON-like representation\n",
234240
"- after that, they are mapped into byte blobs via [`orjson`](https://github.com/ijl/orjson).\n",
235241
"\n",
236242
"When the function is called, cachew [computes the hash of your function's arguments ]({link})\n",
237243
"and compares it against the previously stored hash value.\n",
238-
" \n",
244+
"\n",
239245
"- If they match, it would deserialize and yield whatever is stored in the cache database\n",
240246
"- If the hash mismatches, the original function is called and new data is stored along with the new hash\n",
241247
"''')"
@@ -258,17 +264,17 @@
258264
"types = [f'`{t}`' for t in ['str', 'int', 'float', 'bool', 'datetime', 'date', 'Exception']]\n",
259265
"dmd(f\"\"\"\n",
260266
"* automatic schema inference: {flink('1', 'tests.test_return_type_inference')}, {flink('2', 'tests.test_return_type_mismatch')}\n",
261-
"* supported types: \n",
267+
"* supported types:\n",
262268
"\n",
263269
" * primitive: {', '.join(types)}\n",
264-
" \n",
270+
"\n",
265271
" See {flink('tests.test_types')}, {flink('tests.test_primitive')}, {flink('tests.test_dates')}, {flink('tests.test_exceptions')}\n",
266272
" * {flink('@dataclass and NamedTuple', 'tests.test_dataclass')}\n",
267273
" * {flink('Optional', 'tests.test_optional')} types\n",
268274
" * {flink('Union', 'tests.test_union')} types\n",
269275
" * {flink('nested datatypes', 'tests.test_nested')}\n",
270-
" \n",
271-
"* detects {flink('datatype schema changes', 'tests.test_schema_change')} and discards old data automatically \n",
276+
"\n",
277+
"* detects {flink('datatype schema changes', 'tests.test_schema_change')} and discards old data automatically\n",
272278
"\"\"\")\n",
273279
"# * custom hash function TODO example with mtime?"
274280
]
@@ -302,24 +308,24 @@
302308
"source": [
303309
"dmd(f\"\"\"\n",
304310
"# Using\n",
305-
"See {flink('docstring', 'cachew.cachew')} for up-to-date documentation on parameters and return types. \n",
311+
"See {flink('docstring', 'cachew.cachew')} for up-to-date documentation on parameters and return types.\n",
306312
"You can also use {flink('extensive unit tests', 'tests')} as a reference.\n",
307-
" \n",
313+
"\n",
308314
"Some useful (but optional) arguments of `@cachew` decorator:\n",
309-
" \n",
315+
"\n",
310316
"* `cache_path` can be a directory, or a callable that {flink('returns a path', 'tests.test_callable_cache_path')} and depends on function's arguments.\n",
311-
" \n",
317+
"\n",
312318
" By default, `settings.DEFAULT_CACHEW_DIR` is used.\n",
313-
" \n",
319+
"\n",
314320
"* `depends_on` is a function which determines whether your inputs have changed, and the cache needs to be invalidated.\n",
315-
" \n",
321+
"\n",
316322
" By default it just uses string representation of the arguments, you can also specify a custom callable.\n",
317-
" \n",
323+
"\n",
318324
" For instance, it can be used to {flink('discard cache', 'tests.test_custom_hash')} if the input file was modified.\n",
319-
" \n",
325+
"\n",
320326
"* `cls` is the type that would be serialized.\n",
321327
"\n",
322-
" By default, it is inferred from return type annotations, but can be specified explicitly if you don't control the code you want to cache. \n",
328+
" By default, it is inferred from return type annotations, but can be specified explicitly if you don't control the code you want to cache.\n",
323329
"\"\"\")"
324330
]
325331
},
@@ -415,6 +421,7 @@
415421
"outputs": [],
416422
"source": [
417423
"import cachew.extra\n",
424+
"\n",
418425
"dmd(f\"\"\"```python\n",
419426
"{inspect.getsource(cachew.extra.mcachew)}\n",
420427
"```\"\"\")"
@@ -442,7 +449,7 @@
442449
"- `DEFAULT_CACHEW_DIR`: override to set a different base directory. The default is the \"user cache directory\" (see [platformdirs docs](https://github.com/tox-dev/platformdirs?tab=readme-ov-file#example-output)).\n",
443450
"- `THROW_ON_ERROR`: by default, cachew is defensive and simply attemps to cause the original function on caching issues.\n",
444451
" Set to `True` to catch errors earlier.\n",
445-
"- `DEFAULT_BACKEND`: currently supported are `sqlite` and `file` (file is somewhat experimental, although should work too). \n",
452+
"- `DEFAULT_BACKEND`: currently supported are `sqlite` and `file` (file is somewhat experimental, although should work too).\n",
446453
"\n",
447454
"''')"
448455
]

README.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!--
22
THIS FILE IS AUTOGENERATED BY README.ipynb.
3-
Ideally you should edit README.ipynb and use 'generate-readme' to produce README.md.
3+
Ideally you should edit README.ipynb and use 'generate-readme' to produce README.md.
44
But it's okay to edit README.md too directly if you want to fix something -- I can run generate-readme myself later.
55
-->
66

@@ -125,12 +125,12 @@ Cachew gives the best of two worlds and makes it both **easy and efficient**. Th
125125

126126
# How it works
127127

128-
- first your objects get [converted](src/cachew/marshall/cachew.py#L30) into a simpler JSON-like representation
128+
- first your objects get [converted](src/cachew/marshall/cachew.py#L30) into a simpler JSON-like representation
129129
- after that, they are mapped into byte blobs via [`orjson`](https://github.com/ijl/orjson).
130130

131-
When the function is called, cachew [computes the hash of your function's arguments ](src/cachew/__init__.py:#L588)
131+
When the function is called, cachew [computes the hash of your function's arguments ](src/cachew/__init__.py:#L587)
132132
and compares it against the previously stored hash value.
133-
133+
134134
- If they match, it would deserialize and yield whatever is stored in the cache database
135135
- If the hash mismatches, the original function is called and new data is stored along with the new hash
136136

@@ -141,16 +141,16 @@ and compares it against the previously stored hash value.
141141

142142

143143
* automatic schema inference: [1](src/cachew/tests/test_cachew.py#L387), [2](src/cachew/tests/test_cachew.py#L401)
144-
* supported types:
144+
* supported types:
145145

146146
* primitive: `str`, `int`, `float`, `bool`, `datetime`, `date`, `Exception`
147-
147+
148148
See [tests.test_types](src/cachew/tests/test_cachew.py#L687), [tests.test_primitive](src/cachew/tests/test_cachew.py#L725), [tests.test_dates](src/cachew/tests/test_cachew.py#L637), [tests.test_exceptions](src/cachew/tests/test_cachew.py#L1124)
149149
* [@dataclass and NamedTuple](src/cachew/tests/test_cachew.py#L602)
150150
* [Optional](src/cachew/tests/test_cachew.py#L531) types
151151
* [Union](src/cachew/tests/test_cachew.py#L832) types
152152
* [nested datatypes](src/cachew/tests/test_cachew.py#L447)
153-
153+
154154
* detects [datatype schema changes](src/cachew/tests/test_cachew.py#L477) and discards old data automatically
155155

156156

@@ -165,21 +165,21 @@ You can find some of my performance tests in [benchmarks/](benchmarks) dir, and
165165

166166

167167
# Using
168-
See [docstring](src/cachew/__init__.py#L292) for up-to-date documentation on parameters and return types.
168+
See [docstring](src/cachew/__init__.py#L292) for up-to-date documentation on parameters and return types.
169169
You can also use [extensive unit tests](src/cachew/tests/test_cachew.py) as a reference.
170-
170+
171171
Some useful (but optional) arguments of `@cachew` decorator:
172-
172+
173173
* `cache_path` can be a directory, or a callable that [returns a path](src/cachew/tests/test_cachew.py#L424) and depends on function's arguments.
174-
174+
175175
By default, `settings.DEFAULT_CACHEW_DIR` is used.
176-
176+
177177
* `depends_on` is a function which determines whether your inputs have changed, and the cache needs to be invalidated.
178-
178+
179179
By default it just uses string representation of the arguments, you can also specify a custom callable.
180-
180+
181181
For instance, it can be used to [discard cache](src/cachew/tests/test_cachew.py#L119) if the input file was modified.
182-
182+
183183
* `cls` is the type that would be serialized.
184184

185185
By default, it is inferred from return type annotations, but can be specified explicitly if you don't control the code you want to cache.

conftest.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
# resolve_package_path is called from _pytest.pathlib.import_path
2121
# takes a full abs path to the test file and needs to return the path to the 'root' package on the filesystem
2222
resolve_pkg_path_orig = _pytest.pathlib.resolve_package_path
23+
24+
2325
def resolve_package_path(path: pathlib.Path) -> Optional[pathlib.Path]:
2426
result = path # search from the test file upwards
2527
for parent in result.parents:
@@ -30,6 +32,8 @@ def resolve_package_path(path: pathlib.Path) -> Optional[pathlib.Path]:
3032
if path.name == 'conftest.py':
3133
return resolve_pkg_path_orig(path)
3234
raise RuntimeError("Couldn't determine path for ", path)
35+
36+
3337
_pytest.pathlib.resolve_package_path = resolve_package_path
3438

3539

@@ -38,10 +42,14 @@ def resolve_package_path(path: pathlib.Path) -> Optional[pathlib.Path]:
3842
# so we need to point it at the absolute path properly
3943
# not sure what are the consequences.. maybe it wouldn't be able to run against installed packages? not sure..
4044
search_pypath_orig = _pytest.main.search_pypath
45+
46+
4147
def search_pypath(module_name: str) -> str:
4248
mpath = root_dir / module_name.replace('.', os.sep)
4349
if not mpath.is_dir():
4450
mpath = mpath.with_suffix('.py')
4551
assert mpath.exists(), mpath # just in case
4652
return str(mpath)
53+
54+
4755
_pytest.main.search_pypath = search_pypath

0 commit comments

Comments
 (0)