cachier 2.0.1__py2.py3-none-any.whl → 2.1.0__py2.py3-none-any.whl

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.
cachier/_version.py CHANGED
@@ -11,8 +11,8 @@ version_json = '''
11
11
  {
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "15ce5f36320f15e8058baf29015fa27ea493d211",
15
- "version": "2.0.1"
14
+ "full-revisionid": "7be769b78acf3a0e0aff8d528476913571d79749",
15
+ "version": "2.1.0"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
cachier/base_core.py CHANGED
@@ -8,24 +8,32 @@
8
8
 
9
9
  import abc # for the _BaseCore abstract base class
10
10
  import functools
11
+ import hashlib
12
+ import inspect
13
+ import pickle # nosec: B403
11
14
 
12
15
 
13
- # pylint: disable-next=protected-access
14
- _default_hash_params = functools.partial(functools._make_key, typed=False)
16
+ def _default_hash_func(args, kwds):
17
+ # pylint: disable-next=protected-access
18
+ key = functools._make_key(args, kwds, typed=True)
19
+ hash = hashlib.sha256()
20
+ for item in key:
21
+ hash.update(pickle.dumps(item))
22
+ return hash.hexdigest()
15
23
 
16
24
 
17
25
  class _BaseCore():
18
26
  __metaclass__ = abc.ABCMeta
19
27
 
20
- def __init__(self, stale_after, next_time, hash_params):
21
- self.stale_after = stale_after
22
- self.next_time = next_time
23
- self.hash_func = hash_params if hash_params else _default_hash_params
28
+ def __init__(self, hash_func):
29
+ self.hash_func = hash_func if hash_func else _default_hash_func
24
30
  self.func = None
25
31
 
26
32
  def set_func(self, func):
27
- """Sets the function this core will use. This has to be set before
28
- any method is called"""
33
+ """Sets the function this core will use. This has to be set before any
34
+ method is called. Also determine if the funtion is an object method."""
35
+ func_params = list(inspect.signature(func).parameters)
36
+ self.func_is_method = func_params and func_params[0] == 'self'
29
37
  self.func = func
30
38
 
31
39
  def get_entry(self, args, kwds):
@@ -34,6 +42,12 @@ class _BaseCore():
34
42
  key = self.hash_func(args, kwds)
35
43
  return self.get_entry_by_key(key)
36
44
 
45
+ def precache_value(self, args, kwds, value_to_cache):
46
+ """Writes a precomputed value into the cache."""
47
+ key = self.hash_func(args, kwds)
48
+ self.set_entry(key, value_to_cache)
49
+ return value_to_cache
50
+
37
51
  @abc.abstractmethod
38
52
  def get_entry_by_key(self, key):
39
53
  """Returns the result mapped to the given key in this core's cache,
cachier/core.py CHANGED
@@ -14,6 +14,7 @@ from __future__ import print_function
14
14
 
15
15
  import os
16
16
  from functools import wraps
17
+ from warnings import warn
17
18
 
18
19
  import datetime
19
20
  from concurrent.futures import ThreadPoolExecutor
@@ -85,6 +86,7 @@ def cachier(
85
86
  backend=None,
86
87
  mongetter=None,
87
88
  cache_dir=None,
89
+ hash_func=None,
88
90
  hash_params=None,
89
91
  wait_for_calc_timeout=0,
90
92
  separate_files=False,
@@ -125,7 +127,7 @@ def cachier(
125
127
  A fully qualified path to a file directory to be used for cache files.
126
128
  The running process must have running permissions to this folder. If
127
129
  not provided, a default directory at `~/.cachier/` is used.
128
- hash_params : callable, optional
130
+ hash_func : callable, optional
129
131
  A callable that gets the args and kwargs from the decorated function
130
132
  and returns a hash key for them. This parameter can be used to enable
131
133
  the use of cachier with functions that get arguments that are not
@@ -141,15 +143,19 @@ def cachier(
141
143
  split between several files, one for each argument set. This can help
142
144
  if you per-function cache files become too large.
143
145
  """
146
+ # Check for deprecated parameters
147
+ if hash_params is not None:
148
+ message = 'hash_params will be removed in a future release, ' \
149
+ 'please use hash_func instead'
150
+ warn(message, DeprecationWarning, stacklevel=2)
151
+ hash_func = hash_params
144
152
  # The default is calculated dynamically to maintain previous behavior
145
153
  # to default to pickle unless the ``mongetter`` argument is given.
146
154
  if backend is None:
147
155
  backend = 'pickle' if mongetter is None else 'mongo'
148
156
  if backend == 'pickle':
149
157
  core = _PickleCore( # pylint: disable=R0204
150
- stale_after=stale_after,
151
- next_time=next_time,
152
- hash_params=hash_params,
158
+ hash_func=hash_func,
153
159
  reload=pickle_reload,
154
160
  cache_dir=cache_dir,
155
161
  separate_files=separate_files,
@@ -161,16 +167,12 @@ def cachier(
161
167
  'must specify ``mongetter`` when using the mongo core')
162
168
  core = _MongoCore(
163
169
  mongetter=mongetter,
164
- stale_after=stale_after,
165
- next_time=next_time,
166
- hash_params=hash_params,
170
+ hash_func=hash_func,
167
171
  wait_for_calc_timeout=wait_for_calc_timeout,
168
172
  )
169
173
  elif backend == 'memory':
170
174
  core = _MemoryCore(
171
- stale_after=stale_after,
172
- next_time=next_time,
173
- hash_params=hash_params,
175
+ hash_func=hash_func,
174
176
  )
175
177
  elif backend == 'redis':
176
178
  raise NotImplementedError(
@@ -194,7 +196,10 @@ def cachier(
194
196
  _print = print
195
197
  if ignore_cache:
196
198
  return func(*args, **kwds)
197
- key, entry = core.get_entry(args, kwds)
199
+ if core.func_is_method:
200
+ key, entry = core.get_entry(args[1:], kwds)
201
+ else:
202
+ key, entry = core.get_entry(args, kwds)
198
203
  if overwrite_cache:
199
204
  return _calc_entry(core, key, func, args, kwds)
200
205
  if entry is not None: # pylint: disable=R0101
@@ -259,9 +264,20 @@ def cachier(
259
264
  except AttributeError:
260
265
  return None
261
266
 
267
+ def precache_value(*args, value_to_cache, **kwds):
268
+ """Add an initial value to the cache.
269
+
270
+ Arguments
271
+ ---------
272
+ value : any
273
+ entry to be written into the cache
274
+ """
275
+ return core.precache_value(args, kwds, value_to_cache)
276
+
262
277
  func_wrapper.clear_cache = clear_cache
263
278
  func_wrapper.clear_being_calculated = clear_being_calculated
264
279
  func_wrapper.cache_dpath = cache_dpath
280
+ func_wrapper.precache_value = precache_value
265
281
  return func_wrapper
266
282
 
267
283
  return _cachier_decorator
cachier/memory_core.py CHANGED
@@ -17,8 +17,8 @@ class _MemoryCore(_BaseCore):
17
17
  See :class:`_BaseCore` documentation.
18
18
  """
19
19
 
20
- def __init__(self, stale_after, next_time, hash_params):
21
- super().__init__(stale_after, next_time, hash_params)
20
+ def __init__(self, hash_func):
21
+ super().__init__(hash_func)
22
22
  self.cache = {}
23
23
  self.lock = threading.RLock()
24
24
 
cachier/mongo_core.py CHANGED
@@ -37,14 +37,12 @@ class _MongoCore(_BaseCore):
37
37
 
38
38
  _INDEX_NAME = 'func_1_key_1'
39
39
 
40
- def __init__(
41
- self, mongetter, stale_after, next_time,
42
- hash_params, wait_for_calc_timeout):
40
+ def __init__(self, mongetter, hash_func, wait_for_calc_timeout):
43
41
  if 'pymongo' not in sys.modules:
44
42
  warnings.warn((
45
43
  "Cachier warning: pymongo was not found. "
46
44
  "MongoDB cores will not function."))
47
- super().__init__(stale_after, next_time, hash_params)
45
+ super().__init__(hash_func)
48
46
  self.mongetter = mongetter
49
47
  self.mongo_collection = self.mongetter()
50
48
  self.wait_for_calc_timeout = wait_for_calc_timeout
cachier/pickle_core.py CHANGED
@@ -29,10 +29,6 @@ class _PickleCore(_BaseCore):
29
29
 
30
30
  Parameters
31
31
  ----------
32
- stale_after : datetime.timedelta, optional
33
- See _BaseCore documentation.
34
- next_time : bool, optional
35
- See _BaseCore documentation.
36
32
  pickle_reload : bool, optional
37
33
  See core.cachier() documentation.
38
34
  cache_dir : str, optional.
@@ -84,10 +80,10 @@ class _PickleCore(_BaseCore):
84
80
  self._check_calculation()
85
81
 
86
82
  def __init__(
87
- self, stale_after, next_time, hash_params, reload,
88
- cache_dir, separate_files, wait_for_calc_timeout,
83
+ self, hash_func, reload, cache_dir,
84
+ separate_files, wait_for_calc_timeout,
89
85
  ):
90
- super().__init__(stale_after, next_time, hash_params)
86
+ super().__init__(hash_func)
91
87
  self.cache = None
92
88
  self.reload = reload
93
89
  self.cache_dir = DEF_CACHIER_DIR
File without changes
cachier/scripts/cli.py ADDED
@@ -0,0 +1,17 @@
1
+ """A command-line interface for cachier."""
2
+
3
+ import click
4
+
5
+ from cachier.core import _set_max_workers
6
+
7
+
8
+ @click.group()
9
+ def cli():
10
+ """A command-line interface for cachier."""
11
+
12
+
13
+ @cli.command("Limits the number of worker threads used by cachier.")
14
+ @click.argument('max_workers', nargs=1, type=int)
15
+ def set_max_workers(max_workers):
16
+ """Limits the number of worker threads used by cachier."""
17
+ _set_max_workers(max_workers)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cachier
3
- Version: 2.0.1
3
+ Version: 2.1.0
4
4
  Summary: Persistent, stale-free, local and cross-machine caching for Python functions.
5
5
  Home-page: https://github.com/python-cachier/cachier
6
6
  Author: Shay Palachy
@@ -27,13 +27,18 @@ License-File: LICENSE
27
27
  Requires-Dist: watchdog
28
28
  Requires-Dist: portalocker
29
29
  Requires-Dist: pathtools
30
+ Requires-Dist: setuptools (>=67.6.0)
30
31
  Provides-Extra: test
31
32
  Requires-Dist: pytest ; extra == 'test'
32
33
  Requires-Dist: coverage ; extra == 'test'
33
34
  Requires-Dist: pytest-cov ; extra == 'test'
34
- Requires-Dist: birch ; extra == 'test'
35
+ Requires-Dist: bandit ; extra == 'test'
36
+ Requires-Dist: flake8 ; extra == 'test'
37
+ Requires-Dist: pylint ; extra == 'test'
38
+ Requires-Dist: safety ; extra == 'test'
35
39
  Requires-Dist: pymongo ; extra == 'test'
36
40
  Requires-Dist: dnspython ; extra == 'test'
41
+ Requires-Dist: pymongo-inmemory ; extra == 'test'
37
42
  Requires-Dist: pandas ; extra == 'test'
38
43
  Requires-Dist: collective.checkdocs ; extra == 'test'
39
44
  Requires-Dist: pygments ; extra == 'test'
@@ -123,6 +128,33 @@ You can add a default, pickle-based, persistent cache to your function - meaning
123
128
  """Your function now has a persistent cache mapped by argument values!"""
124
129
  return {'arg1': arg1, 'arg2': arg2}
125
130
 
131
+ Class and object methods can also be cached. Cachier will automatically ignore the `self` parameter when determining the cache key for an object method. **This means that methods will be cached across all instances of an object, which may not be what you want.**
132
+
133
+ .. code-block:: python
134
+
135
+ from cachier import cachier
136
+
137
+ class Foo():
138
+ @staticmethod
139
+ @cachier()
140
+ def good_static_usage(arg_1, arg_2):
141
+ return arg_1 + arg_2
142
+
143
+ # Instance method does not depend on object's internal state, so good to cache
144
+ @cachier()
145
+ def good_usage_1(self, arg_1, arg_2)
146
+ return arg_1 + arg_2
147
+
148
+ # Instance method is calling external service, probably okay to cache
149
+ @cachier()
150
+ def good_usage_2(self, arg_1, arg_2)
151
+ result = self.call_api(arg_1, arg_2)
152
+ return result
153
+
154
+ # Instance method relies on object attribute, NOT good to cache
155
+ @cachier()
156
+ def bad_usage(self, arg_1, arg_2)
157
+ return arg_1 + arg_2 + self.arg_3
126
158
 
127
159
 
128
160
  Resetting a Cache
@@ -133,7 +165,7 @@ The Cachier wrapper adds a ``clear_cache()`` function to each wrapped function.
133
165
 
134
166
  foo.clear_cache()
135
167
 
136
- Genereal Configuration
168
+ General Configuration
137
169
  ----------------------
138
170
 
139
171
  Threads Limit
@@ -175,11 +207,15 @@ Further function calls made while the calculation is being performed will not tr
175
207
  Working with unhashable arguments
176
208
  ---------------------------------
177
209
 
178
- As mentioned above, the positional and keyword arguments to the wrapped function must be hashable (i.e. Python's immutable built-in objects, not mutable containers). To get around this limitation the ``hash_params`` parameter of the ``cachier`` decorator can be provided with a callable that gets the args and kwargs from the decorated function and returns a hash key for them.
210
+ As mentioned above, the positional and keyword arguments to the wrapped function must be hashable (i.e. Python's immutable built-in objects, not mutable containers). To get around this limitation the ``hash_func`` parameter of the ``cachier`` decorator can be provided with a callable that gets the args and kwargs from the decorated function and returns a hash key for them.
179
211
 
180
212
  .. code-block:: python
181
213
 
182
- @cachier(hash_params=hash_my_custom_class)
214
+ def calculate_hash(args, kwds):
215
+ key = ... # compute a hash key here based on arguments
216
+ return key
217
+
218
+ @cachier(hash_func=calculate_hash)
183
219
  def calculate_super_complex_stuff(custom_obj):
184
220
  # amazing code goes here
185
221
 
@@ -188,6 +224,23 @@ See here for an example:
188
224
  `Question: How to work with unhashable arguments <https://github.com/python-cachier/cachier/issues/91>`_
189
225
 
190
226
 
227
+ Precaching values
228
+ ---------------------------------
229
+
230
+ If you want to load a value into the cache without calling the underlying function, this can be done with the `precache_value` function.
231
+
232
+ .. code-block:: python
233
+
234
+ @cachier()
235
+ def add(arg1, arg2):
236
+ return arg1 + arg2
237
+
238
+ add.precache_value(2, 2, value_to_cache=5)
239
+
240
+ result = add(2, 2)
241
+ print(result) # prints 5
242
+
243
+
191
244
  Per-function call arguments
192
245
  ---------------------------
193
246
 
@@ -377,7 +430,7 @@ Other major contributors:
377
430
 
378
431
  * `cthoyt <https://github.com/cthoyt>`_ - Base memory core implementation.
379
432
 
380
- * `amarczew <https://github.com/amarczew>`_ - The ``hash_params`` kwarg.
433
+ * `amarczew <https://github.com/amarczew>`_ - The ``hash_func`` kwarg.
381
434
 
382
435
  * `non-senses <https://github.com/non-senses>`_ - The ``wait_for_calc_timeout`` kwarg.
383
436
 
@@ -423,5 +476,3 @@ Notable bugfixers:
423
476
  .. _watchdog: https://github.com/gorakhargosh/watchdog
424
477
 
425
478
 
426
-
427
-
@@ -0,0 +1,15 @@
1
+ cachier/__init__.py,sha256=znE73J-Sg_4tjDmfKaJ5Cabg_kWhus9yhq1LJmM8B6Q,133
2
+ cachier/_version.py,sha256=Gk55atXZn9Zmgvi_28RCi_UXaHw85U1VAatxQ7cEXK0,471
3
+ cachier/base_core.py,sha256=3TJOmzCwtoGAGsMj-4zo91C6eP69cSB-40Lru3MFgBg,2663
4
+ cachier/core.py,sha256=L0dWlbERd-8RiGPP3Iw1sbNzgclO7wSSflS4QbkaQmY,11454
5
+ cachier/memory_core.py,sha256=do4aKTxcNaoaCpLx6w2bhhLIAze8tEo9gPNAekwWrHo,3020
6
+ cachier/mongo_core.py,sha256=Tbe-fpWyvlYK_WQq02-K2WDGqtoz90rwcTS_DFT146I,5114
7
+ cachier/pickle_core.py,sha256=4-sji-yQNfTvutpxHBHzZbourHyby_7ykGQFLf8dC58,10150
8
+ cachier/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ cachier/scripts/cli.py,sha256=tMwq1IaD_lxhcc8WMgWh4P0gpi5l6-twCS2YeAKAM98,429
10
+ cachier-2.1.0.dist-info/LICENSE,sha256=-2WrMJkIa0gVP6YQHXXDT7ws-S3M2NEVEF4XF3K8qrY,1069
11
+ cachier-2.1.0.dist-info/METADATA,sha256=ysQu-4vNtUdDT2wQjGAsrgfzZNOWaEWKPKdTinfOM_8,16470
12
+ cachier-2.1.0.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110
13
+ cachier-2.1.0.dist-info/entry_points.txt,sha256=HZPL3TEoT-aieCOvQvsLEDBAuPBSbDNrIjMiDA8h6zE,71
14
+ cachier-2.1.0.dist-info/top_level.txt,sha256=_rW_HiJumDCch67YT-WAgzcyvKg5RiYDMZq9d-0ZpaE,8
15
+ cachier-2.1.0.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- cachier/__init__.py,sha256=znE73J-Sg_4tjDmfKaJ5Cabg_kWhus9yhq1LJmM8B6Q,133
2
- cachier/_version.py,sha256=a5msFbwD6NYMINT1KG0orJkvdk7TUYcBzgZ2eQgM_Ts,471
3
- cachier/base_core.py,sha256=PT2fhBy4P8PyaBy_iR6FFbTStDBMeNtF_FVMY7ax7ww,2157
4
- cachier/core.py,sha256=h3dCDlBdUYSsJ2AOUVl-IbNjE6H5NH9y-nlzlxXWYoI,10869
5
- cachier/memory_core.py,sha256=5PGm1avW_nHlctvJrYWlerLWgttKpP69epOt2e5r1O0,3072
6
- cachier/mongo_core.py,sha256=-YOjOOMVCu1bVb26nge2b4vatxFwafAyA52RKzhL9xc,5191
7
- cachier/pickle_core.py,sha256=b7QtVjuRvcUnC2ecabMmH7Zu8JYXF251cWWTFv4Iv48,10354
8
- cachier-2.0.1.dist-info/LICENSE,sha256=-2WrMJkIa0gVP6YQHXXDT7ws-S3M2NEVEF4XF3K8qrY,1069
9
- cachier-2.0.1.dist-info/METADATA,sha256=0wGUUQ0pfQEq3uh8gIDpkmU0Gjil3NX_K8xPJm5jQSg,14837
10
- cachier-2.0.1.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110
11
- cachier-2.0.1.dist-info/entry_points.txt,sha256=HZPL3TEoT-aieCOvQvsLEDBAuPBSbDNrIjMiDA8h6zE,71
12
- cachier-2.0.1.dist-info/top_level.txt,sha256=_rW_HiJumDCch67YT-WAgzcyvKg5RiYDMZq9d-0ZpaE,8
13
- cachier-2.0.1.dist-info/RECORD,,