From 2bc7a5dbfde7fc1da8668481eca1603d334d151a Mon Sep 17 00:00:00 2001 From: Tim Harder Date: Wed, 29 Nov 2023 09:29:51 -0700 Subject: [PATCH] dep: move Dep caching support into CachedDep class That provides LRU-based instance caching for Dep objects. --- benches/test_dep.py | 3 ++- membench/dep.py | 6 +++--- src/pkgcraft/dep/pkg.pyx | 18 +++++------------- tests/dep/test_pkg.py | 10 ++++++---- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/benches/test_dep.py b/benches/test_dep.py index a0130dbe..16a90a08 100644 --- a/benches/test_dep.py +++ b/benches/test_dep.py @@ -2,6 +2,7 @@ from pkgcore.ebuild.atom import atom as pkgcore_dep from portage.dep import Atom as portage_dep +from pkgcraft.dep import CachedDep as pkgcraft_cached_dep from pkgcraft.dep import Dep as pkgcraft_dep pytest_plugins = ("benchmark", "pkgcraft") @@ -16,7 +17,7 @@ def random_dep(func, random_str): dep_funcs = [ ("pkgcraft", pkgcraft_dep), - ("pkgcraft", pkgcraft_dep.cached), + ("pkgcraft", pkgcraft_cached_dep), ("pkgcore", pkgcore_dep), ("portage", portage_dep), ] diff --git a/membench/dep.py b/membench/dep.py index d70b1dfb..ba176f92 100644 --- a/membench/dep.py +++ b/membench/dep.py @@ -11,13 +11,13 @@ from pkgcore.ebuild.atom import atom as pkgcore_dep from portage.dep import Atom as portage_dep -from pkgcraft.dep import Dep as pkgcraft_dep +from pkgcraft.dep import CachedDep, Dep eprint = lambda x: print(x, file=sys.stderr) dep_funcs = [ - ("pkgcraft", pkgcraft_dep), - ("pkgcraft-cached", pkgcraft_dep.cached), + ("pkgcraft", Dep), + ("pkgcraft-cached", CachedDep), ("pkgcore", pkgcore_dep), ("portage", portage_dep), ] diff --git a/src/pkgcraft/dep/pkg.pyx b/src/pkgcraft/dep/pkg.pyx index c7ca0640..f5b145ec 100644 --- a/src/pkgcraft/dep/pkg.pyx +++ b/src/pkgcraft/dep/pkg.pyx @@ -1,5 +1,4 @@ from enum import IntEnum -from functools import lru_cache from types import MappingProxyType cimport cython @@ -12,18 +11,12 @@ from ..restrict cimport Restrict from . cimport Cpv from .version cimport Version +from .._misc import LruInstanceCache from ..eapi import EAPI_LATEST from ..error import InvalidDep from ..types import OrderedFrozenSet -# TODO: merge with Dep.cached function when cython bug is fixed -# https://github.com/cython/cython/issues/1434 -@lru_cache(maxsize=10000) -def _cached_dep(cls, dep, eapi=None): - return cls(dep, eapi) - - class Blocker(IntEnum): """Package dependency blocker.""" Strong = C.BLOCKER_STRONG @@ -125,11 +118,6 @@ cdef class Dep: inst.ptr = ptr return inst - @classmethod - def cached(cls, s: str, eapi=None): - """Return a cached Dep if one exists, otherwise return a new instance.""" - return _cached_dep(cls, s, eapi) - @staticmethod def valid(s: str, eapi=None, raised=False): """Determine if a string is a valid package dependency. @@ -618,6 +606,10 @@ cdef class Dep: C.pkgcraft_dep_free(self.ptr) +class CachedDep(Dep, metaclass=LruInstanceCache): + """Package dependency with LRU-based instance caching.""" + + @cython.final cdef class Cpn(Dep): """Unversioned package dependency.""" diff --git a/tests/dep/test_pkg.py b/tests/dep/test_pkg.py index 475cd5f1..7e2938bf 100644 --- a/tests/dep/test_pkg.py +++ b/tests/dep/test_pkg.py @@ -355,16 +355,18 @@ def test_hash(self): length = 1 if d["equal"] else len(d["versions"]) assert len(s) == length - def test_cached(self): - l = [Dep.cached("cat/pkg") for _ in range(1000)] - assert len(l) == 1000 - def test_pickle(self): dep = Dep("=cat/pkg-1-r2:0/2=[a,b,c]") new_dep = pickle.loads(pickle.dumps(dep)) assert dep == new_dep +class TestCachedDep: + def test_cached(self): + assert CachedDep("cat/pkg") is CachedDep("cat/pkg") + assert Dep("cat/pkg") is not Dep("cat/pkg") + + class TestCpn: def test_creation(self): dep = Cpn("cat/pkg")