From 08e2ad99043fa67ee7dc1a13bde3d915e0ac290f Mon Sep 17 00:00:00 2001 From: Leela vadlamudi Date: Tue, 9 Mar 2021 11:59:17 +0530 Subject: [PATCH] feat: Lazy import functionality added (#12517) --- frappe/__init__.py | 15 +++++++++------ frappe/utils/lazy_loader.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 frappe/utils/lazy_loader.py diff --git a/frappe/__init__.py b/frappe/__init__.py index 160ed93c50..ab27bff9fe 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -18,9 +18,14 @@ import os, sys, importlib, inspect, json from past.builtins import cmp import click -# public +# Local application imports from .exceptions import * from .utils.jinja import (get_jenv, get_template, render_template, get_email_from_template, get_jloader) +from .utils.lazy_loader import lazy_import + +# Lazy imports +faker = lazy_import('faker') + # Harmless for Python 3 # For Python 2 set default encoding to utf-8 @@ -1749,15 +1754,13 @@ def parse_json(val): return parse_json(val) def mock(type, size=1, locale='en'): - from faker import Faker - results = [] - faker = Faker(locale) - if not type in dir(faker): + fake = faker.Faker(locale) + if type not in dir(fake): raise ValueError('Not a valid mock type.') else: for i in range(size): - data = getattr(faker, type)() + data = getattr(fake, type)() results.append(data) from frappe.chat.util import squashify diff --git a/frappe/utils/lazy_loader.py b/frappe/utils/lazy_loader.py new file mode 100644 index 0000000000..ae4cba66a1 --- /dev/null +++ b/frappe/utils/lazy_loader.py @@ -0,0 +1,34 @@ +import importlib.util +import sys + +def lazy_import(name, package=None): + """Import a module lazily. + + The module is loaded when modules's attribute is accessed for the first time. + This works with both absolute and relative imports. + $ cat mod.py + print("Loading mod.py") + $ python -i lazy_loader.py + >>> mod = lazy_import("mod") # Module is not loaded + >>> mod.__str__() # module is loaded on accessing attribute + Loading mod.py + "" + >>> + + Code based on https://github.com/python/cpython/blob/master/Doc/library/importlib.rst#implementing-lazy-imports. + """ + # Return if the module already loaded + if name in sys.modules: + return sys.modules[name] + + # Find the spec if not loaded + spec = importlib.util.find_spec(name, package) + if not spec: + raise ImportError(f'Module {name} Not found.') + + loader = importlib.util.LazyLoader(spec.loader) + spec.loader = loader + module = importlib.util.module_from_spec(spec) + sys.modules[name] = module + loader.exec_module(module) + return module