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