Source code for cache
"""
Patch for pytest cache to serialize datetime.datetime
"""
import datetime
import functools
import json
from typing import Any, Dict, Union, Tuple
from dateutil.parser import isoparse
import _pytest
import _pytest.cacheprovider
[docs]def json_iso_datetimes(obj: Any) -> str:
"""JSON serializer for objects not serializable by default json
module."""
if isinstance(obj, datetime.datetime):
return obj.isoformat()
raise TypeError(f"Unserializable type {type(obj)}")
[docs]def json_iso_datetime_string_to_datetime(obj: Dict[Any, Any]) -> Dict[Any, Any]:
"""JSON object hook that converts object vals from ISO datetime
strings to python datetime.datetime`s if possible."""
for k, v in obj.items():
if not isinstance(v, str):
continue
try:
obj[k] = isoparse(v)
except (OverflowError, ValueError):
pass
return obj
[docs]def datetime_encode_set(
self: _pytest.cacheprovider.Cache,
key: str,
value: Union[str, int, float, Dict[Any, Any], Tuple[Any]],
) -> None:
"""save value for the given key.
:param key: must be a ``/`` separated value. Usually the first
name is the name of your plugin or your application.
:param value: must be of any combination of basic
python types, including nested types
like e. g. lists of dictionaries.
"""
path = self._getvaluepath(key)
try:
path.parent.mkdir(exist_ok=True, parents=True)
except (IOError, OSError):
self.warn("could not create cache path {path}", path=path)
return
try:
f = path.open("w")
except (IOError, OSError):
self.warn("cache could not write path {path}", path=path)
else:
with f:
json.dump(value, f, indent=2, sort_keys=True, default=json_iso_datetimes)
self._ensure_supporting_files()
[docs]def datetime_encode_get(
self: _pytest.cacheprovider.Cache, key: str, default: Any
) -> Any:
"""return cached value for the given key. If no value
was yet cached or the value cannot be read, the specified
default is returned.
:param key: must be a ``/`` separated value. Usually the first
name is the name of your plugin or your application.
:param default: must be provided in case of a cache-miss or
invalid cache values.
"""
path = self._getvaluepath(key)
try:
with path.open("r") as f:
return json.load(f, object_hook=json_iso_datetime_string_to_datetime)
except (ValueError, IOError, OSError):
return default
[docs]def patch_cache_set(config: _pytest.config.Config) -> None:
assert config.cache, "pytest does not have a cache configured to patch"
# types ignored due to https://github.com/python/mypy/issues/2427
config.cache.set = functools.partial(datetime_encode_set, config.cache) # type: ignore
config.cache.get = functools.partial(datetime_encode_get, config.cache) # type: ignore