Skip to content
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ebca276
Retain raw Performance using header file
Vizonex May 19, 2026
fde50f5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 19, 2026
109b3a7
add changes to timeline
Vizonex May 19, 2026
e936ad5
Merge branch '_helpers_h' of https://github.com/Vizonex/propcache int…
Vizonex May 19, 2026
a95f2f2
fix spelling mistakes
Vizonex May 19, 2026
067c6c6
spelling mistake fix in _helpers_c.pyx
Vizonex May 19, 2026
90930ea
reformat function code
Vizonex May 19, 2026
6163eb9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 19, 2026
5723881
add same performance optimizations for cached_property
Vizonex May 19, 2026
951f14c
just extern the function inline there is no use in an extra header fi…
Vizonex May 19, 2026
a4a11fa
ensure changes reflect the ones made in the timeline
Vizonex May 19, 2026
99b85f6
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 19, 2026
b1fb8cc
removed unused functions to make linter happy.
Vizonex May 19, 2026
b5fe811
Merge branch '_helpers_h' of https://github.com/Vizonex/propcache int…
Vizonex May 19, 2026
431da53
use Py_XINCREF incase val comes out as NULL
Vizonex May 19, 2026
e0a2d7b
improve cache type check performance
Vizonex May 19, 2026
5104841
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 19, 2026
8e66e62
reformat C code portion
Vizonex May 19, 2026
f38ad33
Merge branch 'master' into _helpers_h
Vizonex May 20, 2026
8800269
implement given suggestion to prevent memory leaks and leave in comme…
Vizonex May 21, 2026
64dfa66
Merge branch '_helpers_h' of https://github.com/Vizonex/propcache int…
Vizonex May 21, 2026
7d054a1
Merge branch 'master' into _helpers_h
Vizonex May 22, 2026
035086d
Merge branch 'master' into _helpers_h
Vizonex May 23, 2026
df60c83
fix wording of timeline
Vizonex May 23, 2026
68daad1
Merge branch 'master' into _helpers_h
Vizonex May 28, 2026
d005d50
Merge branch 'master' into _helpers_h
Vizonex Jun 4, 2026
7ced43a
Merge branch 'master' into _helpers_h
Vizonex Jun 14, 2026
4b71133
Merge branch 'master' into _helpers_h
Vizonex Jun 15, 2026
9cf61d4
Merge branch 'master' into _helpers_h
Vizonex Jun 21, 2026
7b92f21
Modify test coverage for being ridiculously unfair.
Vizonex Jun 27, 2026
2e63aa5
Merge branch 'master' into _helpers_h
Vizonex Jun 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES/245.bugfix.rst

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No imperative mood and no period before the em dash plz.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are my changes much improved now?

Retain raw performance of propcache by moving critical sections to C
-- by :user:`Vizonex`.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Retain raw performance of propcache by keeping it's critical logic
in a C function instead of in Cython.
-- by :user:`Vizonex`.
77 changes: 48 additions & 29 deletions src/propcache/_helpers_c.pyx
Original file line number Diff line number Diff line change
@@ -1,22 +1,53 @@
# cython: language_level=3, freethreading_compatible=True
from types import GenericAlias

from cpython.dict cimport PyDict_GetItem
from cpython.object cimport PyObject


# Added to prevent performance from degrading in the most critical sections.
cdef extern from "Python.h":
# Call a callable Python object callable with exactly
# 1 positional argument arg and no keyword arguments.
# Return the result of the call on success, or raise
# an exception and return NULL on failure.
PyObject* PyObject_CallOneArg(
object callable, object arg
) except NULL
int PyDict_SetItem(
object dict, object key, PyObject* value
) except -1
void Py_DECREF(PyObject*)
"""
/* Fixes performance regression when generating cython code. */
/* SEE: https://github.com/aio-libs/propcache/issues/244 */
static PyObject*
under_cached_property_get(
PyObject* wrapped,
PyObject* name,
PyObject* cache,
PyObject* inst
)
{
PyObject* val;

if (!PyDict_Check(cache)){
PyErr_Format(
PyExc_TypeError,
"Expected dict, got %.200s",
Py_TYPE(cache)->tp_name
);
return NULL;
}


val = PyDict_GetItem(cache, name);
if (val == NULL){
val = PyObject_CallOneArg(wrapped, inst);
if (val == NULL){
return NULL;
}
if (PyDict_SetItem(cache, name, val) < 0){
Py_CLEAR(val);
return NULL;
}
return val; /* already owned the ref from CallOneArg */
}
Py_INCREF(val); /* borrowed from PyDict_GetItem */
return val;
}
"""
object under_cached_property_get(
object wrapped,
object name,
object cache,
object inst
)


cdef class under_cached_property:
Expand All @@ -42,13 +73,7 @@ cdef class under_cached_property:
def __get__(self, object inst, owner):
if inst is None:
return self
cdef dict cache = inst._cache
cdef PyObject* val = PyDict_GetItem(cache, self.name)
if val == NULL:
val = PyObject_CallOneArg(self.wrapped, inst)
PyDict_SetItem(cache, self.name, val)
Py_DECREF(val)
return <object>val
return under_cached_property_get(self.wrapped, self.name, inst._cache, inst)

def __set__(self, inst, value):
raise AttributeError("cached property is read-only")
Expand Down Expand Up @@ -92,12 +117,6 @@ cdef class cached_property:
raise TypeError(
"Cannot use cached_property instance"
" without calling __set_name__ on it.")
cdef dict cache = inst.__dict__
cdef PyObject* val = PyDict_GetItem(cache, self.name)
if val is NULL:
val = PyObject_CallOneArg(self.func, inst)
PyDict_SetItem(cache, self.name, val)
Py_DECREF(val)
return <object>val
return under_cached_property_get(self.func, self.name, inst.__dict__, inst)

__class_getitem__ = classmethod(GenericAlias)
Loading