cdxcore 0.1.27__tar.gz → 0.1.28__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.

Potentially problematic release.


This version of cdxcore might be problematic. Click here for more details.

Files changed (45) hide show
  1. {cdxcore-0.1.27 → cdxcore-0.1.28}/PKG-INFO +1 -1
  2. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/__init__.py +1 -1
  3. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/subdir.py +159 -47
  4. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore.egg-info/PKG-INFO +1 -1
  5. {cdxcore-0.1.27 → cdxcore-0.1.28}/pyproject.toml +1 -1
  6. {cdxcore-0.1.27 → cdxcore-0.1.28}/tests/test_subdir.py +62 -7
  7. {cdxcore-0.1.27 → cdxcore-0.1.28}/LICENSE +0 -0
  8. {cdxcore-0.1.27 → cdxcore-0.1.28}/README.md +0 -0
  9. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/config.py +0 -0
  10. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/deferred.py +0 -0
  11. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/dynalimits.py +0 -0
  12. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/dynaplot.py +0 -0
  13. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/err.py +0 -0
  14. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/filelock.py +0 -0
  15. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/jcpool.py +0 -0
  16. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/npio.py +0 -0
  17. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/npshm.py +0 -0
  18. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/pretty.py +0 -0
  19. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/uniquehash.py +0 -0
  20. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/util.py +0 -0
  21. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/verbose.py +0 -0
  22. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore/version.py +0 -0
  23. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore.egg-info/SOURCES.txt +0 -0
  24. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore.egg-info/dependency_links.txt +0 -0
  25. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore.egg-info/requires.txt +0 -0
  26. {cdxcore-0.1.27 → cdxcore-0.1.28}/cdxcore.egg-info/top_level.txt +0 -0
  27. {cdxcore-0.1.27 → cdxcore-0.1.28}/docs/source/conf.py +0 -0
  28. {cdxcore-0.1.27 → cdxcore-0.1.28}/setup.cfg +0 -0
  29. {cdxcore-0.1.27 → cdxcore-0.1.28}/tests/test_config.py +0 -0
  30. {cdxcore-0.1.27 → cdxcore-0.1.28}/tests/test_deferred.py +0 -0
  31. {cdxcore-0.1.27 → cdxcore-0.1.28}/tests/test_err.py +0 -0
  32. {cdxcore-0.1.27 → cdxcore-0.1.28}/tests/test_jcpool.py +0 -0
  33. {cdxcore-0.1.27 → cdxcore-0.1.28}/tests/test_npio.py +0 -0
  34. {cdxcore-0.1.27 → cdxcore-0.1.28}/tests/test_npshm.py +0 -0
  35. {cdxcore-0.1.27 → cdxcore-0.1.28}/tests/test_pretty.py +0 -0
  36. {cdxcore-0.1.27 → cdxcore-0.1.28}/tests/test_uniquehash.py +0 -0
  37. {cdxcore-0.1.27 → cdxcore-0.1.28}/tests/test_util.py +0 -0
  38. {cdxcore-0.1.27 → cdxcore-0.1.28}/tests/test_verbose.py +0 -0
  39. {cdxcore-0.1.27 → cdxcore-0.1.28}/tests/test_version.py +0 -0
  40. {cdxcore-0.1.27 → cdxcore-0.1.28}/tmp/filelock.py +0 -0
  41. {cdxcore-0.1.27 → cdxcore-0.1.28}/tmp/np.py +0 -0
  42. {cdxcore-0.1.27 → cdxcore-0.1.28}/tmp/npsh1.py +0 -0
  43. {cdxcore-0.1.27 → cdxcore-0.1.28}/tmp/sharedarray.py +0 -0
  44. {cdxcore-0.1.27 → cdxcore-0.1.28}/up/git_message.py +0 -0
  45. {cdxcore-0.1.27 → cdxcore-0.1.28}/up/pip_modify_setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cdxcore
3
- Version: 0.1.27
3
+ Version: 0.1.28
4
4
  Summary: Basic Python Tools; upgraded cdxbasics
5
5
  Author-email: Hans Buehler <github@buehler.london>
6
6
  License-Expression: MIT
@@ -4,4 +4,4 @@ Created on June 2022
4
4
  @author: hansb
