Giter Club home page Giter Club logo

plone.memoize's Introduction

plone.memoize

plone.memoize provides Python function decorators for caching the values of functions and methods.

The type of cache storage is freely configurable by the user, as is the cache key, which is what the function's value depends on.

plone.memoize has support for memcached and is easily extended to use other caching storages. It also has specialized decorators for use with Zope views. However, plone.memoize can be used without Zope.

plone.memoize's People

Contributors

ale-rt avatar andbag avatar bogdangi avatar davisagli avatar dnouri avatar esteele avatar frapell avatar garbas avatar gforcada avatar hannosch avatar icemac avatar jensens avatar matthewwilkes avatar mauritsvanrees avatar optilude avatar pgrunewald avatar pre-commit-ci[bot] avatar stefanholek avatar thet avatar tomgross avatar wichert avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

plone.memoize's Issues

tox is broken

❯ tox -e py38
py38 installed: coverage==5.5,zc.buildout==2.13.3
py38 run-test-pre: PYTHONHASHSEED='2423449449'
py38 run-test: commands[0] | /tmp/plone.memoize/.tox/py38/bin/buildout -c /tmp/plone.memoize/buildout.cfg buildout:directory=/tmp/plone.memoize/.tox/py38 buildout:develop=/tmp/plone.memoize bootstrap
Creating directory '/tmp/plone.memoize/.tox/py38/develop-eggs'.
Generated script '/tmp/plone.memoize/.tox/py38/bin/buildout'.
py38 run-test: commands[1] | /tmp/plone.memoize/.tox/py38/bin/buildout -c /tmp/plone.memoize/buildout.cfg buildout:directory=/tmp/plone.memoize/.tox/py38 buildout:develop=/tmp/plone.memoize install test
Upgraded:
  setuptools version 42.0.2;
restarting.
Generated script '/tmp/plone.memoize/.tox/py38/bin/buildout'.
While:
  Initializing.
Error: Couldn't open /tmp/plone.memoize/.tox/py38/buildout.cfg
ERROR: InvocationError for command /tmp/plone.memoize/.tox/py38/bin/buildout -c buildout.cfg buildout:directory=/tmp/plone.memoize/.tox/py38 buildout:develop=/tmp/plone.memoize install test (exited with code 1)
_______________________________________________________________________________________ summary _______________________________________________________________________________________
ERROR:   py38: commands failed

I noticed this as I ran tox / tox4-pre on all Zope/Plone repositories, see https://jugmac00.github.io/blog/testing-the-tox-4-pre-release-at-scale/

P.S. The above error is for tox 3, the current version.

The upcoming tox4 fails for a different reason... there is an endless setuptools update circle, which finally leads to memory exhaustion of the developer box.

plone.memoize on  master via 🐍 v2.7.17 took 14s 
❯ tox4 -e py38
py38: install_deps> python -I -m pip install coverage zc.buildout
py38: commands[0]> .tox/4/py38/bin/buildout -c /tmp/plone.memoize/buildout.cfg buildout:directory=/tmp/plone.memoize/.tox/4/py38 buildout:develop=/tmp/plone.memoize bootstrap
Creating directory '/tmp/plone.memoize/.tox/4/py38/eggs'.
Creating directory '/tmp/plone.memoize/.tox/4/py38/parts'.
Creating directory '/tmp/plone.memoize/.tox/4/py38/develop-eggs'.
Generated script '/tmp/plone.memoize/.tox/4/py38/bin/buildout'.
py38: commands[1]> .tox/4/py38/bin/buildout -c /tmp/plone.memoize/buildout.cfg buildout:directory=/tmp/plone.memoize/.tox/4/py38 buildout:develop=/tmp/plone.memoize install test
Getting distribution for 'setuptools==42.0.2'.
Got setuptools 42.0.2.
Upgraded:
  setuptools version 42.0.2;
restarting.
Generated script '/tmp/plone.memoize/.tox/4/py38/bin/buildout'.
Upgraded:
  setuptools version 42.0.2;
restarting.
Generated script '/tmp/plone.memoize/.tox/4/py38/bin/buildout'.
Upgraded:
  setuptools version 42.0.2;
restarting.
Upgraded:
  setuptools version 42.0.2;
