From 4e59a65f9acbb7172b21d2ecf84e5da71b125534 Mon Sep 17 00:00:00 2001 From: Dima Gerasimov Date: Tue, 31 May 2022 13:06:29 +0100 Subject: [PATCH] core/general: move cached_property into compat, use standard implementation from python3.8 --- my/coding/codeforces.py | 10 +++++----- my/coding/topcoder.py | 11 ++++++----- my/core/common.py | 10 +++------- my/core/compat.py | 13 +++++++++++++ my/rtm.py | 13 +++++++------ my/twitter/archive.py | 8 ++++---- 6 files changed, 38 insertions(+), 27 deletions(-) diff --git a/my/coding/codeforces.py b/my/coding/codeforces.py index 659a2d9..1ac6ba4 100644 --- a/my/coding/codeforces.py +++ b/my/coding/codeforces.py @@ -6,8 +6,8 @@ from typing import NamedTuple import json from typing import Dict, Iterator -from ..common import cproperty, get_files -from ..error import Res, unwrap +from ..core import get_files, Res, unwrap +from ..core.compat import cached_property from ..core.konsume import ignore, wrap from kython import fget @@ -46,18 +46,18 @@ class Competition(NamedTuple): contest: str cmap: Cmap - @cproperty + @cached_property def uid(self) -> Cid: return self.contest_id def __hash__(self): return hash(self.contest_id) - @cproperty + @cached_property def when(self) -> datetime: return self.cmap[self.uid].when - @cproperty + @cached_property def summary(self) -> str: return f'participated in {self.contest}' # TODO diff --git a/my/coding/topcoder.py b/my/coding/topcoder.py index 43a2c8a..2577dd1 100644 --- a/my/coding/topcoder.py +++ b/my/coding/topcoder.py @@ -6,8 +6,9 @@ from typing import NamedTuple import json from typing import Dict, Iterator -from ..common import cproperty, get_files -from ..error import Res, unwrap +from ..core import get_files, Res, unwrap +from ..core.compat import cached_property +from ..core.error import Res, unwrap # TODO get rid of fget? from kython import fget @@ -26,18 +27,18 @@ class Competition(NamedTuple): percentile: float dates: str - @cproperty + @cached_property def uid(self) -> str: return self.contest_id def __hash__(self): return hash(self.contest_id) - @cproperty + @cached_property def when(self) -> datetime: return datetime.strptime(self.dates, '%Y-%m-%dT%H:%M:%S.%fZ') - @cproperty + @cached_property def summary(self) -> str: return f'participated in {self.contest}: {self.percentile:.0f}' diff --git a/my/core/common.py b/my/core/common.py index b7db362..c72fc77 100644 --- a/my/core/common.py +++ b/my/core/common.py @@ -128,13 +128,6 @@ def test_make_dict() -> None: assert d == {0: 0, 1: 1, 2: 0, 3: 1, 4: 0} -Cl = TypeVar('Cl') -R = TypeVar('R') - -def cproperty(f: Callable[[Cl], R]) -> R: - return property(functools.lru_cache(maxsize=1)(f)) # type: ignore - - # https://stackoverflow.com/a/12377059/706389 def listify(fn=None, wrapper=list): """ @@ -638,3 +631,6 @@ class DummyExecutor(Executor): def shutdown(self, wait: bool=True) -> None: # type: ignore[override] self._shutdown = True + +# legacy deprecated import +from .compat import cached_property as cproperty diff --git a/my/core/compat.py b/my/core/compat.py index 4dc8865..a2a627c 100644 --- a/my/core/compat.py +++ b/my/core/compat.py @@ -90,3 +90,16 @@ def removeprefix(text: str, prefix: str) -> str: if text.startswith(prefix): return text[len(prefix):] return text + + +# can remove after python3.8 +if sys.version_info[:2] >= (3, 8): + from functools import cached_property +else: + from typing import TypeVar, Callable + Cl = TypeVar('Cl') + R = TypeVar('R') + def cached_property(f: Callable[[Cl], R]) -> R: + return property(functools.lru_cache(maxsize=1)(f)) # type: ignore + del Cl + del R diff --git a/my/rtm.py b/my/rtm.py index 2fc783f..2731049 100755 --- a/my/rtm.py +++ b/my/rtm.py @@ -10,7 +10,8 @@ import re from typing import Dict, List, Iterator from datetime import datetime -from .common import LazyLogger, get_files, group_by_key, cproperty, make_dict +from .core.common import LazyLogger, get_files, group_by_key, make_dict +from .core.compat import cached_property from my.config import rtm as config @@ -28,14 +29,14 @@ class MyTodo: self.todo = todo self.revision = revision - @cproperty + @cached_property def notes(self) -> List[str]: # TODO can there be multiple?? desc = self.todo['DESCRIPTION'] notes = re.findall(r'---\n\n(.*?)\n\nUpdated:', desc, flags=re.DOTALL) return notes - @cproperty + @cached_property def tags(self) -> List[str]: desc = self.todo['DESCRIPTION'] [tags_str] = re.findall(r'\nTags: (.*?)\n', desc, flags=re.DOTALL) @@ -44,11 +45,11 @@ class MyTodo: tags = [t.strip() for t in tags_str.split(',')] return tags - @cproperty + @cached_property def uid(self) -> str: return str(self.todo['UID']) - @cproperty + @cached_property def title(self) -> str: return str(self.todo['SUMMARY']) @@ -59,7 +60,7 @@ class MyTodo: return str(self.todo['STATUS']) # TODO tz? - @cproperty + @cached_property def time(self) -> datetime: t1 = self.todo['DTSTAMP'].dt t2 = self.todo['LAST-MODIFIED'].dt diff --git a/my/twitter/archive.py b/my/twitter/archive.py index 0583214..9975e6e 100644 --- a/my/twitter/archive.py +++ b/my/twitter/archive.py @@ -21,9 +21,9 @@ except ImportError as ie: from dataclasses import dataclass -from functools import lru_cache import html from ..core.common import Paths, datetime_aware +from ..core.compat import cached_property from ..core.error import Res from ..core.kompress import ZipPath @@ -192,7 +192,7 @@ class ZipExport: # older format yield j - @lru_cache(1) + @cached_property def screen_name(self) -> str: [acc] = self.raw('account') return acc['username'] @@ -201,14 +201,14 @@ class ZipExport: # NOTE: for some reason, created_at doesn't seem to be in order # it mostly is, but there are a bunch of one-off random tweets where the time decreases (typically at the very end) for r in self.raw('tweet'): - yield Tweet(r, screen_name=self.screen_name()) + yield Tweet(r, screen_name=self.screen_name) def likes(self) -> Iterator[Like]: # TODO ugh. would be nice to unify Tweet/Like interface # however, akeout only got tweetId, full text and url for r in self.raw('like'): - yield Like(r, screen_name=self.screen_name()) + yield Like(r, screen_name=self.screen_name) # todo not sure about list and sorting? although can't hurt considering json is not iterative?