Path:
strictdoc/cli/main.py
Lines:
125
Non-empty lines:
104
Non-empty lines covered with requirements:
104 / 104 (100.0%)
Functions:
3
Functions covered by requirements:
3 / 3 (100.0%)
1
# Needed to ensure that multiprocessing.freeze_support() is called2
# in a frozen application (see main() below).3
import multiprocessing
4
import sys
5
from typing import Any, Dict, Optional
6
7
from strictdoc import environment
8
from strictdoc.cli.cli_arg_parser import (
9
SDocArgsParser,
10
)11
from strictdoc.commands.about_command import AboutCommand
12
from strictdoc.commands.export import ExportCommand
13
from strictdoc.commands.import_excel import ImportExcelCommand
14
from strictdoc.commands.import_reqif import ImportReqIFCommand
15
from strictdoc.commands.launcher_command import (
16
LauncherCommand,
17
is_launcher_available,
18
)19
from strictdoc.commands.manage_autouid_command import ManageAutoUIDCommand
20
from strictdoc.commands.new_command import NewCommand
21
from strictdoc.commands.server import ServerCommand
22
from strictdoc.commands.version_command import VersionCommand
23
from strictdoc.helpers.coverage import register_code_coverage_hook
24
from strictdoc.helpers.exception import (
25
ExceptionInfo,
26
StrictDocChildProcessException,
27
)28
from strictdoc.helpers.parallelizer import Parallelizer
29
from strictdoc.helpers.timing import SimpleNominalExit, measure_performance
30
31
32
def create_command_registry() -> Dict[str, Any]:
33
command_registry: Dict[str, Any] = {
34
"about": AboutCommand,
35
"export": ExportCommand,
36
"import": {"excel": ImportExcelCommand, "reqif": ImportReqIFCommand},
37
"manage": {"auto-uid": ManageAutoUIDCommand},
38
"new": NewCommand,
39
"server": ServerCommand,
40
"version": VersionCommand,
41
}42
43
if is_launcher_available():
44
command_registry["launcher"] = LauncherCommand
45
46
return command_registry
47
48
49
COMMAND_REGISTRY: Dict[str, Any] = create_command_registry()
50
51
52
def _main() -> None:
53
# The parser can raise when no arguments or incorrect arguments are provided.54
try:
55
parser = SDocArgsParser.create_sdoc_args_parser(COMMAND_REGISTRY)
56
except Exception as exception_:
57
print(f"error: {str(exception_)}", flush=True) # noqa: T201
58
sys.exit(1)
59
60
if parser.is_debug_mode():
61
environment.is_debug_mode = True
62
63
# Ensure that multiprocessing.freeze_support() is called in a frozen64
# application65
# https://github.com/pyinstaller/pyinstaller/issues/743866
if getattr(sys, "frozen", False): # pragma: no cover
67
multiprocessing.freeze_support()
68
69
# This is crucial for a good performance on macOS. Linux uses 'fork' by default.70
# Changed in version 3.8: On macOS, the spawn start method is now the default.71
# The fork start method should be considered unsafe as it can lead to crashes72
# of the subprocess as macOS system libraries may start threads. See bpo-33725.73
# https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods74
# 2024-12-26: StrictDoc has been working with 'fork' just fine, so keep doing it until75
# anything serious appears against using it.76
if sys.platform != "win32":
77
multiprocessing.set_start_method("fork", force=True)
78
else: # pragma: no cover
79
pass # pragma: no cover
80
81
# How to make python 3 print() utf882
# https://stackoverflow.com/a/3597849/59805783
# sys.stdout.reconfigure(encoding='utf-8') for Python 3.784
sys.stdout = open( # pylint: disable=bad-option-value,consider-using-with
85
1, "w", encoding="utf-8", closefd=False
86
)87
88
register_code_coverage_hook()
89
90
enable_parallelization = "--no-parallelization" not in sys.argv
91
parallelizer = Parallelizer.create(enable_parallelization)
92
93
exception_info: Optional[ExceptionInfo] = None
94
try:
95
parser.run(parallelizer)
96
except SimpleNominalExit:
97
raise98
except StrictDocChildProcessException as exception_info_:
99
exception_info = exception_info_.exception_info
100
except Exception as exception_:
101
exception_info = ExceptionInfo(exception_)
102
finally:
103
parallelizer.shutdown()
104
105
if exception_info is not None:
106
if parser.is_debug_mode():
107
print(exception_info.get_stack_trace(), flush=True) # noqa: T201
108
print(exception_info.get_detailed_error_message(), flush=True) # noqa: T201
109
if not parser.is_debug_mode():
110
print( # noqa: T201
111
"Rerun with strictdoc --debug <...> to enable stack trace printing.",
112
flush=True,
113
)114
sys.exit(1)
115
116
117
def main() -> None:
118
with measure_performance("Total execution time"):
119
_main()
120
121
122
if __name__ == "__main__":
123
main()
124
else: # pragma: no cover
125
pass