restarting.
Upgraded:
  setuptools version 42.0.2;
restarting.

I am not using this package, and unfortunately I won't have time to look into these issues.

Allow plone.memoize.view to use the global request

view.memoize and view.memoize_contextless require to have a request attribute set to work.

Sometimes it might be useful to use it also for adapter or functions that do not have a request attribute.
It would be great if in this case the global request could be picked up.

Py 3.11: AttributeError: module 'inspect' has no attribute 'getargspec'

Running the tests with Plone 6.0 on Python 3.11 fails:

File "/Users/maurits/shared-eggs/cp311/plone.memoize-2.1.1-py3.11.egg/plone/memoize/request.rst", line 40, in request.rst
Failed example:
    cached_increment(A(1))
Exception raised:
    Traceback (most recent call last):
      File "/Users/maurits/.pyenv/versions/3.11.0rc2/lib/python3.11/doctest.py", line 1350, in __run
        exec(compile(example.source, filename, "single",
      File "<doctest request.rst[10]>", line 1, in <module>
        cached_increment(A(1))
      File "/Users/maurits/shared-eggs/cp311/plone.memoize-2.1.1-py3.11.egg/plone/memoize/volatile.py", line 71, in replacement
        cache = get_cache(fun, *args, **kwargs)
      File "/Users/maurits/shared-eggs/cp311/plone.memoize-2.1.1-py3.11.egg/plone/memoize/request.py", line 56, in _store_in_annotation
        spec = inspect.getargspec(fun)
    AttributeError: module 'inspect' has no attribute 'getargspec'

Clean up package

As suggested by @thet in #18 (review)

  • I'd remove bootstrap-buildout.py and add a note on how to bootstrap buildout using pip install.
  • I'd add [isort] and [flake8] config sections into setup.cfg
  • I'd also do a isort -rc -y if not done already

Work in FIPS enabled environments

On FIPS enabled environments, starting Plone fails with

...
...
  File "/opt/plone/buildout-cache/eggs/plone.memoize-2.1.0-py3.6.egg/plone/memoize/volatile.py", line 72, in replacement
    cached_value = cache.get(key, _marker)
  File "/opt/plone/buildout-cache/eggs/plone.memoize-2.1.0-py3.6.egg/plone/memoize/ram.py", line 36, in get
    return self.__getitem__(key)
  File "/opt/plone/buildout-cache/eggs/plone.memoize-2.1.0-py3.6.egg/plone/memoize/ram.py", line 75, in __getitem__
    self.globalkey, dict(key=self._make_key(key)), MARKER
  File "/opt/plone/buildout-cache/eggs/plone.memoize-2.1.0-py3.6.egg/plone/memoize/ram.py", line 71, in _make_key
    return md5(source).digest()
ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for FIPS

There is a flag that can be used when hasing with md5 in a non security related usage that is not available if FIPS is not enabled in the environment called usedforsecurity

I will submit a PR shortly with a proposed fix (The same that was done with zodb/relstorage#481)

_marker pattern is slow and cumbersome

If you look at plone.memoize.view code it is using a marker to check if the cache is cold, something like in this function:

_marker = object()

def old(d):
    value = d.get("key", _marker)
    if value is _marker:
        value = d["key"] = 1
    return value

Theoretically this should be equivalent and simpler:

def new(d):
    if "key" not in d:
        d["key"] = 1
    return d["key"]

In addition it seems to perform better:

from timeit import timeit

empty = {}
not_empty = {"key": 1}

def _benchmark(value):
    print(value, timeit(value, number=10000000, globals=globals()))

_benchmark("old(empty)")
_benchmark("old(not_empty)")
_benchmark("new(empty)")
_benchmark("new(not_empty)")
_benchmark("old(empty)")
_benchmark("old(not_empty)")
_benchmark("new(empty)")
_benchmark("new(not_empty)")

These are the results:

[ale@emily benchmark]$ python3 in.py 
old(empty) 1.3479654699913226
old(not_empty) 1.3339006070164032
new(empty) 0.9015584019944072
new(not_empty) 0.9282507239840925
old(empty) 1.3717991490266286
old(not_empty) 1.4188532830448821
new(empty) 0.9324833910213783
new(not_empty) 0.943703431985341

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.