Skip to content

Commit 1cab771

Browse files
committed
fix safe import and base executor test
1 parent 6e67cb6 commit 1cab771

File tree

10 files changed

+88
-50
lines changed

10 files changed

+88
-50
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ lint:
66
flake8 piper
77

88
unit:
9-
#pytest -vs tests/base_test.py
9+
pytest -vs tests/base_test.py
1010
pytest -vs tests/envs_test.py::TestCompose
1111
pytest -vs tests/envs_test.py::TestVenv
1212

piper/base/docker/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ def render(self):
2222
trim_blocks=True,
2323
lstrip_blocks=True)
2424
template = jinja_env.get_template(self.template_file)
25-
return template.render(cmd=self.cmd, python_docker_version=self.python_docker_version, run_command_lines=self.run_rows, post_install_lines=self.post_install_lines)
25+
return template.render(cmd=self.cmd,
26+
python_docker_version=self.python_docker_version,
27+
run_command_lines=self.run_rows,
28+
post_install_lines=self.post_install_lines)
2629

2730

2831
# class PythonTesseractImage:

piper/base/executors.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,22 @@
44
from piper.base.docker import PythonImage
55
from piper.configurations import get_configuration
66
from piper.envs import get_env, is_current_env, is_docker_env
7-
from piper.utils import docker_utils as du
7+
from piper.utils import docker_utils
88

99
import inspect
10-
import os
1110
import sys
1211
import time
1312
from abc import ABC, abstractmethod
14-
from distutils.command.config import config
1513
from typing import Dict
14+
from distutils.dir_util import copy_tree
1615

1716
import aiohttp
1817
import docker
1918
import requests
20-
from loguru import logger
2119
from pydantic import BaseModel # , BytesObject, ListOfStringsObject
2220

21+
from piper.utils.logger_utils import logger
22+
2323

2424
class BaseExecutor:
2525
pass
@@ -88,7 +88,6 @@ async def __call__(self, *args, **kwargs):
8888

8989
def copy_piper(path: str):
9090
cfg = get_configuration()
91-
from distutils.dir_util import copy_tree
9291
copy_tree(cfg.piper_path, f"{path}piper")
9392

9493

@@ -107,7 +106,8 @@ def write_requirements(path, requirements):
107106
def build_image(path: str, docker_image):
108107
client = docker.DockerClient(base_url='unix://var/run/docker.sock')
109108
image = docker_image.render()
110-
with open(f"{path}/Dockerfile", "w") as output:
109+
print(f"{path}Dockerfile")
110+
with open(f"{path}Dockerfile", "w") as output:
111111
output.write(image)
112112

113113
image, logs = client.images.build(path=path,
@@ -146,6 +146,7 @@ def wait_for_fast_api_app_start(host, external_port, wait_on_iter, n_iters):
146146
if r.status_code == 200:
147147
break
148148
except Exception as e:
149+
logger.error(f"Exception while starting FastAPI app {e}")
149150
time.sleep(wait_on_iter)
150151

151152
if i == n_iters:
@@ -170,12 +171,15 @@ def __init__(self, port: int = 8080, **service_kwargs):
170171

171172
copy_piper(project_output_path)
172173
copy_scripts(project_output_path, self.scripts())
173-
# build_image(project_output_path, docker_image)
174174
self.create_fast_api_files(project_output_path, **service_kwargs)
175175

176+
docker_image = PythonImage(self.image_tag, "3.9", cmd=f"./run.sh", template_file='default-python.j2',
177+
run_rows="", post_install_lines="")
178+
build_image(project_output_path, docker_image)
179+
176180
# create and run docker container
177181
# if container exits it will be recreated!
178-
du.create_image_and_container_by_dockerfile(
182+
docker_utils.create_image_and_container_by_dockerfile(
179183
docker_client,
180184
project_output_path,
181185
self.image_tag,
@@ -206,14 +210,13 @@ def create_fast_api_files(self, path: str, **service_kwargs):
206210
function_name=self.base_handler,
207211
request_model="StringValue",
208212
response_model="StringValue")
209-
210213
with open(f"{path}/main.py", "w") as output:
211214
output.write(backend)
212215

213216
write_requirements(path, self.requirements)
214217

215218
gunicorn = "#!/bin/bash \n" \
216-
f"gunicorn -b 0.0.0.0:8080 --workers {cfg.n_gunicorn_workers} main:app --worker-class uvicorn.workers.UvicornWorker --preload --timeout 120 --reload=True"
219+
f"gunicorn -b 0.0.0.0:8080 --workers {cfg.n_gunicorn_workers} main:app --worker-class uvicorn.workers.UvicornWorker --preload --timeout 120"
217220
with open(f"{path}/run.sh", "w") as output:
218221
output.write(gunicorn)
219222

@@ -257,7 +260,7 @@ def __init__(self, port: int = 8080, **service_kwargs):
257260

258261
# create and run docker container
259262
# if container exits it will be recreated!
260-
du.create_image_and_container_by_dockerfile(
263+
docker_utils.create_image_and_container_by_dockerfile(
261264
docker_client,
262265
project_output_path,
263266
self.image_tag,

piper/configurations.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import time
2+
3+
14
class Configuration:
2-
path: str = "./piper_new_out/"
3-
test_path: str = "./piper_test_out/"
5+
path: str = f"./applications/piper_project_{time.time_ns()}/"
6+
test_path: str = f"./applications/piper_project_{time.time_ns()}/"
47
piper_path: str = "piper"
58
default_env: str = "docker"
69
docker_app_port: int = 8788
@@ -9,7 +12,7 @@ class Configuration:
912
number: int = 10
1013

1114
env: str = 'compose'
12-
ignore_import_errors: bool = False
15+
ignore_import_errors: bool = True
1316

1417
# start time and counter
1518
wait_on_iter = 0.5

piper/imports.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import builtins
2+
import inspect
23
from types import ModuleType
34

45
from piper.utils.logger_utils import logger
6+
from piper.configurations import get_configuration
7+
8+
configuration = get_configuration()
59

610

711
def _empty_import():
@@ -27,13 +31,35 @@ def __getattr__(self, name):
2731
def try_import(name, globals={}, locals={}, fromlist=[], level=0):
2832
"""
2933
This import replace real Python import with fake import which returns warning only and PiperDummyModule.
34+
This works for everything under piper/ frameworks files by filename but not for piper import (like piper.base)
35+
And this also works for every file where you import something from piper firstly !
3036
"""
31-
try:
37+
is_piper_imported_from_previous_module = False
38+
prev_module_locals = inspect.currentframe().f_back.f_locals
39+
prev_module_globals = inspect.currentframe().f_back.f_globals
40+
prev_modules = prev_module_locals | prev_module_globals
41+
42+
if prev_modules.values():
43+
prev_modules = [v for v in prev_modules.values() if v is not None and hasattr(v, "__module__")]
44+
if len(prev_modules) > 0:
45+
is_piper_imported_from_previous_module = \
46+
any("piper" in v.__module__ for v in prev_modules if type(v.__module__) == str)
47+
48+
is_import_from_piper_source_code = "__file__" in globals and "piper/" in globals["__file__"]
49+
not_piper_import = not ("piper" in name)
50+
is_from_source_but_not_piper = is_import_from_piper_source_code and not_piper_import
51+
52+
if is_piper_imported_from_previous_module and is_from_source_but_not_piper:
53+
logger.info(f"Piper activates safe import for library {name} in piper file {globals['__file__']} ")
54+
try:
55+
return real_import(name, globals, locals, fromlist, level)
56+
except ImportError as e:
57+
logger.warning(f"Piper ignores ImportError and module {name} "
58+
f": replaced by dummy module. ImportError: {e.with_traceback(None)}")
59+
module = PiperDummyModule(name)
60+
return module
61+
else:
3262
return real_import(name, globals, locals, fromlist, level)
33-
except ImportError as e:
34-
logger.warning(f"Piper ignores ImportError and module {name} replaced by dummy module. ImportError: {e}")
35-
module = PiperDummyModule(name)
36-
return module
3763

3864

3965
"""

piper/services/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
import spacy
77
from fastapi.responses import JSONResponse
88

9-
from loguru import logger
9+
# from loguru import logger
10+
from piper.utils.logger_utils import logger
1011
from pydantic import BaseModel
1112

1213
from piper.base.executors import FastAPIExecutor, FastAPITesseractExecutor
1314
from piper.configurations import get_configuration
1415
from piper.utils import tesrct_utils as tu
1516

16-
logger.add("file.log", level="INFO", backtrace=True, diagnose=True, rotation='5 MB')
17+
# logger.add("file.log", level="INFO", backtrace=True, diagnose=True, rotation='5 MB')
1718

1819

1920
class StringValue(BaseModel):

piper/utils/docker_utils.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
from piper.configurations import get_configuration
2+
13
import sys
24
import time
35

46
import docker
5-
from configurations import get_configuration
6-
from loguru import logger
7+
# from loguru import logger
8+
from piper.utils.logger_utils import logger
79

810
cfg = get_configuration()
911

@@ -127,7 +129,7 @@ def image_find_and_rm(docker_client, image_tag):
127129
return True
128130

129131

130-
def create_image_and_container_by_dockerfile(docker_client, path, image_tag, container_name, port):
132+
def create_image_and_container_by_dockerfile(docker_client: docker.DockerClient, path, image_tag, container_name, port):
131133
# should be deleted
132134
status = stop_and_rm_container(docker_client, container_name)
133135

@@ -156,7 +158,10 @@ def create_image_and_container_by_dockerfile(docker_client, path, image_tag, con
156158

157159
# run container
158160
try:
159-
container = docker_client.containers.run(image_tag, name=container_name, detach=True, ports={8080:port})
161+
container = docker_client.containers.run(image_tag,
162+
name=container_name,
163+
detach=True,
164+
ports={8080: port})
160165
for log in container.logs():
161166
logger.debug(log)
162167
logger.info(f'container {container} created')

piper/utils/logger_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
handler.setFormatter(formatter)
1111
logger.addHandler(handler)
1212

13-
fh = logging.FileHandler('../piper_base_log.log')
13+
fh = logging.FileHandler('./piper_base_log.log')
1414
fh.setLevel(logging.DEBUG)
1515
fh.setFormatter(formatter)
1616
logger.addHandler(fh)

piper/utils/tesrct_utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import pytesseract
77

88
import requests
9-
from loguru import logger
9+
# from loguru import logger
10+
from piper.utils.logger_utils import logger
1011

1112
from piper.configurations import get_configuration
1213

tests/base_test.py

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,25 @@
11
# pytest -vs tests/base_test.py::TestPiperBase
22
import asyncio
3-
import os
4-
import sys
5-
import time
63

7-
root_dir = os.path.join(os.path.realpath(os.path.pardir), 'piper')
8-
sys.path.insert(1, root_dir)
4+
from piper.base.executors import FastAPIExecutor
5+
from piper.services import StringValue
6+
from piper.configurations import get_configuration
7+
from piper.envs import CurrentEnv, DockerEnv, ComposeEnv
98

109

11-
class TestPiperBase:
10+
class TestMessageAdder(FastAPIExecutor):
1211

13-
def test_simple_executor(self):
14-
from piper.base.executors import FastAPIExecutor
15-
from piper.services import StringValue
16-
from piper.configurations import get_configuration
17-
from piper.envs import CurrentEnv, DockerEnv
12+
def __init__(self, appender="TEST", **kwargs):
13+
self.appender = appender
14+
super().__init__(**kwargs)
1815

19-
class TestMessageAdder(FastAPIExecutor):
16+
async def run(self, message: StringValue) -> StringValue:
17+
return StringValue(value=(message.value + self.appender))
2018

21-
def __init__(self, appender="TEST", **kwargs):
22-
self.appender = appender
23-
super().__init__(**kwargs)
2419

25-
async def run(self, message: StringValue) -> StringValue:
26-
return StringValue(value=(message.value + self.appender))
20+
class TestPiperBase:
21+
22+
def test_simple_executor(self):
2723

2824
cfg = get_configuration()
2925
loop = asyncio.get_event_loop()
@@ -32,15 +28,15 @@ async def run(self, message: StringValue) -> StringValue:
3228
need_result = f'{init_value}TEST'
3329

3430
with CurrentEnv() as env:
35-
adder = TestMessageAdder(appender="!", port=cfg.docker_app_port)
31+
adder = TestMessageAdder(port=cfg.docker_app_port)
3632
result = loop.run_until_complete(adder(x))
3733
print(result)
38-
assert result.get('value') == need_result
34+
assert result.value == need_result
3935

4036
with DockerEnv() as env:
41-
adder = TestMessageAdder(appender="!", port=cfg.docker_app_port)
37+
adder = TestMessageAdder(port=cfg.docker_app_port)
4238
result = loop.run_until_complete(adder(x))
4339
print(result)
4440
adder.rm_container()
45-
assert result.get('value') == need_result
41+
assert result.get("value") == need_result
4642

0 commit comments

Comments
 (0)