Skip to content

Commit e0a7f4c

Browse files
committed
Refactoring of test (new base test and ocr tests was moved)
New Import Fix by using safe_imports
1 parent c9bfa39 commit e0a7f4c

16 files changed

+433
-326
lines changed

Makefile

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
SHELL:=/usr/bin/env bash
22

3-
.PHONY: lint
3+
.PHONY: lint unit package test jupyter
4+
45
lint:
56
flake8 piper
67

7-
.PHONY: unit
88
unit:
9-
pytest -vs tests/running_piper_test.py::TestCompose
9+
pytest -vs tests/envs_test.py::TestCompose
1010

11-
.PHONY: package
1211
package:
1312
pip check
1413

15-
.PHONY: test
1614
test: package unit
1715

1816
jupyter:

piper/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from piper.configurations import get_configuration
2+
from piper.imports import activate_safe_import
3+
4+
configuration = get_configuration()
5+
if configuration.ignore_import_errors:
6+
"""
7+
Piper activates safe import if configured True.
8+
This ignores any import errors for safe imports in piper.base.executors
9+
"""
10+
activate_safe_import()

piper/base/executors.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
# from piper.base.docker import PythonTesseractImage
2+
from piper.base.backend.utils import (render_fast_api_backend,
3+
render_fast_api_tsrct_backend)
4+
from piper.base.docker import PythonImage
5+
from piper.configurations import get_configuration
6+
from piper.envs import get_env, is_current_env, is_docker_env
7+
from piper.utils import docker_utils as du
8+
19
import inspect
210
import os
311
import sys
@@ -12,14 +20,6 @@
1220
from loguru import logger
1321
from pydantic import BaseModel # , BytesObject, ListOfStringsObject
1422

15-
# from piper.base.docker import PythonTesseractImage
16-
from piper.base.backend.utils import (render_fast_api_backend,
17-
render_fast_api_tsrct_backend)
18-
from piper.base.docker import PythonImage
19-
from piper.configurations import get_configuration
20-
from piper.envs import get_env, is_current_env, is_docker_env
21-
from piper.utils import docker_utils as du
22-
2323

2424
class BaseExecutor:
2525
pass
@@ -89,7 +89,7 @@ async def __call__(self, *args, **kwargs):
8989
def copy_piper(path: str):
9090
cfg = get_configuration()
9191
from distutils.dir_util import copy_tree
92-
copy_tree(cfg.piper_path, f"{path}/piper")
92+
copy_tree(cfg.piper_path, f"{path}piper")
9393

9494

9595
def copy_scripts(path: str, scripts: Dict[str, str]):

piper/configurations.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
class Configuration:
2-
# path = "/Users/olegsokolov/PycharmProjects/piper/applications"
3-
path = "./piper_new_out/"
4-
test_path = "./piper_test_out/"
5-
piper_path = "piper"
6-
default_env = "docker"
7-
docker_app_port = 8788
2+
path: str = "./piper_new_out/"
3+
test_path: str = "./piper_test_out/"
4+
piper_path: str = "../piper"
5+
default_env: str = "docker"
6+
docker_app_port: int = 8788
87

9-
name_venv = "venv_test"
10-
number = 10
8+
name_venv: str = "venv_test"
9+
number: int = 10
1110

12-
env = 'compose'
11+
env: str = 'compose'
12+
ignore_import_errors: bool = False
1313

1414
# start time and counter
1515
wait_on_iter = 0.5