5
5
  """
6
6
 
7
- __version__ = "0.1.27" # auto-updated by setup.py
7
+ __version__ = "0.1.28" # auto-updated by setup.py
@@ -2801,14 +2801,14 @@ class SubDir(object):
2801
2801
  # caching
2802
2802
  # -------
2803
2803
 
2804
- def cache( self, version : str = None , *,
2805
- dependencies : list = None,
2806
- label : Callable = None,
2807
- uid : Callable = None,
2808
- name : str = None,
2809
- exclude_args : list[str] = None,
2810
- include_args : list[str] = None,
2811
- exclude_arg_types : list[type] = None,
2804
+ def cache( self, version : str|None = None , *,
2805
+ dependencies : list|None = None,
2806
+ label : Callable|None = None,
2807
+ uid : Callable|None = None,
2808
+ name : str|None = None,
2809
+ exclude_args : list[str]|None = None,
2810
+ include_args : list[str]|None = None,
2811
+ exclude_arg_types : list[type]|None = None,
2812
2812
  version_auto_class : bool = True):
2813
2813
  """
2814
2814
  Advanced versioned caching for callables.
@@ -3178,9 +3178,13 @@ class SubDir(object):
3178
3178
  :dec:`cdxcore.subdir.SubDir.cache`
3179
3179
  to provide version information at class level. Only version information are provided here.
3180
3180
 
3181
+ You can use :dec:`cdxcore.subdir.SubDir.cache_class` as an alias.
3182
+
3181
3183
  2) Secondly, decorate ``__init__``. You do not need to specify a version
3182
3184
  for ``__init__`` as its version usually coincides with the version of the class. At ``__init__``
3183
3185
  you define how unique IDs are generated from the parameters passed to object construction.
3186
+
3187
+ You can use :dec:`cdxcore.subdir.SubDir.cache_init` as an alias.
3184
3188
 
3185
3189
  Simple example:
3186
3190
 
@@ -3190,10 +3194,10 @@ class SubDir(object):
3190
3194
  cache = SubDir("!/.cache")
3191
3195
  cache.delete_all_content() # for illustration
3192
3196
 
3193
- @cache.cache("0.1")
3197
+ @cache.cache_class("0.1")
3194
3198
  class A(object):
3195
3199
 
3196
- @cache.cache(exclude_args=['debug'])
3200
+ @cache.cache_init(exclude_args=['debug'])
3197
3201
  def __init__(self, x, debug):
3198
3202
  if debug:
3199
3203
  print("__init__",x)
@@ -3216,10 +3220,10 @@ class SubDir(object):
3216
3220
 
3217
3221
  .. code-block:: python
3218
3222
 
3219
- @cache.cache("0.1")
3223
+ @cache.cache_class("0.1")
3220
3224
  class A(object):
3221
3225
 
3222
- @cache.cache("0.1", id=lambda x, debug: f"A.__init__(x={x})") # <-- 'self' is not passed to the lambda function; no need to add **_
3226
+ @cache.cache_init(id=lambda x, debug: f"A.__init__(x={x})") # <-- 'self' is not passed to the lambda function; no need to add **_
3223
3227
  def __init__(self, x, debug):
3224
3228
  if debug:
3225
3229
  print("__init__",x)
@@ -3227,35 +3231,79 @@ class SubDir(object):
3227
3231
 
3228
3232
  Decorating classes with ``__slots__`` does not yet work.
3229
3233
 
3230
- See also
3231
- ^^^^^^^^
3234
+ Managing Caching Accross a Project
3235
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3232
3236
 
3233
- For project-wide use it is usually inconvenient to control caching at the level of a
3237
+ For project-wide use it is usually convenient to control caching at the level of a
3234
3238
  project-wide cache root directory.
3235
- See :class:`cdxcore.subdir.VersionedCacheRoot` for a thin convenience wrapper around a :class:`cdxcore.subdir.SubDir`
3239
+ The classs :class:`cdxcore.subdir.VersionedCacheRoot` is a thin convenience wrapper around a :class:`cdxcore.subdir.SubDir`
3236
3240
  with a :class:`cdxcore.subdir.CacheController`.
3237
3241
 
