From d4a26c31722330048262e78d9a61b8c00bd2cd91 Mon Sep 17 00:00:00 2001 From: omesser Date: Thu, 13 Jul 2023 23:05:19 +0300 Subject: [PATCH 1/8] Use importlib package to dist resolution --- mlem/utils/module.py | 28 ++++++++++++++++++---------- setup.py | 5 ++++- tests/utils/test_module_tools.py | 11 +++++++---- tests/utils/test_save.ipynb | 32 +++++++++++++++++--------------- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/mlem/utils/module.py b/mlem/utils/module.py index 4099cf7d..910c8272 100644 --- a/mlem/utils/module.py +++ b/mlem/utils/module.py @@ -8,6 +8,7 @@ import sys import threading import warnings +import importlib.metadata from collections import defaultdict from functools import lru_cache, wraps from pickle import PickleError @@ -249,15 +250,22 @@ def get_module_version(mod: ModuleType) -> Optional[str]: :param mod: module object to use :return: version as `str` or `None` if version could not be determined """ - for attr in "__version__", "VERSION": - if hasattr(mod, attr): - return str(getattr(mod, attr)) - if mod.__file__ is None: - return None - for name in os.listdir(os.path.dirname(mod.__file__)): - m = re.match(re.escape(mod.__name__) + "-(.+)\\.dist-info", name) - if m: - return m.group(1) + # try using importlib package -> distro mapping and distro metadata + package_to_distros = packages_distributions() + try: + if mod.__name__ in package_to_distros: + for distro_name in package_to_distros[mod.__name__]: + distro = importlib.metadata.distribution(distro_name) + return distro.version + except importlib.metadata.PackageNotFoundError: + pass + + # if there's a package-file, try to get it from there + if mod.__file__ is not None: + for name in os.listdir(os.path.dirname(mod.__file__)): + m = re.match(re.escape(mod.__name__) + "-(.+)\\.dist-info", name) + if m: + return m.group(1) return None @@ -502,7 +510,7 @@ def save_type_with_classvars(pickler: "RequirementAnalyzer", obj): class RequirementAnalyzer(dill.Pickler): """Special pickler implementation that collects requirements while pickling - (and not pickling actualy)""" + (and not actually pickling)""" ignoring = ( "dill", diff --git a/setup.py b/setup.py index 526b3356..e1e3a584 100644 --- a/setup.py +++ b/setup.py @@ -57,6 +57,9 @@ "jupyter", "nbconvert", "nbloader", + # We're using regex to test requirement version extraction + # edge case, see: https://github.com/iterative/mlem/issues/688 + 'regex==2023.6.3', ] extras = { @@ -75,7 +78,7 @@ "lightgbm": ["lightgbm"], "fastapi": ["uvicorn", "fastapi"], "prometheus": ["prometheus-fastapi-instrumentator"], - "streamlit": ["uvicorn", "fastapi", "streamlit", "streamlit_pydantic"], + "streamlit": ["uvicorn", "fastapi", "streamlit>=1.14.0", "streamlit_pydantic"], "sagemaker": ["docker", "boto3", "sagemaker"], "torch": ["torch"], "tensorflow": ["tensorflow"], diff --git a/tests/utils/test_module_tools.py b/tests/utils/test_module_tools.py index f971f493..b4f0b4d7 100644 --- a/tests/utils/test_module_tools.py +++ b/tests/utils/test_module_tools.py @@ -1,6 +1,7 @@ import os import subprocess from typing import ClassVar +import regex import nbformat import numpy @@ -220,11 +221,11 @@ def test_get_requirements_notebook(): loaded_notebook = Notebook(TEST_NOTEBOOK_NAME) - kek = loaded_notebook.run_all() - res = kek.ns["res"] + notebook = loaded_notebook.run_all() + res = notebook.ns["res"] assert isinstance(res, Requirements) - assert res.modules == ["numpy"] + assert sorted(res.modules) == sorted(["regex", "numpy"]) def _run_jup(command): @@ -249,7 +250,9 @@ def test_get_requirements_notebook_run(): with open(TEST_NOTEBOOK_NAME, encoding="utf8") as f: nb = nbformat.read(f, as_version=4) - assert nb["cells"][1]["outputs"][0].text.strip() == get_module_repr(numpy) + res = nb["cells"][1]["outputs"][0].text.strip() + assert get_module_repr(numpy) in res + assert get_module_repr(regex) in res # Copyright 2019 Zyfra diff --git a/tests/utils/test_save.ipynb b/tests/utils/test_save.ipynb index 68ccf781..b6c97dc8 100644 --- a/tests/utils/test_save.ipynb +++ b/tests/utils/test_save.ipynb @@ -5,10 +5,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2023-02-13T14:11:29.261665Z", - "iopub.status.busy": "2023-02-13T14:11:29.261394Z", - "iopub.status.idle": "2023-02-13T14:11:29.267566Z", - "shell.execute_reply": "2023-02-13T14:11:29.266734Z" + "iopub.execute_input": "2023-07-13T20:04:23.425791Z", + "iopub.status.busy": "2023-07-13T20:04:23.425682Z", + "iopub.status.idle": "2023-07-13T20:04:23.436620Z", + "shell.execute_reply": "2023-07-13T20:04:23.436325Z" }, "pycharm": { "name": "#%%\n" @@ -17,8 +17,10 @@ "outputs": [], "source": [ "import numpy as np\n", + "import regex\n", "\n", - "def func(data):\n", + "def use_modules():\n", + " regex.split(' ', 'brown fox')\n", " return bool(np.all([True]))\n" ] }, @@ -27,13 +29,12 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2023-02-13T14:11:29.270506Z", - "iopub.status.busy": "2023-02-13T14:11:29.270233Z", - "iopub.status.idle": "2023-02-13T14:11:29.969468Z", - "shell.execute_reply": "2023-02-13T14:11:29.968705Z" + "iopub.execute_input": "2023-07-13T20:04:23.438339Z", + "iopub.status.busy": "2023-07-13T20:04:23.438249Z", + "iopub.status.idle": "2023-07-13T20:04:24.532574Z", + "shell.execute_reply": "2023-07-13T20:04:24.532277Z" }, "pycharm": { - "is_executing": true, "name": "#%%\n" } }, @@ -42,16 +43,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "numpy==1.22.4\n" + "regex==2023.6.3\n", + "numpy==1.25.1\n" ] } ], "source": [ "from mlem.utils.module import get_object_requirements\n", "\n", - "res = get_object_requirements(func)\n", + "res = get_object_requirements(use_modules)\n", "\n", - "print(\" \".join(res.to_pip()))" + "print(\"\\n\".join(res.to_pip()))" ] } ], @@ -71,9 +73,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.13" + "version": "3.10.9" } }, "nbformat": 4, "nbformat_minor": 0 -} +} \ No newline at end of file From 2572a1517eea60cbd3e3c1c2a58010d70d7a2e9c Mon Sep 17 00:00:00 2001 From: omesser Date: Thu, 13 Jul 2023 23:11:07 +0300 Subject: [PATCH 2/8] Slightly less verbose --- mlem/utils/module.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mlem/utils/module.py b/mlem/utils/module.py index 910c8272..e009b813 100644 --- a/mlem/utils/module.py +++ b/mlem/utils/module.py @@ -8,7 +8,7 @@ import sys import threading import warnings -import importlib.metadata +from importlib.metadata import distribution, PackageNotFoundError from collections import defaultdict from functools import lru_cache, wraps from pickle import PickleError @@ -255,9 +255,9 @@ def get_module_version(mod: ModuleType) -> Optional[str]: try: if mod.__name__ in package_to_distros: for distro_name in package_to_distros[mod.__name__]: - distro = importlib.metadata.distribution(distro_name) + distro = distribution(distro_name) return distro.version - except importlib.metadata.PackageNotFoundError: + except PackageNotFoundError: pass # if there's a package-file, try to get it from there From 08b8152ef61167149b79a00474489774a11695d0 Mon Sep 17 00:00:00 2001 From: omesser Date: Thu, 13 Jul 2023 23:19:54 +0300 Subject: [PATCH 3/8] fixes, linting and such --- mlem/utils/module.py | 2 +- setup.py | 4 ++-- tests/utils/test_module_tools.py | 2 +- tests/utils/test_save.ipynb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mlem/utils/module.py b/mlem/utils/module.py index e009b813..a6163c55 100644 --- a/mlem/utils/module.py +++ b/mlem/utils/module.py @@ -8,9 +8,9 @@ import sys import threading import warnings -from importlib.metadata import distribution, PackageNotFoundError from collections import defaultdict from functools import lru_cache, wraps +from importlib.metadata import PackageNotFoundError, distribution from pickle import PickleError from types import FunctionType, LambdaType, MethodType, ModuleType from typing import Dict, List, Optional, Set, Union diff --git a/setup.py b/setup.py index e1e3a584..d999d91a 100644 --- a/setup.py +++ b/setup.py @@ -59,7 +59,7 @@ "nbloader", # We're using regex to test requirement version extraction # edge case, see: https://github.com/iterative/mlem/issues/688 - 'regex==2023.6.3', + "regex==2023.6.3", ] extras = { @@ -78,7 +78,7 @@ "lightgbm": ["lightgbm"], "fastapi": ["uvicorn", "fastapi"], "prometheus": ["prometheus-fastapi-instrumentator"], - "streamlit": ["uvicorn", "fastapi", "streamlit>=1.14.0", "streamlit_pydantic"], + "streamlit": ["uvicorn", "fastapi", "streamlit", "streamlit_pydantic"], "sagemaker": ["docker", "boto3", "sagemaker"], "torch": ["torch"], "tensorflow": ["tensorflow"], diff --git a/tests/utils/test_module_tools.py b/tests/utils/test_module_tools.py index b4f0b4d7..02253434 100644 --- a/tests/utils/test_module_tools.py +++ b/tests/utils/test_module_tools.py @@ -1,11 +1,11 @@ import os import subprocess from typing import ClassVar -import regex import nbformat import numpy import pytest +import regex from pydantic import BaseModel from mlem.core.requirements import Requirements diff --git a/tests/utils/test_save.ipynb b/tests/utils/test_save.ipynb index b6c97dc8..2ef30103 100644 --- a/tests/utils/test_save.ipynb +++ b/tests/utils/test_save.ipynb @@ -78,4 +78,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} From 41f36fc7823ab538f1662b5e5d882e215c71a00b Mon Sep 17 00:00:00 2001 From: omesser Date: Thu, 13 Jul 2023 23:40:36 +0300 Subject: [PATCH 4/8] Take free-space.sh from nuclio --- tests/utils/test_save.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/utils/test_save.ipynb b/tests/utils/test_save.ipynb index 2ef30103..b6c97dc8 100644 --- a/tests/utils/test_save.ipynb +++ b/tests/utils/test_save.ipynb @@ -78,4 +78,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} +} \ No newline at end of file From 0266c814e92d95392028e43e0cd0ab352a0b01db Mon Sep 17 00:00:00 2001 From: omesser Date: Thu, 13 Jul 2023 23:44:10 +0300 Subject: [PATCH 5/8] Fixing ipynb lint again. shakes-fist-at-pycharm --- tests/utils/test_save.ipynb | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/tests/utils/test_save.ipynb b/tests/utils/test_save.ipynb index b6c97dc8..68ccf781 100644 --- a/tests/utils/test_save.ipynb +++ b/tests/utils/test_save.ipynb @@ -5,10 +5,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2023-07-13T20:04:23.425791Z", - "iopub.status.busy": "2023-07-13T20:04:23.425682Z", - "iopub.status.idle": "2023-07-13T20:04:23.436620Z", - "shell.execute_reply": "2023-07-13T20:04:23.436325Z" + "iopub.execute_input": "2023-02-13T14:11:29.261665Z", + "iopub.status.busy": "2023-02-13T14:11:29.261394Z", + "iopub.status.idle": "2023-02-13T14:11:29.267566Z", + "shell.execute_reply": "2023-02-13T14:11:29.266734Z" }, "pycharm": { "name": "#%%\n" @@ -17,10 +17,8 @@ "outputs": [], "source": [ "import numpy as np\n", - "import regex\n", "\n", - "def use_modules():\n", - " regex.split(' ', 'brown fox')\n", + "def func(data):\n", " return bool(np.all([True]))\n" ] }, @@ -29,12 +27,13 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2023-07-13T20:04:23.438339Z", - "iopub.status.busy": "2023-07-13T20:04:23.438249Z", - "iopub.status.idle": "2023-07-13T20:04:24.532574Z", - "shell.execute_reply": "2023-07-13T20:04:24.532277Z" + "iopub.execute_input": "2023-02-13T14:11:29.270506Z", + "iopub.status.busy": "2023-02-13T14:11:29.270233Z", + "iopub.status.idle": "2023-02-13T14:11:29.969468Z", + "shell.execute_reply": "2023-02-13T14:11:29.968705Z" }, "pycharm": { + "is_executing": true, "name": "#%%\n" } }, @@ -43,17 +42,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "regex==2023.6.3\n", - "numpy==1.25.1\n" + "numpy==1.22.4\n" ] } ], "source": [ "from mlem.utils.module import get_object_requirements\n", "\n", - "res = get_object_requirements(use_modules)\n", + "res = get_object_requirements(func)\n", "\n", - "print(\"\\n\".join(res.to_pip()))" + "print(\" \".join(res.to_pip()))" ] } ], @@ -73,9 +71,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.9" + "version": "3.9.13" } }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} From ea167b55e8bdc76b52dc6fe93a6b95c511108e37 Mon Sep 17 00:00:00 2001 From: omesser Date: Mon, 31 Jul 2023 12:49:19 +0300 Subject: [PATCH 6/8] typo fix --- mlem/core/hooks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlem/core/hooks.py b/mlem/core/hooks.py index 769cbcf8..c43af595 100644 --- a/mlem/core/hooks.py +++ b/mlem/core/hooks.py @@ -67,7 +67,7 @@ def __init_subclass__(cls, *args, **kwargs): ) else: logger.debug( - "Not registerting %s to any Analyzer because it's an abstract class", + "Not registering %s to any Analyzer because it's an abstract class", cls.__name__, ) super(Hook, cls).__init_subclass__(*args, **kwargs) From 2059f214dfebe8a373d9a8c0eb925df6b45af87b Mon Sep 17 00:00:00 2001 From: omesser Date: Mon, 31 Jul 2023 13:04:25 +0300 Subject: [PATCH 7/8] fixing test_save.ipynb --- tests/utils/test_save.ipynb | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/tests/utils/test_save.ipynb b/tests/utils/test_save.ipynb index 68ccf781..275713f5 100644 --- a/tests/utils/test_save.ipynb +++ b/tests/utils/test_save.ipynb @@ -5,10 +5,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2023-02-13T14:11:29.261665Z", - "iopub.status.busy": "2023-02-13T14:11:29.261394Z", - "iopub.status.idle": "2023-02-13T14:11:29.267566Z", - "shell.execute_reply": "2023-02-13T14:11:29.266734Z" + "iopub.execute_input": "2023-07-31T10:02:34.099802Z", + "iopub.status.busy": "2023-07-31T10:02:34.099406Z", + "iopub.status.idle": "2023-07-31T10:02:34.115259Z", + "shell.execute_reply": "2023-07-31T10:02:34.114688Z" }, "pycharm": { "name": "#%%\n" @@ -17,8 +17,11 @@ "outputs": [], "source": [ "import numpy as np\n", + "import regex\n", "\n", "def func(data):\n", + " # using regex, just so it's listed and its version inferred correctly\n", + " regex.search(r'(ab)', 'abcdef')\n", " return bool(np.all([True]))\n" ] }, @@ -27,10 +30,10 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2023-02-13T14:11:29.270506Z", - "iopub.status.busy": "2023-02-13T14:11:29.270233Z", - "iopub.status.idle": "2023-02-13T14:11:29.969468Z", - "shell.execute_reply": "2023-02-13T14:11:29.968705Z" + "iopub.execute_input": "2023-07-31T10:02:34.118394Z", + "iopub.status.busy": "2023-07-31T10:02:34.118192Z", + "iopub.status.idle": "2023-07-31T10:02:35.897692Z", + "shell.execute_reply": "2023-07-31T10:02:35.897269Z" }, "pycharm": { "is_executing": true, @@ -42,7 +45,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "numpy==1.22.4\n" + "numpy==1.25.1 regex==2023.6.3\n" ] } ], @@ -71,7 +74,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.13" + "version": "3.10.9" } }, "nbformat": 4, From 02232ca10e06d81cb070acf24a57bf6c1cfc7aa4 Mon Sep 17 00:00:00 2001 From: omesser Date: Wed, 23 Aug 2023 16:21:26 +0300 Subject: [PATCH 8/8] Adding pragma no branch --- mlem/utils/module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlem/utils/module.py b/mlem/utils/module.py index a6163c55..260c8231 100644 --- a/mlem/utils/module.py +++ b/mlem/utils/module.py @@ -261,7 +261,7 @@ def get_module_version(mod: ModuleType) -> Optional[str]: pass # if there's a package-file, try to get it from there - if mod.__file__ is not None: + if mod.__file__ is not None: # pragma: no branch for name in os.listdir(os.path.dirname(mod.__file__)): m = re.match(re.escape(mod.__name__) + "-(.+)\\.dist-info", name) if m: