diff --git a/my/fbmessenger/__init__.py b/my/fbmessenger/__init__.py new file mode 100644 index 00000000..8407c64a --- /dev/null +++ b/my/fbmessenger/__init__.py @@ -0,0 +1,58 @@ +""" +This is here temporarily, for backwards compatibility purposes +It should be removed in the future, and you should replace any imports +like: +from my.fbmessenger import ... +to: +from my.fbmessenger.export import ... +since that allows for easier overriding using namespace packages +https://github.com/karlicoss/HPI/issues/102 +""" +# TODO ^^ later, replace the above with from my.fbmessenger.all, when we add more data sources + +# For now, including this here, since importing the module +# causes .export to be imported, which requires fbmessengerexport +REQUIRES = [ + 'git+https://github.com/karlicoss/fbmessengerexport', +] + +import re +import inspect + + +mname = 'fbmessenger' # todo infer from __name__? + + +# allow stuff like 'import my.module.submodule' and such +imported_as_parent = False + + +# allow stuff like 'from my.module import submodule' +importing_submodule = False + +# some hacky traceback to inspect the current stack +# to see if the user is using the old style of importing +for f in inspect.stack(): + # seems that when a submodule is imported, at some point it'll call some internal import machinery + # with 'parent' set to the parent module + # if parent module is imported first (i.e. in case of deprecated usage), it won't be the case + args = inspect.getargvalues(f.frame) + if args.locals.get('parent') == f'my.{mname}': + imported_as_parent = True + + # this we can only detect from the code I guess + line = '\n'.join(f.code_context or []) + if re.match(rf'from\s+my\.{mname}\s+import\s+export', line): + # todo 'export' is hardcoded, not sure how to infer allowed objects anutomatically.. + importing_submodule = True + + +warn = not (imported_as_parent or importing_submodule) + +# TODO: add link to instructions to migrate +if warn: + from my.core import warnings as W + W.high("DEPRECATED! Instead of my.fbmessengerexport, import from my.fbmessengerexport.export") + + +from .export import * diff --git a/my/fbmessenger.py b/my/fbmessenger/export.py similarity index 93% rename from my/fbmessenger.py rename to my/fbmessenger/export.py index 405605de..5a1801f5 100644 --- a/my/fbmessenger.py +++ b/my/fbmessenger/export.py @@ -10,11 +10,12 @@ from pathlib import Path from typing import Iterator -from .core import PathIsh +from ..core import PathIsh import fbmessengerexport.dal as messenger from my.config import fbmessenger as config +# TODO migrate this config to my.fbmessenger.export def _dal() -> messenger.DAL: @@ -28,7 +29,7 @@ def messages() -> Iterator[messenger.Message]: yield from t.iter_messages() -from .core import stat, Stats +from ..core import stat, Stats def stats() -> Stats: return stat(messages) diff --git a/tests/test_import_warnings.sh b/tests/test_import_warnings.sh new file mode 100644 index 00000000..dd677cbb --- /dev/null +++ b/tests/test_import_warnings.sh @@ -0,0 +1,62 @@ +#!/bin/bash +set -eu + +errors=0 +function expect_warn () { + echo "check: " "$@" + [[ $(2>&1 "$@" | grep -c DEPRECATED) -gt 0 ]] || { + echo "ERROR: " "$@" + errors=1 + } +} + +function expect_ok () { + echo "check: " "$@" + [[ $(2>&1 "$@" | grep -c DEPRECATED) -eq 0 ]] || { + echo "ERROR: " "$@" + errors=1 + } +} + + +# TODO actually this one might be ok? nothing wrong with it in principle +expect_warn python3 -c 'from my import fbmessenger' +echo 'from my import fbmessenger' > /tmp/script.py +expect_warn python3 /tmp/script.py + +expect_warn python3 -c 'from my.fbmessenger import messages' +echo 'from my.fbmessenger import messages' > /tmp/script.py +expect_warn python3 /tmp/script.py + +expect_warn python3 -c 'from my.fbmessenger import *' +echo 'from my.fbmessenger import *' > /tmp/script.py +expect_warn python3 /tmp/script.py + +expect_warn python3 -c 'import my.fbmessenger' +echo 'import my.fbmessenger' > /tmp/script.py +expect_warn python3 /tmp/script.py + +expect_warn python3 -m my.core query my.fbmessenger.messages +expect_warn python3 -m my.core doctor my.fbmessenger + + +expect_ok python3 -c 'from my.fbmessenger.export import *' +echo 'from my.fbmessenger.export import *' > /tmp/script.py +expect_ok python3 /tmp/script.py + + +# TODO kinda annoying: this doesn't work, and doesn't seem like traceback has anything +# guess it's fine, kind of a border case +# expect_ok python3 -c 'from my.fbmessenger import export' +echo 'from my.fbmessenger import export' > /tmp/script.py +expect_ok python3 /tmp/script.py + +expect_ok python3 -c 'import my.fbmessenger.export' +echo 'import my.fbmessenger.export' > /tmp/script.py +expect_ok python3 /tmp/script.py + +expect_ok python3 -m my.core query my.fbmessenger.export.messages +expect_ok python3 -m my.core doctor my.fbmessenger.export + + +exit $errors