3242
+ The idea is to have a central file, ``cache.py`` which contains the central root for caching.
3243
+ We recommend using an environment variable to be able to control the location of this directory
3244
+ out side the code. Here is an example with an environment variable ``PROJECT_CACHE_DIR``::
3245
+
3246
+ # file cache.py
3247
+
3248
+ from cdxcore.subdir import VersionedCacheRoot
3249
+ import os as os
3250
+
3251
+ cache_root = VersionedCacheRoot(
3252
+ os.getenv("PROJECT_CACHE_DIR", "!/.cache")
3253
+ )
3254
+
3255
+ In a particular project file, say ``pipeline.py`` create a file-local cache directory
3256
+ and use it::
3257
+
3258
+ # file pipeline.py
3259
+
3260
+ from cache import cache_root
3261
+
3262
+ cache_dir = cache_root("pipeline")
3263
+
3264
+ @cache_dir.cache("0.1")
3265
+ def f(x):
3266
+ return x+2
3267
+
3268
+ @cache_dir.cache("0.1", dependencies=[f])
3269
+ def g(x)
3270
+ return f(x)**2
3271
+
3272
+ # ...
3273
+
3274
+ In case you have issues with caching you can use the central root directory to turn on tracing
3275
+ accross your project:
3276
+
3277
+ .. code-block:: python
3278
+ :emphasize-lines: 4
3279
+
3280
+ from cdxcore.verbose import Context
3281
+ cache_root = VersionedCacheRoot(
3282
+ os.getenv("PROJECT_CACHE_DIR", "!/.cache"),
3283
+ debug_verbose=Context.all # turn full traing on
3284
+ )
3285
+
3238
3286
  Parameters
3239
3287
  ----------
3240
- version : str, optional
3288
+ version : str | None, default ``None``
3241
3289
  Version of the function.
3242
3290
 
