perf: improve cli startup time
- do not provide automatically imported api functions and objects in `imaginairy` root module - horrible hack to overcome horrible design choices by easy_install/setuptools The hack modifies the installed script to remove the __import__ pkg_resources line If we don't do this then the scripts will be slow to start up because of pkg_resources.require() which is called by setuptools to ensure the "correct" version of the package is installed. before modification example: ``` __requires__ = 'imaginAIry==14.0.0b5' __import__('pkg_resources').require('imaginAIry==14.0.0b5') __file__ = '/home/user/projects/imaginairy/imaginairy/bin/aimg' with open(__file__) as f: exec(compile(f.read(), __file__, 'exec')) ```pull/411/head^2
parent
2bd6cb264b
commit
9b95e8b0b6
@ -0,0 +1,79 @@
|
||||
"""
|
||||
horrible hack to overcome horrible design choices by easy_install/setuptools
|
||||
|
||||
If we don't do this then the scripts will be slow to start up because of
|
||||
pkg_resources.require() which is called by setuptools to ensure the
|
||||
"correct" version of the package is installed.
|
||||
"""
|
||||
import os
|
||||
|
||||
|
||||
def log(text):
|
||||
# for debugging
|
||||
pass
|
||||
# print(text)
|
||||
|
||||
|
||||
def find_script_path(script_name):
|
||||
for path in os.environ["PATH"].split(os.pathsep):
|
||||
script_path = os.path.join(path, script_name)
|
||||
if os.path.isfile(script_path):
|
||||
return script_path
|
||||
return None
|
||||
|
||||
|
||||
def is_already_modified():
|
||||
return bool(os.environ.get("IMAGINAIRY_SCRIPT_MODIFIED"))
|
||||
|
||||
|
||||
def remove_pkg_resources_requirement(script_path):
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
with open(script_path) as file:
|
||||
lines = file.readlines()
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_file:
|
||||
for line in lines:
|
||||
if "__import__('pkg_resources').require" not in line:
|
||||
temp_file.write(line)
|
||||
else:
|
||||
temp_file.write(
|
||||
'\nimport os\nos.environ["IMAGINAIRY_SCRIPT_MODIFIED"] = "1"\n'
|
||||
)
|
||||
log(f"Writing to {temp_file.name}")
|
||||
|
||||
# Preserve the original file permissions
|
||||
original_permissions = os.stat(script_path).st_mode
|
||||
os.chmod(temp_file.name, original_permissions)
|
||||
|
||||
# Replace the original file with the modified one
|
||||
shutil.move(temp_file.name, script_path)
|
||||
log(f"Replaced {script_path}")
|
||||
|
||||
|
||||
has_run = False
|
||||
|
||||
|
||||
def unslowify_scripts():
|
||||
global has_run
|
||||
|
||||
if has_run or is_already_modified():
|
||||
return
|
||||
|
||||
has_run = True
|
||||
script_names = ["aimg", "imagine"]
|
||||
|
||||
for script_name in script_names:
|
||||
script_path = find_script_path(script_name)
|
||||
log(f"Found script {script_name} at {script_path}")
|
||||
|
||||
if script_path:
|
||||
remove_pkg_resources_requirement(script_path)
|
||||
|
||||
|
||||
def unslowify_scripts_safe():
|
||||
try: # noqa
|
||||
unslowify_scripts()
|
||||
except Exception: # noqa
|
||||
pass
|
@ -1,3 +1,4 @@
|
||||
import os.path
|
||||
|
||||
TESTS_FOLDER = os.path.abspath(os.path.dirname(__file__))
|
||||
PROJECT_FOLDER = os.path.abspath(os.path.join(TESTS_FOLDER, ".."))
|
||||
|
@ -1,15 +1,37 @@
|
||||
import subprocess
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from click.testing import CliRunner
|
||||
|
||||
from imaginairy import ImaginePrompt, LazyLoadingImage, surprise_me
|
||||
from imaginairy import surprise_me
|
||||
from imaginairy.cli.edit import edit_cmd
|
||||
from imaginairy.cli.edit_demo import edit_demo_cmd
|
||||
from imaginairy.cli.imagine import imagine_cmd
|
||||
from imaginairy.cli.main import aimg
|
||||
from imaginairy.cli.upscale import upscale_cmd
|
||||
from imaginairy.schema import ImaginePrompt, LazyLoadingImage
|
||||
from imaginairy.utils.model_cache import GPUModelCache
|
||||
from tests import TESTS_FOLDER
|
||||
from tests import PROJECT_FOLDER, TESTS_FOLDER
|
||||
from tests.utils import Timer
|
||||
|
||||
|
||||
@pytest.mark.parametrize("subcommand_name", aimg.commands.keys())
|
||||
def test_cmd_help_time(subcommand_name):
|
||||
cmd_parts = [
|
||||
"python",
|
||||
"-X",
|
||||
"importtime",
|
||||
"imaginairy/cli/main.py",
|
||||
subcommand_name,
|
||||
"--help",
|
||||
]
|
||||
with Timer(f"{subcommand_name} --help") as t:
|
||||
result = subprocess.run(
|
||||
cmd_parts, check=False, capture_output=True, cwd=PROJECT_FOLDER
|
||||
)
|
||||
assert result.returncode == 0, result.stderr
|
||||
assert t.elapsed < 1.0, f"{t.elapsed} > 1.0"
|
||||
|
||||
|
||||
def test_imagine_cmd(monkeypatch):
|
Loading…
Reference in New Issue