piper/imports.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import builtins
2+
from types import ModuleType
3+
4+
from piper.utils.logger_utils import logger
5+
6+
7+
def _empty_import():
8+
logger.error("Import Not Installed Yet!")
9+
raise ImportError
10+
11+
12+
real_import = _empty_import
13+
14+
15+
class PiperDummyModule(ModuleType):
16+
17+
def __init__(self, name):
18+
super().__init__(name)
19+
logger.info(f"Piper emulates {name} module")
20+
21+
def __getattr__(self, name):
22+
return PiperDummyModule(name)
23+
24+
__all__ = []
25+
26+
27+
def try_import(name, globals={}, locals={}, fromlist=[], level=0):
28+
"""
29+
This import replace real Python import with fake import which returns warning only and PiperDummyModule.
30+
"""
31+
try:
32+
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
37+
38+
39+
"""
40+
Here Piper saves default Python *import* only.
41+
"""
42+
if builtins.__import__ != try_import:
43+
real_import = builtins.__import__
44+
45+
46+
def set_ignore_import_errors(ignore: bool = True):
47+
if ignore:
48+
builtins.__import__ = try_import
49+
else:
50+
builtins.__import__ = real_import
51+
52+
53+
def activate_safe_import():
54+
"""
55+
Activate piper safe import with try_import function.
56+
Piper needs safe import to ignore imports in Executors examples.
57+
For instance if you want to use Pandas in your CustomExecutor normally you have to *import pandas*
58+
But we don't want to install everything for every executor in default Python (where Piper is installed)
59+
For that you have to ignore every Executors dependencies.
60+
61+
Otherwise, you can wrap buy yourself every Executors import with try_import
62+
or you can use directly only *requirements* field in your CustomExecutor.
63+
64+
"""
65+
logger.info(f"Piper activates safe import")
66+
set_ignore_import_errors(ignore=True)
67+
68+
69+
def deactivate_safe_import():
70+
logger.info(f"Piper deactivates safe import")
71+
set_ignore_import_errors(ignore=False)
72+
73+
74+
class safe_import:
75+
"""
76+
Context manager to activate safe import on some part of imports.
77+
For instance:
78+
79+
with safe_import():
80+
import foo
81+
import bar
82+
83+
foo would be ignored and replaced by PiperDummyModule
84+
boo wouldn't be replaced (you can catch ImportError)
85+
"""
86+
87+
def __enter__(self):
88+
activate_safe_import()
89+
90+
def __exit__(self, type, value, traceback):
91+
deactivate_safe_import()

piper/services/__init__.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import json
21
import sys
32

4-
import spacy
5-
from fastapi.responses import JSONResponse
3+
from piper.imports import safe_import
4+
5+
with safe_import():
6+
import spacy
7+
from fastapi.responses import JSONResponse
8+
69
from loguru import logger
710
from pydantic import BaseModel
811

@@ -25,16 +28,6 @@ class ListOfStringsObject(BaseModel):
2528
value: list
2629

2730

28-
class TestMessageAdder(FastAPIExecutor):
29-
30-
def __init__(self, appender="TEST", **kwargs):
31-
self.appender = appender
32-
super().__init__(**kwargs)
33-
34-
async def run(self, message: StringValue) -> StringValue:
35-
return StringValue(value=(message.value + self.appender))
36-
37-
3831
class TesseractRecognizer(FastAPITesseractExecutor):
3932
'''
4033
Tesseract OCR implementation service

piper/utils/tesrct_utils.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
import cv2
2-
import numpy as np
3-
import pdf2image
4-
import pytesseract
1+
from piper.imports import safe_import
2+
with safe_import():
3+
import cv2
4+
import numpy as np
5+
import pdf2image
6+
import pytesseract
7+
58
import requests
69
from loguru import logger
710

tests/base_test.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# pytest -vs tests/base_test.py::TestPiperBase
2+
import asyncio
3+
import os
4+
import sys
5+
import time
6+
7+
root_dir = os.path.join(os.path.realpath(os.path.pardir), 'piper')
8+
sys.path.insert(1, root_dir)
9+
10+
11+
class TestPiperBase:
12+
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
18+
19+
class TestMessageAdder(FastAPIExecutor):
20+
21+
def __init__(self, appender="TEST", **kwargs):
22+
self.appender = appender
23+
super().__init__(**kwargs)
24+
25+
async def run(self, message: StringValue) -> StringValue:
26+
return StringValue(value=(message.value + self.appender))
27+
28+
cfg = get_configuration()
29+
loop = asyncio.get_event_loop()
30+
init_value = "TEST_container_"
31+
x = StringValue(value=init_value)
32+
need_result = f'{init_value}TEST'
33+
34+
with CurrentEnv() as env:
35+
adder = TestMessageAdder(appender="!", port=cfg.docker_app_port)
36+
result = loop.run_until_complete(adder(x))
37+
print(result)
38+
assert result.get('value') == need_result
39+
40+
with DockerEnv() as env:
41+
adder = TestMessageAdder(appender="!", port=cfg.docker_app_port)
42+
result = loop.run_until_complete(adder(x))
43+
print(result)
44+
adder.rm_container()
45+
assert result.get('value') == need_result
46+

tests/container_test.py

Lines changed: 0 additions & 28 deletions
This file was deleted.

tests/running_piper_test.py renamed to tests/envs_test.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
1-
# pytest -vs tests/running_piper_test.py::TestDocker
1+
# pytest -vs tests/envs_test.py::TestDocker
22
import time
3-
from pathlib import Path
4-
from shlex import split
5-
from subprocess import check_call
6-
from tempfile import TemporaryDirectory
7-
from venv import create
8-
93
import requests
104

115
from piper.envs import ComposeEnv, VirtualEnv

0 commit comments

Comments
 (0)