3243
- * If ``None`` then ``F`` must be decorated with :dec:`cdxcore.version.version`.
3244
- * If set, the function ``F`` is first decorated with :dec:`cdxcore.version.version`.
3291
+ * If ``None`` then a common `F`` must be decorated manually with :dec:`cdxcore.version.version`.
3292
+ * If set, the function ``F`` is automatically first decorated with :dec:`cdxcore.version.version` for you.
3245
3293
 
3246
- dependencies : list[type], optional
3294
+ dependencies : list[type] | None, default ``None``
3247
3295
  A list of version dependencies, either by reference or by name.
3248
3296
  See :dec:`cdxcore.version.version` for details on name lookup if strings are used.
3249
3297
 
3250
- label : str | Callable
3251
- Specify a human-readable label for the function call given its parameters.
3298
+ label : str | Callable | None, default ``None``
3299
+ Specify a human-readabl label for the function call given its parameters.
3252
3300
  This label is used to generate the cache file name, and is also printed in when tracing
3253
3301
  hashing operations. Labels are not assumed to be unique, hence a unique hash of
3254
3302
  the label and the parameters to this function will be appended to generate
3255
3303
  the actual cache file name.
3256
3304
 
3257
- Use ``uid`` instead if ``label`` represents valid unique filenames.
3258
-
3305
+ Use ``uid`` instead if ``label`` represents valid unique filenames. You cannot specify both ``uid`` and ``label``.
3306
+ If neither ``uid`` and ``label`` are present, ``name`` will be used.
3259
3307
 
3260
3308
  **Usage:**
3261
3309
 
@@ -3271,30 +3319,34 @@ class SubDir(object):
3271
3319
 
3272
3320
  ``label`` cannot be used alongside ``uid``.
3273
3321
 
3274
- uid : str | Callable
3322
+ uid : str | Callable | None, default ``None``
3275
3323
  Alternative to ``label`` which is assumed to generate a unique cache file name. It has the same
3276
- semantics as ``label``. When used, parameters to the decorated function are not hashed.
3324
+ semantics as ``label``. When used, parameters to the decorated function are not hashed
3325
+ as the ``uid`` is assumed to be already unique. The string must be a valid file name
3277
3326
 
3278
- ``uid`` be used alongside ``label``.
3327
+ Use ``label`` if the id is not unique. You cannot specify both ``uid`` and ``label``.
3328
+ If neither ``uid`` and ``label`` are present, ``name`` will be used (as non-unique ``label``).
3279
3329
 
3280
- name : str, optional
3281
- Name of this function which is used either on its own if neither ``label`` not ``uid`` are used.
3282
- If either of them is used, ``name`` is passed as a parameter to either the callable or the
3283
- formatting operator.
3330
+ name : str | None, default ``None``
3331
+ Name of this function which is used either on its own if neither ``label`` not ``uid`` are used,
3332
+ or which passed as a parameter ``name`` to either the callable or the
3333
+ formatting operator. See above for more details.
3284
3334
 
3285
3335
  If ``name`` is not specified it defaults to ``__qualname__`` expanded
3286
3336
  by the module name the function is defined in.
3287
3337
 
3288
- include_args : list[str]
3338
+ include_args : list[str] | None, default ``None``
3289
3339
  List of arguments to include in generating an unqiue ID, or ``None`` for all.
3290
3340
 
3291
- exclude_args : list[str]:
3292
- List of arguments to exclude from generating an unique ID.
3341
+ exclude_args : list[str] | None, default ``None``
3342
+ List of arguments to exclude from generating an unique ID. Examples of such non-functional arguments
3343
+ are workflow controls (debugging) and i/o elements.
3293
3344
 
3294
- exclude_arg_types : list[type]
3295
- List of parameter types to exclude from generating an unique ID.
3345
+ exclude_arg_types : list[type] | None, default ``None``
3346
+ List of parameter types to exclude from generating an unique ID. Examples of such non-functional arguments
3347
+ are workflow controls (debugging) and i/o elements.
3296
3348
 
3297
- version_auto_class : bool
3349
+ version_auto_class : bool, default ``True``
3298
3350
  Whether to automaticallty add version dependencies on base classes or, for member functions, on containing
3299
3351
  classes. This is the ``auto_class`` parameter for :dec:`cdxcore.version.version`.
3300
3352
 
@@ -3326,12 +3378,39 @@ class SubDir(object):
3326
3378
 
3327
3379
  The decorated ``F()`` has additional function parameters, namely:
3328
3380
 
3329
- * ``override_cache_mode`` : allows to override caching mode temporarily, in particular you can set it to ``"off"``.
3330
- * ``track_cached_files`` : allows passing a :class:`cdxcore.subdir.CacheTracker`
3381
+ * ``override_cache_mode`` : ``CacheMode`` | None, default ``None``
3382
+
3383
+ Allows overriding the ``CacheMode`` temporarily, in particular you can set it to ``"off"``.
3384
+
3385
+ * ``track_cached_files`` : :class:`cdxcore.subdir.CacheTracker` | None, default ``None``
3386
+
3387
+ Allows passing a :class:`cdxcore.subdir.CacheTracker`
3331
3388
  object to keep track of all
3332
3389
  files used (loaded from or saved to).
3333
3390
  The function :meth:`cdxcore.subdir.CacheTracker.delete_cache_files` can be used
3334
3391
  to delete all files involved in caching.
3392
+
3393
+ * ``return_cache_uid`` : bool, default ``False``
3394
+
3395
+ If ``True``, then the decorated function will return a tuple ``uid, result``
3396
+ where ``uid`` is the unique filename generated for this function call,
3397
+ and where ``result`` is the actual result from the function, cached or not.
3398
+
3399
+ Usage::
3400
+
3401
+ from cdxcore.subdir import SubDir
3402
+ cache_dir = SubDir("!/.cache")
3403
+
3404
+ @cache_dir.cache()
3405
+ def f(x, y):
3406
+ return x*y
3407
+
3408
+ uid, xy = f( x=1, y=2, return_cache_uid=True )
3409
+
3410
+ This pattern is thread-safe when compared to using::
3411
+
3412
+ xy = f( x=1, y=2 )
3413
+ uid = f.cache_info.filename
3335
3414
  """
3336
3415
  return CacheCallable(subdir = self,
3337
3416
  version = version,
@@ -3361,17 +3440,41 @@ class SubDir(object):
3361
3440
  @cache.cache_class("0.1")
3362
3441
  class A(object):
3363
3442
 
3364
- @cache.cache(exclude_args=['debug'])
3443
+ @cache.cache_init(exclude_args=['debug'])
3365
3444
  def __init__(self, x, debug):
3366
3445
  if debug:
3367
3446
  print("__init__",x)
3368
3447
  self.x = x
3369
3448
 
3370
3449
  """
3371
- return self.cache( name=name,
3372
- version=version,
3373
- dependencies=dependencies,
3374
- version_auto_class=version_auto_class)
3450
+ return self.cache( name=name, version=version, dependencies=dependencies, version_auto_class=version_auto_class)
3451
+
3452
+ def cache_init( self,
3453
+ label : Callable = None,
3454
+ uid : Callable = None,
3455
+ exclude_args : list[str] = None,
3456
+ include_args : list[str] = None,
3457
+ exclude_arg_types : list[type] = None,
3458
+ ):
3459
+ """
3460
+ Short-cut for :dec:`cdxcore.subdir.SubDir.cache` applied to decorating ``__init__``
3461
+ with a reduced number of available parameters.
3462
+
3463
+ Example::
3464
+
3465
+ cache = SubDir("!/.cache")
3466
+
3467
+ @cache.cache_class("0.1")
3468
+ class A(object):
3469
+
3470
+ @cache.cache_init(exclude_args=['debug'])
3471
+ def __init__(self, x, debug):
3472
+ if debug:
3473
+ print("__init__",x)
3474
+ self.x = x
3475
+
3476
+ """
3477
+ return self.cache( label=label, uid=uid, exclude_args=exclude_args, include_args=include_args, exclude_arg_types=exclude_arg_types )
3375
3478
 
3376
3479
  # ========================================================================
3377
3480
  # Caching, convenience
@@ -3444,6 +3547,9 @@ def VersionedCacheRoot( directory : str, *,
3444
3547
 
3445
3548
  * ``hash_length``: length used for hashes, see :class:`cdxcore.uniquehash.UniqueHash`.
3446
3549
 
3550
+ * ``debug_verbose`` set to ``Context.all`` after importing ``from cdxcore.verbose import Context``
3551
+ will turn on tracing all caching operations.
3552
+
3447
3553
  Returns
3448
3554
  -------
3449
3555
  Root : :class:`cdxcore.subdir.SubDir`
@@ -3768,8 +3874,9 @@ class CacheCallable(object):
3768
3874
  exclude_types = ( self._exclude_arg_types if not self._exclude_arg_types is None else set() )\
3769
3875
  | ( self.global_exclude_arg_types if not self.global_exclude_arg_types is None else set())
3770
3876
 
3771
- def execute( *args, override_cache_mode : CacheMode = None,
3772
- track_cached_files : CacheTracker = None,
3877
+ def execute( *args, override_cache_mode : CacheMode|None = None,
3878
+ track_cached_files : CacheTracker|None = None,
3879
+ return_cache_uid : bool = False,
3773
3880
  **kwargs ):
3774
3881
  """
3775
3882
  Cached execution of the wrapped function
@@ -3899,7 +4006,7 @@ class CacheCallable(object):
3899
4006
  # -------------------------
3900
4007
 
3901
4008
  execute.cache_info.label = str(label) if not label is None else None
3902
- execute.cache_info.filename = filename
4009
+ execute.cache_info.filename = filename # that is the unique ID for this call
3903
4010
  execute.cache_info.version = version_
3904
4011
 
3905
4012
  if self.cache_controller.keep_last_arguments:
@@ -3937,6 +4044,8 @@ class CacheCallable(object):
3937
4044
  assert r.__magic_cache_call_init__ is None, ("**** Internal error. __init__ should reset __magic_cache_call_init__", F.__qualname__, label)
3938
4045
  r.__magic_cache_call_init__ = False # since we called __new__, __init__ will be called next
3939
4046
 
4047
+ if return_cache_uid:
4048
+ return filename, r
3940
4049
  return r
3941
4050
 
3942
4051
  r = F(*args, **kwargs)
@@ -3966,6 +4075,9 @@ class CacheCallable(object):
3966
4075
  debug_verbose.write(f"cache({name}): called '{label}' version 'version {version_}' and wrote result into '{self._subdir.full_file_name(filename)}'.")
3967
4076
  else:
3968
4077
  debug_verbose.write(f"cache({name}): called '{label}' version 'version {version_}' but did *not* write into '{self._subdir.full_file_name(filename)}'.")
4078
+
4079
+ if return_cache_uid:
4080
+ return filename, r
3969
4081
  return r
3970
4082
 
3971
4083
  update_wrapper( wrapper=execute, wrapped=F )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cdxcore
3
- Version: 0.1.27
3
+ Version: 0.1.28
4
4
  Summary: Basic Python Tools; upgraded cdxbasics
5
5
  Author-email: Hans Buehler <github@buehler.london>
6
6
  License-Expression: MIT
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "cdxcore"
9
- version = "0.1.27"
9
+ version = "0.1.28"
10
10
  description = "Basic Python Tools; upgraded cdxbasics"
11
11
  authors = [{ name = "Hans Buehler", email = "github@buehler.london" }]
12
12
  readme = "README.md"
@@ -25,14 +25,14 @@ import_local()
25
25
  """
26
26
  Imports
27
27
  """
28
- from cdxcore.subdir import SubDir, CacheMode, VersionError, VersionPresentError
28
+ from cdxcore.subdir import SubDir, CacheMode, VersionError, VersionPresentError, VersionedCacheRoot
29
29
  import numpy as np
30
30
 
31
31
  class Test(unittest.TestCase):
32
32
 
33
33
  def test_subdir(self):
34
34
 
35
- sub = SubDir("!/.tmp_test_for_cdxbasics.subdir", delete_everything=True )
35
+ sub = SubDir("?/.tmp_test_for_cdxbasics.subdir", delete_everything=True )
36
36
  sub['y'] = 2
37
37
  sub.write('z',3)
38
38
  sub.write_string('l',"hallo")
@@ -193,11 +193,8 @@ class Test(unittest.TestCase):
193
193
  with self.assertRaises(VersionError):
194
194
  r = sub.read("test", None, version="2", raise_on_error=True)
195
195
  # wrong version
196
- sub.delete_everything()
197
196
 
198
197
  def test_new(self):
199
-
200
-
201
198
  subdir = SubDir("my_directory") # relative to current working directory
202
199
  subdir = SubDir("./my_directory") # relative to current working directory
203
200
  subdir = SubDir("~/my_directory") # relative to home directory
@@ -248,8 +245,6 @@ class Test(unittest.TestCase):
248
245
  test_format( SubDir.GZIP, True )
249
246
  test_format( SubDir.JSON_PICKLE )
250
247
 
251
-
252
-
253
248
  def test_cache_mode(self):
254
249
 
255
250
  on = CacheMode("on")
@@ -275,6 +270,66 @@ class Test(unittest.TestCase):
275
270
  self.assertEqual( [ x.write for x in allc ], [True, True, False, False, True, False] )
276
271
  self.assertEqual( [ x.delete for x in allc ], [False, False, False, True, True, False ] )
277
272
  self.assertEqual( [ x.del_incomp for x in allc ], [True, False, False, True, True, False ] )
273
+
274
+ class A(object):
275
+ def __init__(self, x):
276
+ self.x = x
277
+ class B(object):
278
+ def __init__(self, x):
279
+ self.x = x
280
+
281
+ class Test(unittest.TestCase):
282
+
283
+ def test_cache( self ):
284
+
285
+ sub = VersionedCacheRoot("?/subdir_cache_test", exclude_arg_types=[A] )
286
+
287
+ @sub.cache("1.0")
288
+ def f(x):
289
+ return x
290
+
291
+ _ = f(1)
292
+ _ = f(1)
293
+ self.assertTrue( f.cache_info.last_cached )
294
+
295
+ @sub.cache("1.0")
296
+ def g(x):
297
+ return x
298
+
299
+ # a new B object each time -> no caching
300
+ _ = f(B(1))
301
+ _ = f(B(2))
302
+ self.assertFalse( f.cache_info.last_cached )
303
+
304
+ # same B object each time -> no caching
305
+ _ = f(B(1))
306
+ _ = f(B(1))
307
+ self.assertTrue( f.cache_info.last_cached )
308
+
309
+ # a new A object each time -> caching, as we ignore 'A' types
310
+ _ = f(A(1))
311
+ _ = f(A(2))
312
+ self.assertTrue( f.cache_info.last_cached )
313
+
314
+ @sub.cache("1.0", label=lambda x, **_: f"f({x})")
315
+ def f(x):
316
+ return x
317
+
318
+ _ = f(1)
319
+ self.assertEqual( f.cache_info.filename[:5], "f(1) " )
320
+ uid, _ = f(1, return_cache_uid=True)
321
+ self.assertEqual( uid[:5], "f(1) " )
322
+
323
+ @sub.cache("1.0", uid=lambda x, **_: f"f({x})")
324
+ def f(x):
325
+ return x
326
+
327
+ _ = f(1)
328
+ self.assertEqual( f.cache_info.filename, "f(1)" )
329
+ uid, _ = f(1, return_cache_uid=True)
330
+ self.assertEqual( uid, "f(1)" )
331
+
332
+
278
333
  if __name__ == '__main__':
279
334
  unittest.main()
280
335
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes