core/cachew: rely on ~/.cache for default cache path

- rely on appdirs for default cache path instead of hardcoded /var/tmp/cachew
  technically backwards incompatible, but no action needed
  you might want to clean /var/tmp/cachew after updating

- use default cache path (e.g. ~/.cache) by default
  see https://github.com/ActiveState/appdirs#some-example-output for more info
  *warning*: things will be cached by default now (used to be uncached before)

- treat cache_dir = None in the config
  *warning*: kind of backwards incompatible.. but again nothing disasterous
This commit is contained in:
Dima Gerasimov 2021-02-21 16:56:11 +00:00 committed by karlicoss
parent 837ea16dc8
commit da3c1c9b74
6 changed files with 87 additions and 34 deletions

View file

@ -7,12 +7,10 @@ General/my.core changes:
cli: add `hpi module install` and `hpi module requires` cli: add `hpi module install` and `hpi module requires`
relevant: relevant: https://github.com/karlicoss/HPI/issues/12, https://github.com/karlicoss/HPI/issues/79
- https://github.com/karlicoss/HPI/issues/12
- https://github.com/karlicoss/HPI/issues/79
- 97650adf3b48c653651b31c78cefe24ecae5ed4f add discovery_pure module to get modules and their dependencies via ast module - 97650adf3b48c653651b31c78cefe24ecae5ed4f add discovery_pure module to get modules and their dependencies via `ast` module
- f90599d7e4463e936c8d95196ff767c730207202 make module discovery rely on =ast= module - f90599d7e4463e936c8d95196ff767c730207202 make module discovery rely on `ast` module
Hopefully it will make it more robust & much faster. Hopefully it will make it more robust & much faster.
- 07f901e1e5fb2bd3009561c84cc4efd311c94733 helpers for **automatic dataframes** from sequences of NamedTuple/dataclass - 07f901e1e5fb2bd3009561c84cc4efd311c94733 helpers for **automatic dataframes** from sequences of NamedTuple/dataclass
- 4012f9b7c2a429170df8600591ec8d1e1407b162 more generic functions to jsonify data - 4012f9b7c2a429170df8600591ec8d1e1407b162 more generic functions to jsonify data
@ -49,7 +47,7 @@ Misc:
- d562f00dca720fd4f6736377a41168e9a796c122 - d562f00dca720fd4f6736377a41168e9a796c122
tests: run all tests, but exclude tests specific to my computer from CI tests: run all tests, but exclude tests specific to my computer from CI
controllable via `HPI_TESTS_KARLICOSS=true`` controllable via `HPI_TESTS_KARLICOSS=true`
- improved mypy coverage - improved mypy coverage

View file

@ -1,8 +1,12 @@
from contextlib import contextmanager from contextlib import contextmanager
from pathlib import Path from pathlib import Path
from typing import Optional
# can lead to some unexpected issues if you 'import cachew' which being in my/core directory.. so let's protect against it
# NOTE: if we use overlay, name can be smth like my.origg.my.core.cachew ...
assert 'my.core' in __name__, f'Expected module __name__ ({__name__}) to start with my.core'
def disable_cachew(): def disable_cachew() -> None:
try: try:
import cachew import cachew
except ImportError: except ImportError:
@ -13,8 +17,9 @@ def disable_cachew():
settings.ENABLE = False settings.ENABLE = False
from typing import Iterator
@contextmanager @contextmanager
def disabled_cachew(): def disabled_cachew() -> Iterator[None]:
try: try:
import cachew import cachew
except ImportError: except ImportError:
@ -26,18 +31,13 @@ def disabled_cachew():
yield yield
def cache_dir() -> Path: def _appdirs_cache_dir() -> Path:
''' import appdirs # type: ignore
Base directory for cachew. cd = Path(appdirs.user_cache_dir('my'))
To override, add to your config file: cd.mkdir(exist_ok=True, parents=True)
class config: return cd
cache_dir = '/your/custom/cache/path'
'''
from .core_config import config def cache_dir() -> Optional[Path]:
cdir = config.cache_dir from . import core_config as CC
if cdir is None: return CC.config.get_cache_dir()
# TODO handle this in core_config.py
# TODO fallback to default cachew dir instead? or appdirs cache
return Path('/var/tmp/cachew')
else:
return Path(cdir)

View file

@ -214,7 +214,8 @@ if TYPE_CHECKING:
mcachew: McachewType mcachew: McachewType
# TODO set default cache dir here instead?
# TODO I don't really like 'mcachew', just 'cache' would be better... maybe?
# todo ugh. I think it needs doublewrap, otherwise @mcachew without args doesn't work # todo ugh. I think it needs doublewrap, otherwise @mcachew without args doesn't work
def mcachew(*args, **kwargs): # type: ignore[no-redef] def mcachew(*args, **kwargs): # type: ignore[no-redef]
""" """

View file

@ -4,8 +4,7 @@ Bindings for the 'core' HPI configuration
import re import re
from typing import Sequence, Optional from typing import Sequence, Optional
from .common import PathIsh from . import warnings, PathIsh, Path
from . import warnings
try: try:
from my.config import core as user_config # type: ignore[attr-defined] from my.config import core as user_config # type: ignore[attr-defined]
@ -20,22 +19,50 @@ except Exception as e:
user_config = object # type: ignore[assignment, misc] user_config = object # type: ignore[assignment, misc]
_HPI_CACHE_DIR_DEFAULT = ''
from dataclasses import dataclass from dataclasses import dataclass
@dataclass @dataclass
class Config(user_config): class Config(user_config):
# TODO if attr is set _and_ it's none, disable cache? '''
# todo or empty string? Config for the HPI itself.
# I guess flip the switch at some point when I'm confident in cachew To override, add to your config file something like
cache_dir: Optional[PathIsh] = None # FIXME use appdirs cache dir or something
class config:
cache_dir = '/your/custom/cache/path'
'''
cache_dir: Optional[PathIsh] = _HPI_CACHE_DIR_DEFAULT
'''
Base directory for cachew.
- if None , means cache is disabled
- if '' (empty string), use user cache dir (see https://github.com/ActiveState/appdirs for more info). This is the default.
- otherwise , use the specified directory as base cache directory
NOTE: you shouldn't use this attribute in HPI modules directly, use Config.get_cache_dir()/cachew.cache_dir() instead
'''
# list of regexes/globs
# None means 'rely on disabled_modules'
enabled_modules : Optional[Sequence[str]] = None enabled_modules : Optional[Sequence[str]] = None
'''
list of regexes/globs
- None means 'rely on disabled_modules'
'''
# list of regexes/globs
# None means 'rely on enabled_modules'
disabled_modules: Optional[Sequence[str]] = None disabled_modules: Optional[Sequence[str]] = None
'''
list of regexes/globs
- None means 'rely on enabled_modules'
'''
def get_cache_dir(self) -> Optional[Path]:
cdir = self.cache_dir
if cdir is None:
return None
if cdir == _HPI_CACHE_DIR_DEFAULT:
from .cachew import _appdirs_cache_dir
return _appdirs_cache_dir()
else:
return Path(cdir)
def _is_module_active(self, module: str) -> Optional[bool]: def _is_module_active(self, module: str) -> Optional[bool]:
# None means the config doesn't specify anything # None means the config doesn't specify anything
@ -81,6 +108,7 @@ def _reset_config() -> Iterator[Config]:
with override_config(config) as cc: with override_config(config) as cc:
cc.enabled_modules = None cc.enabled_modules = None
cc.disabled_modules = None cc.disabled_modules = None
cc.cache_dir = None
yield cc yield cc

View file

@ -4,9 +4,11 @@ import gzip
import lzma import lzma
import io import io
import zipfile import zipfile
from typing import List
from my.core.kompress import kopen, kexists, CPath from my.core.kompress import kopen, kexists, CPath
def test_kopen(tmp_path: Path) -> None: def test_kopen(tmp_path: Path) -> None:
"Plaintext handled transparently" "Plaintext handled transparently"
assert kopen(tmp_path / 'file' ).read() == 'just plaintext' assert kopen(tmp_path / 'file' ).read() == 'just plaintext'
@ -95,3 +97,26 @@ def test_warn_iterable() -> None:
assert list(x2) == [1, 2, 3] assert list(x2) == [1, 2, 3]
assert len(w) == 0 assert len(w) == 0
def test_cachew() -> None:
from cachew import settings
settings.ENABLE = True # by default it's off in tests (see conftest.py)
from my.core.cachew import cache_dir
from my.core.common import mcachew
called = 0
@mcachew
def cf() -> List[int]:
nonlocal called
called += 1
return [1, 2, 3]
list(cf())
cc = called
# todo ugh. how to clean cache?
# assert called == 1 # precondition, to avoid turdes from previous tests
assert list(cf()) == [1, 2, 3]
assert called == cc

View file

@ -22,6 +22,7 @@ commands =
setenv = MY_CONFIG = nonexistent setenv = MY_CONFIG = nonexistent
commands = commands =
pip install -e .[testing] pip install -e .[testing]
pip install cachew
hpi module install my.location.google hpi module install my.location.google
pip install ijson # optional dependency pip install ijson # optional dependency