From 1c9f29d361023bfebd9b0f8f0b3ccc62ead774a6 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 19 Sep 2017 07:55:30 -0700 Subject: [PATCH 1/3] Separate properties module --- pandas/_libs/lib.pyx | 2 +- pandas/_libs/properties.pyx | 69 +++++++++++++++++++++++++++++++++++++ setup.py | 3 +- 3 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 pandas/_libs/properties.pyx diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index 53ca41e4b2489..a9226d8f3ce41 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -67,6 +67,7 @@ import tslib from tslib import NaT, Timestamp, Timedelta import interval from interval import Interval +from properties import AxisProperty, cache_readonly # noqa cdef int64_t NPY_NAT = util.get_nat() @@ -1907,5 +1908,4 @@ cdef class BlockPlacement: include "reduce.pyx" -include "properties.pyx" include "inference.pyx" diff --git a/pandas/_libs/properties.pyx b/pandas/_libs/properties.pyx new file mode 100644 index 0000000000000..22d66356ebdc3 --- /dev/null +++ b/pandas/_libs/properties.pyx @@ -0,0 +1,69 @@ + +from cython cimport Py_ssize_t + +from cpython cimport ( + PyDict_Contains, PyDict_GetItem, PyDict_SetItem) + + +cdef class cache_readonly(object): + + cdef readonly: + object func, name, allow_setting + + def __init__(self, func=None, allow_setting=False): + if func is not None: + self.func = func + self.name = func.__name__ + self.allow_setting = allow_setting + + def __call__(self, func, doc=None): + self.func = func + self.name = func.__name__ + return self + + def __get__(self, obj, typ): + # Get the cache or set a default one if needed + + cache = getattr(obj, '_cache', None) + if cache is None: + try: + cache = obj._cache = {} + except (AttributeError): + return + + if PyDict_Contains(cache, self.name): + # not necessary to Py_INCREF + val = PyDict_GetItem(cache, self.name) + else: + val = self.func(obj) + PyDict_SetItem(cache, self.name, val) + return val + + def __set__(self, obj, value): + + if not self.allow_setting: + raise Exception("cannot set values for [%s]" % self.name) + + # Get the cache or set a default one if needed + cache = getattr(obj, '_cache', None) + if cache is None: + try: + cache = obj._cache = {} + except (AttributeError): + return + + PyDict_SetItem(cache, self.name, value) + +cdef class AxisProperty(object): + cdef: + Py_ssize_t axis + + def __init__(self, axis=0): + self.axis = axis + + def __get__(self, obj, type): + cdef list axes = obj._data.axes + return axes[self.axis] + + def __set__(self, obj, value): + obj._set_axis(self.axis, value) diff --git a/setup.py b/setup.py index 0e4e22b875e1d..d28c4ba8be5b0 100755 --- a/setup.py +++ b/setup.py @@ -437,7 +437,7 @@ def get_tag(self): cmdclass['build_src'] = DummyBuildSrc cmdclass['build_ext'] = CheckingBuildExt -lib_depends = ['reduce', 'inference', 'properties'] +lib_depends = ['reduce', 'inference'] def srcpath(name=None, suffix='.pyx', subdir='src'): @@ -478,6 +478,7 @@ def pxd(name): ext_data = { '_libs.lib': {'pyxfile': '_libs/lib', 'depends': lib_depends + tseries_depends}, + '_libs.properties': {'pyxfile': '_libs/properties', 'include': []}, '_libs.hashtable': {'pyxfile': '_libs/hashtable', 'pxdfiles': ['_libs/hashtable'], 'depends': (['pandas/_libs/src/klib/khash_python.h'] From 74bfb1f908368651a3c26007b1c5a6548301c62f Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Thu, 21 Sep 2017 16:10:34 -0700 Subject: [PATCH 2/3] remove defunct src/properties.pyx --- pandas/_libs/src/properties.pyx | 66 --------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 pandas/_libs/src/properties.pyx diff --git a/pandas/_libs/src/properties.pyx b/pandas/_libs/src/properties.pyx deleted file mode 100644 index 4a3fd4b771a17..0000000000000 --- a/pandas/_libs/src/properties.pyx +++ /dev/null @@ -1,66 +0,0 @@ -from cpython cimport ( - PyDict_Contains, PyDict_GetItem, PyDict_GetItem, PyDict_SetItem) - - -cdef class cache_readonly(object): - - cdef readonly: - object func, name, allow_setting - - def __init__(self, func=None, allow_setting=False): - if func is not None: - self.func = func - self.name = func.__name__ - self.allow_setting = allow_setting - - def __call__(self, func, doc=None): - self.func = func - self.name = func.__name__ - return self - - def __get__(self, obj, typ): - # Get the cache or set a default one if needed - - cache = getattr(obj, '_cache', None) - if cache is None: - try: - cache = obj._cache = {} - except (AttributeError): - return - - if PyDict_Contains(cache, self.name): - # not necessary to Py_INCREF - val = PyDict_GetItem(cache, self.name) - else: - val = self.func(obj) - PyDict_SetItem(cache, self.name, val) - return val - - def __set__(self, obj, value): - - if not self.allow_setting: - raise Exception("cannot set values for [%s]" % self.name) - - # Get the cache or set a default one if needed - cache = getattr(obj, '_cache', None) - if cache is None: - try: - cache = obj._cache = {} - except (AttributeError): - return - - PyDict_SetItem(cache, self.name, value) - -cdef class AxisProperty(object): - cdef: - Py_ssize_t axis - - def __init__(self, axis=0): - self.axis = axis - - def __get__(self, obj, type): - cdef list axes = obj._data.axes - return axes[self.axis] - - def __set__(self, obj, value): - obj._set_axis(self.axis, value) From dd377af595c15d88fa50a1a3bf24aa642df81b81 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Thu, 21 Sep 2017 16:10:50 -0700 Subject: [PATCH 3/3] import cache_readonly and AxisProperty directly from _libs.properties --- pandas/_libs/lib.pyx | 1 - pandas/core/generic.py | 4 ++-- pandas/util/_decorators.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index a9226d8f3ce41..01548e17d39ab 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -67,7 +67,6 @@ import tslib from tslib import NaT, Timestamp, Timedelta import interval from interval import Interval -from properties import AxisProperty, cache_readonly # noqa cdef int64_t NPY_NAT = util.get_nat() diff --git a/pandas/core/generic.py b/pandas/core/generic.py index a71bf7be1bc75..e0a9fdb08dcb2 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -9,7 +9,7 @@ import numpy as np import pandas as pd -from pandas._libs import tslib, lib +from pandas._libs import tslib, lib, properties from pandas.core.dtypes.common import ( _ensure_int64, _ensure_object, @@ -258,7 +258,7 @@ def _setup_axes(cls, axes, info_axis=None, stat_axis=None, aliases=None, if build_axes: def set_axis(a, i): - setattr(cls, a, lib.AxisProperty(i)) + setattr(cls, a, properties.AxisProperty(i)) cls._internal_names_set.add(a) if axes_are_reversed: diff --git a/pandas/util/_decorators.py b/pandas/util/_decorators.py index bb7ffe45c689b..31e27817913c5 100644 --- a/pandas/util/_decorators.py +++ b/pandas/util/_decorators.py @@ -1,5 +1,5 @@ from pandas.compat import callable, signature -from pandas._libs.lib import cache_readonly # noqa +from pandas._libs.properties import cache_readonly # noqa import types import warnings from textwrap import dedent