diff --git a/my/core/__main__.py b/my/core/__main__.py index 8755c0c..1787538 100644 --- a/my/core/__main__.py +++ b/my/core/__main__.py @@ -378,13 +378,14 @@ def query_hpi_functions( pprint(res) else: # output == 'repl' + eprint(f"\nInteract with the results by using the {click.style('res', fg='green')} variable\n") try: import IPython # type: ignore[import] except ModuleNotFoundError: - eprint("'repl' requires ipython, install it with 'python3 -m pip install ipython'") - sys.exit(1) + eprint("'repl' typically uses ipython, install it with 'python3 -m pip install ipython'. falling back to stdlib...") + import code + code.interact(local=locals()) else: - eprint(f"\nInteract with the results by using the {click.style('res', fg='green')} variable\n") IPython.embed() @@ -502,35 +503,35 @@ def module_install_cmd(user: bool, module: str) -> None: @click.option('-k', '--order-key', default=None, - type=click.STRING, + type=str, help='order by an object attribute or dict key on the individual objects returned by the HPI function') @click.option('-t', '--order-type', default=None, - type=click.Choice(['datetime', 'int', 'float']), + type=click.Choice(['datetime', 'date', 'int', 'float']), help='order by searching for some type on the iterable') @click.option('--after', default=None, - type=click.STRING, + type=str, help='while ordering, filter items for the key or type larger than or equal to this') @click.option('--before', default=None, - type=click.STRING, + type=str, help='while ordering, filter items for the key or type smaller than this') @click.option('--within', default=None, - type=click.STRING, + type=str, help="a range 'after' or 'before' to filter items by. see above for further explanation") @click.option('--recent', default=None, - type=click.STRING, + type=str, help="a shorthand for '--order-type datetime --reverse --before now --within'. e.g. --recent 5d") @click.option('--reverse/--no-reverse', default=False, help='reverse the results returned from the functions') @click.option('--limit', default=None, - type=click.INT, + type=int, help='limit the number of items returned from the (functions)') @click.option('--drop-unsorted', default=False, @@ -592,11 +593,13 @@ def query_cmd( hpi query --order-type datetime --after '2016-01-01 00:00:00' --before '2019-01-01 00:00:00' my.reddit.comments ''' - from datetime import datetime + from datetime import datetime, date chosen_order_type: Optional[Type] if order_type == "datetime": chosen_order_type = datetime + if order_type == "date": + chosen_order_type = date elif order_type == "int": chosen_order_type = int elif order_type == "float": @@ -606,7 +609,7 @@ def query_cmd( if recent is not None: before = "now" - chosen_order_type = datetime + chosen_order_type = chosen_order_type or datetime # dont override if the user specified date within = recent reverse = not reverse diff --git a/my/core/common.py b/my/core/common.py index a891a18..dacdd76 100644 --- a/my/core/common.py +++ b/my/core/common.py @@ -352,21 +352,12 @@ class classproperty(Generic[_R]): tzdatetime = datetime -fromisoformat: Callable[[str], datetime] -import sys -if sys.version_info[:2] >= (3, 7): - # prevent mypy on py3.6 from complaining... - fromisoformat_real = datetime.fromisoformat - fromisoformat = fromisoformat_real -else: - from .py37 import fromisoformat - - # TODO doctests? def isoparse(s: str) -> tzdatetime: """ Parses timestamps formatted like 2020-05-01T10:32:02.925961Z """ + from .compat import fromisoformat # TODO could use dateutil? but it's quite slow as far as I remember.. # TODO support non-utc.. somehow? assert s.endswith('Z'), s diff --git a/my/core/compat.py b/my/core/compat.py index eb973fa..4a0d79f 100644 --- a/my/core/compat.py +++ b/my/core/compat.py @@ -2,6 +2,8 @@ Some backwards compatibility stuff/deprecation helpers ''' from types import ModuleType +from typing import Callable +from datetime import datetime from . import warnings from .common import LazyLogger @@ -10,6 +12,16 @@ from .common import LazyLogger logger = LazyLogger('my.core.compat') +fromisoformat: Callable[[str], datetime] +import sys +if sys.version_info[:2] >= (3, 7): + # prevent mypy on py3.6 from complaining... + fromisoformat_real = datetime.fromisoformat + fromisoformat = fromisoformat_real +else: + from .py37 import fromisoformat + + def pre_pip_dal_handler( name: str, e: ModuleNotFoundError, diff --git a/my/core/error.py b/my/core/error.py index 33ba96a..e11103e 100644 --- a/my/core/error.py +++ b/my/core/error.py @@ -127,7 +127,7 @@ def attach_dt(e: Exception, *, dt: Optional[datetime]) -> Exception: # todo it might be problematic because might mess with timezones (when it's converted to string, it's converted to a shift) def extract_error_datetime(e: Exception) -> Optional[datetime]: - from .common import fromisoformat + from .compat import fromisoformat import re for x in reversed(e.args): if isinstance(x, datetime): diff --git a/my/core/query_range.py b/my/core/query_range.py index cbaedba..1b8f040 100644 --- a/my/core/query_range.py +++ b/my/core/query_range.py @@ -24,14 +24,8 @@ from .query import ( ET, ) -fromisoformat: Callable[[str], datetime] -import sys -if sys.version_info[:2] >= (3, 7): - # prevent mypy on py3.6 from complaining... - fromisoformat_real = datetime.fromisoformat - fromisoformat = fromisoformat_real -else: - from .py37 import fromisoformat +from .compat import fromisoformat +from .common import isoparse timedelta_regex = re.compile(r"^((?P[\.\d]+?)w)?((?P[\.\d]+?)d)?((?P[\.\d]+?)h)?((?P[\.\d]+?)m)?((?P[\.\d]+?)s)?$") @@ -82,10 +76,11 @@ def parse_datetime_float(date_str: str) -> float: # isoformat - default format when you call str() on datetime return fromisoformat(ds).timestamp() except ValueError: + pass + try: + return isoparse(ds).timestamp() + except (AssertionError, ValueError): raise QueryException(f"Was not able to parse {ds} into a datetime") - # todo: add isoparse from my.core.common? not sure how it handles - # timezones and this purposefully avoids that by converting all - # datelike items to floats instead # probably DateLike input? but a user could specify an order_key @@ -329,7 +324,7 @@ Specify a type or a key to order the value by""") # sort the iterable by the generated order_by_chosen function itr = select(itr, order_by=order_by_chosen, drop_unsorted=True) filter_func: Optional[Where] - if order_by_value_type == datetime: + if order_by_value_type in [datetime, date]: filter_func = _create_range_filter( unparsed_range=unparsed_range, end_parser=parse_datetime_float,