pyxecm 2.0.3__py3-none-any.whl → 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyxecm might be problematic. Click here for more details.
- pyxecm/coreshare.py +76 -8
- pyxecm/helper/data.py +16 -24
- pyxecm/helper/otel_config.py +26 -0
- pyxecm/helper/web.py +1 -2
- pyxecm/otca.py +1356 -16
- pyxecm/otcs.py +4238 -758
- pyxecm/otds.py +4 -12
- pyxecm/otmm.py +4 -5
- pyxecm/py.typed +0 -0
- pyxecm-3.0.0.dist-info/METADATA +48 -0
- pyxecm-3.0.0.dist-info/RECORD +96 -0
- {pyxecm-2.0.3.dist-info → pyxecm-3.0.0.dist-info}/WHEEL +1 -2
- pyxecm-3.0.0.dist-info/entry_points.txt +4 -0
- {pyxecm/customizer/api → pyxecm_api}/__main__.py +1 -1
- pyxecm_api/agents/__init__.py +7 -0
- pyxecm_api/agents/app.py +13 -0
- pyxecm_api/agents/functions.py +119 -0
- pyxecm_api/agents/models.py +10 -0
- pyxecm_api/agents/otcm_knowledgegraph/functions.py +85 -0
- pyxecm_api/agents/otcm_knowledgegraph/models.py +61 -0
- pyxecm_api/agents/otcm_knowledgegraph/router.py +74 -0
- pyxecm_api/agents/otcm_user_agent/models.py +20 -0
- pyxecm_api/agents/otcm_user_agent/router.py +65 -0
- pyxecm_api/agents/otcm_workspace_agent/models.py +40 -0
- pyxecm_api/agents/otcm_workspace_agent/router.py +200 -0
- pyxecm_api/app.py +221 -0
- {pyxecm/customizer/api → pyxecm_api}/auth/functions.py +10 -2
- {pyxecm/customizer/api → pyxecm_api}/auth/router.py +4 -3
- {pyxecm/customizer/api → pyxecm_api}/common/functions.py +39 -9
- {pyxecm/customizer/api → pyxecm_api}/common/metrics.py +1 -2
- {pyxecm/customizer/api → pyxecm_api}/common/router.py +12 -11
- {pyxecm/customizer/api → pyxecm_api}/settings.py +30 -6
- {pyxecm/customizer/api → pyxecm_api}/terminal/router.py +1 -1
- {pyxecm/customizer/api → pyxecm_api}/v1_csai/router.py +39 -10
- pyxecm_api/v1_csai/statics/bindings/utils.js +189 -0
- pyxecm_api/v1_csai/statics/tom-select/tom-select.complete.min.js +356 -0
- pyxecm_api/v1_csai/statics/tom-select/tom-select.css +334 -0
- pyxecm_api/v1_csai/statics/vis-9.1.2/vis-network.css +1 -0
- pyxecm_api/v1_csai/statics/vis-9.1.2/vis-network.min.js +27 -0
- pyxecm_api/v1_maintenance/__init__.py +1 -0
- {pyxecm/customizer/api → pyxecm_api}/v1_maintenance/functions.py +3 -3
- {pyxecm/customizer/api → pyxecm_api}/v1_maintenance/router.py +8 -8
- pyxecm_api/v1_otcs/__init__.py +1 -0
- {pyxecm/customizer/api → pyxecm_api}/v1_otcs/functions.py +7 -5
- {pyxecm/customizer/api → pyxecm_api}/v1_otcs/router.py +24 -13
- pyxecm_api/v1_payload/__init__.py +1 -0
- {pyxecm/customizer/api → pyxecm_api}/v1_payload/functions.py +10 -7
- {pyxecm/customizer/api → pyxecm_api}/v1_payload/router.py +11 -10
- {pyxecm/customizer → pyxecm_customizer}/__init__.py +8 -0
- {pyxecm/customizer → pyxecm_customizer}/__main__.py +15 -21
- {pyxecm/customizer → pyxecm_customizer}/browser_automation.py +414 -103
- {pyxecm/customizer → pyxecm_customizer}/customizer.py +178 -116
- {pyxecm/customizer → pyxecm_customizer}/guidewire.py +60 -20
- {pyxecm/customizer → pyxecm_customizer}/k8s.py +4 -4
- pyxecm_customizer/knowledge_graph.py +719 -0
- pyxecm_customizer/log.py +35 -0
- {pyxecm/customizer → pyxecm_customizer}/m365.py +41 -33
- {pyxecm/customizer → pyxecm_customizer}/payload.py +2359 -1991
- {pyxecm/customizer/api/common → pyxecm_customizer}/payload_list.py +57 -65
- {pyxecm/customizer → pyxecm_customizer}/salesforce.py +1 -1
- {pyxecm/customizer → pyxecm_customizer}/sap.py +6 -2
- {pyxecm/customizer → pyxecm_customizer}/servicenow.py +2 -4
- {pyxecm/customizer → pyxecm_customizer}/settings.py +7 -6
- {pyxecm/customizer → pyxecm_customizer}/successfactors.py +40 -28
- {pyxecm/customizer → pyxecm_customizer}/translate.py +14 -10
- {pyxecm/maintenance_page → pyxecm_maintenance_page}/__main__.py +1 -1
- {pyxecm/maintenance_page → pyxecm_maintenance_page}/app.py +16 -6
- pyxecm/customizer/api/app.py +0 -163
- pyxecm/customizer/log.py +0 -107
- pyxecm/customizer/nhc.py +0 -1169
- pyxecm/customizer/openapi.py +0 -258
- pyxecm/customizer/pht.py +0 -1357
- pyxecm-2.0.3.dist-info/METADATA +0 -119
- pyxecm-2.0.3.dist-info/RECORD +0 -78
- pyxecm-2.0.3.dist-info/licenses/LICENSE +0 -202
- pyxecm-2.0.3.dist-info/top_level.txt +0 -1
- {pyxecm/customizer/api → pyxecm_api}/__init__.py +0 -0
- {pyxecm/customizer/api/auth → pyxecm_api/agents/otcm_knowledgegraph}/__init__.py +0 -0
- {pyxecm/customizer/api/common → pyxecm_api/agents/otcm_user_agent}/__init__.py +0 -0
- {pyxecm/customizer/api/v1_csai → pyxecm_api/agents/otcm_workspace_agent}/__init__.py +0 -0
- {pyxecm/customizer/api/v1_maintenance → pyxecm_api/auth}/__init__.py +0 -0
- {pyxecm/customizer/api → pyxecm_api}/auth/models.py +0 -0
- {pyxecm/customizer/api/v1_otcs → pyxecm_api/common}/__init__.py +0 -0
- {pyxecm/customizer/api → pyxecm_api}/common/models.py +0 -0
- {pyxecm/customizer/api → pyxecm_api}/terminal/__init__.py +0 -0
- {pyxecm/customizer/api/v1_payload → pyxecm_api/v1_csai}/__init__.py +0 -0
- {pyxecm/customizer/api → pyxecm_api}/v1_csai/models.py +0 -0
- {pyxecm/customizer/api → pyxecm_api}/v1_maintenance/models.py +0 -0
- {pyxecm/customizer/api → pyxecm_api}/v1_payload/models.py +0 -0
- {pyxecm/customizer → pyxecm_customizer}/exceptions.py +0 -0
- {pyxecm/maintenance_page → pyxecm_maintenance_page}/__init__.py +0 -0
- {pyxecm/maintenance_page → pyxecm_maintenance_page}/settings.py +0 -0
- {pyxecm/maintenance_page → pyxecm_maintenance_page}/static/favicon.avif +0 -0
- {pyxecm/maintenance_page → pyxecm_maintenance_page}/templates/maintenance.html +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""init module."""
|
|
@@ -7,10 +7,10 @@ from http import HTTPStatus
|
|
|
7
7
|
import yaml
|
|
8
8
|
from fastapi import HTTPException
|
|
9
9
|
from pydantic import HttpUrl, ValidationError
|
|
10
|
+
from pyxecm_customizer.k8s import K8s
|
|
11
|
+
from pyxecm_maintenance_page.settings import settings as maint_settings
|
|
10
12
|
|
|
11
|
-
from
|
|
12
|
-
from pyxecm.customizer.k8s import K8s
|
|
13
|
-
from pyxecm.maintenance_page.settings import settings as maint_settings
|
|
13
|
+
from pyxecm_api.v1_maintenance.models import MaintenanceModel
|
|
14
14
|
|
|
15
15
|
logger = logging.getLogger("v1_maintenance.functions")
|
|
16
16
|
|
|
@@ -4,18 +4,18 @@ import logging
|
|
|
4
4
|
from typing import Annotated
|
|
5
5
|
|
|
6
6
|
from fastapi import APIRouter, Depends, Form
|
|
7
|
+
from pyxecm_customizer.k8s import K8s
|
|
8
|
+
from pyxecm_maintenance_page.settings import settings as maint_settings
|
|
7
9
|
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
from
|
|
11
|
-
from
|
|
12
|
-
from
|
|
13
|
-
from pyxecm.customizer.k8s import K8s
|
|
14
|
-
from pyxecm.maintenance_page.settings import settings as maint_settings
|
|
10
|
+
from pyxecm_api.auth import models
|
|
11
|
+
from pyxecm_api.auth.functions import get_authorized_user
|
|
12
|
+
from pyxecm_api.common.functions import get_k8s_object
|
|
13
|
+
from pyxecm_api.v1_maintenance.functions import get_maintenance_mode_status, set_maintenance_mode_via_ingress
|
|
14
|
+
from pyxecm_api.v1_maintenance.models import MaintenanceModel
|
|
15
15
|
|
|
16
16
|
router = APIRouter(prefix="/api/v1/maintenance", tags=["maintenance"])
|
|
17
17
|
|
|
18
|
-
logger = logging.getLogger("
|
|
18
|
+
logger = logging.getLogger("pyxecm_api.v1_maintenance")
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
@router.get(path="")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""init module."""
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
"""Define functions for v1_otcs."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from datetime import
|
|
4
|
+
from datetime import UTC, datetime
|
|
5
5
|
from threading import Lock
|
|
6
6
|
|
|
7
7
|
from fastapi import APIRouter
|
|
8
|
+
from pyxecm_customizer.k8s import K8s
|
|
8
9
|
|
|
9
|
-
from
|
|
10
|
-
from pyxecm.customizer.k8s import K8s
|
|
10
|
+
from pyxecm_api.settings import CustomizerAPISettings
|
|
11
11
|
|
|
12
12
|
router = APIRouter(prefix="/api/v1/otcs", tags=["otcs"])
|
|
13
13
|
|
|
14
|
-
logger = logging.getLogger("
|
|
14
|
+
logger = logging.getLogger("pyxecm_api.v1_otcs")
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def collect_otcs_logs(host: str, k8s_object: K8s, logs_lock: Lock, settings: CustomizerAPISettings) -> None:
|
|
18
18
|
"""Collect the logs for the given OTCS instance."""
|
|
19
19
|
|
|
20
20
|
with logs_lock:
|
|
21
|
-
timestamp = datetime.now(tz=
|
|
21
|
+
timestamp = datetime.now(tz=UTC).strftime("%Y-%m-%d_%H-%M")
|
|
22
22
|
tgz_file = f"/tmp/{timestamp}_{host}.tar.gz" # noqa: S108
|
|
23
23
|
|
|
24
24
|
if host.startswith("otcs-frontend"):
|
|
@@ -27,6 +27,8 @@ def collect_otcs_logs(host: str, k8s_object: K8s, logs_lock: Lock, settings: Cus
|
|
|
27
27
|
container = "otcs-backend-search-container"
|
|
28
28
|
elif host.startswith("otcs-admin"):
|
|
29
29
|
container = "otcs-admin-container"
|
|
30
|
+
elif host.startswith("otcs-da"):
|
|
31
|
+
container = "otcs-da-container"
|
|
30
32
|
else:
|
|
31
33
|
container = None
|
|
32
34
|
|
|
@@ -10,17 +10,18 @@ from typing import Annotated
|
|
|
10
10
|
import anyio
|
|
11
11
|
from fastapi import APIRouter, Body, Depends, File, HTTPException, UploadFile
|
|
12
12
|
from fastapi.responses import FileResponse, JSONResponse
|
|
13
|
+
from pyxecm_customizer.k8s import K8s
|
|
13
14
|
|
|
14
|
-
from
|
|
15
|
-
from
|
|
16
|
-
from
|
|
17
|
-
from
|
|
18
|
-
|
|
19
|
-
from
|
|
15
|
+
from pyxecm_api.auth.functions import get_authorized_user
|
|
16
|
+
from pyxecm_api.auth.models import User
|
|
17
|
+
from pyxecm_api.common.functions import get_k8s_object, get_otcs_logs_lock, get_settings
|
|
18
|
+
from pyxecm_api.settings import CustomizerAPISettings
|
|
19
|
+
|
|
20
|
+
from .functions import collect_otcs_logs
|
|
20
21
|
|
|
21
22
|
router = APIRouter(prefix="/api/v1/otcs", tags=["otcs"])
|
|
22
23
|
|
|
23
|
-
logger = logging.getLogger("
|
|
24
|
+
logger = logging.getLogger("pyxecm_api.v1_otcs")
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
@router.put(path="/logs", tags=["otcs"])
|
|
@@ -35,10 +36,15 @@ async def put_otcs_logs(
|
|
|
35
36
|
|
|
36
37
|
if "all" in hosts:
|
|
37
38
|
hosts = []
|
|
38
|
-
for sts in ["otcs-admin", "otcs-frontend", "otcs-backend-search"]:
|
|
39
|
+
for sts in ["otcs-admin", "otcs-frontend", "otcs-backend-search", "otcs-da"]:
|
|
39
40
|
try:
|
|
40
|
-
sts_replicas = k8s_object.get_stateful_set_scale(sts)
|
|
41
|
-
|
|
41
|
+
sts_replicas = k8s_object.get_stateful_set_scale(sts)
|
|
42
|
+
|
|
43
|
+
if sts_replicas is None:
|
|
44
|
+
logger.debug("Cannot get statefulset {sts}")
|
|
45
|
+
continue
|
|
46
|
+
|
|
47
|
+
hosts.extend([f"{sts}-{i}" for i in range(sts_replicas.status.replicas)])
|
|
42
48
|
except Exception as e:
|
|
43
49
|
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR) from e
|
|
44
50
|
|
|
@@ -118,10 +124,15 @@ async def get_otcs_log_files(
|
|
|
118
124
|
response = {"status": {host: bool(otcs_logs_lock[host].locked()) for host in otcs_logs_lock}, "files": files}
|
|
119
125
|
|
|
120
126
|
# Extend response with all hosts
|
|
121
|
-
for sts in ["otcs-admin", "otcs-frontend", "otcs-backend-search"]:
|
|
127
|
+
for sts in ["otcs-admin", "otcs-frontend", "otcs-backend-search", "otcs-da"]:
|
|
122
128
|
try:
|
|
123
|
-
sts_replicas = k8s_object.get_stateful_set_scale(sts)
|
|
124
|
-
|
|
129
|
+
sts_replicas = k8s_object.get_stateful_set_scale(sts)
|
|
130
|
+
|
|
131
|
+
if sts_replicas is None:
|
|
132
|
+
logger.debug("Cannot get statefulset {sts}")
|
|
133
|
+
continue
|
|
134
|
+
|
|
135
|
+
for i in range(sts_replicas.status.replicas):
|
|
125
136
|
host = f"{sts}-{i}"
|
|
126
137
|
|
|
127
138
|
if host in otcs_logs_lock:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""init module."""
|
|
@@ -12,13 +12,14 @@ import os
|
|
|
12
12
|
from collections.abc import AsyncGenerator
|
|
13
13
|
|
|
14
14
|
import anyio
|
|
15
|
+
from pyxecm.helper.otel_config import tracer
|
|
16
|
+
from pyxecm_customizer.exceptions import PayloadImportError
|
|
17
|
+
from pyxecm_customizer.payload import load_payload
|
|
15
18
|
|
|
16
|
-
from
|
|
17
|
-
from
|
|
18
|
-
from pyxecm.customizer.exceptions import PayloadImportError
|
|
19
|
-
from pyxecm.customizer.payload import load_payload
|
|
19
|
+
from pyxecm_api.common.functions import PAYLOAD_LIST
|
|
20
|
+
from pyxecm_api.settings import api_settings
|
|
20
21
|
|
|
21
|
-
logger = logging.getLogger("
|
|
22
|
+
logger = logging.getLogger("pyxecm_api.v1_payload")
|
|
22
23
|
|
|
23
24
|
# Initialize the globel Payloadlist object
|
|
24
25
|
|
|
@@ -141,7 +142,9 @@ def import_payload(
|
|
|
141
142
|
|
|
142
143
|
for filename in sorted(os.listdir(payload_dir)):
|
|
143
144
|
try:
|
|
144
|
-
|
|
145
|
+
with tracer.start_as_current_span("import_payload") as t:
|
|
146
|
+
t.set_attribute("payload", filename)
|
|
147
|
+
import_payload_file(os.path.join(payload_dir, filename), enabled, dependencies)
|
|
145
148
|
except PayloadImportError as exc:
|
|
146
149
|
logger.error(exc)
|
|
147
150
|
logger.debug(exc, exc_info=True)
|
|
@@ -166,7 +169,7 @@ def prepare_dependencies(dependencies: list) -> list | None:
|
|
|
166
169
|
return converted_list
|
|
167
170
|
|
|
168
171
|
|
|
169
|
-
async def tail_log(file_path: str) -> AsyncGenerator[str
|
|
172
|
+
async def tail_log(file_path: str) -> AsyncGenerator[str]:
|
|
170
173
|
"""Asynchronously follow the log file like `tail -f`."""
|
|
171
174
|
try:
|
|
172
175
|
async with await anyio.open_file(file_path) as file:
|
|
@@ -6,24 +6,25 @@ import json
|
|
|
6
6
|
import logging
|
|
7
7
|
import os
|
|
8
8
|
import shutil
|
|
9
|
-
from datetime import
|
|
9
|
+
from datetime import UTC, datetime
|
|
10
10
|
from http import HTTPStatus
|
|
11
11
|
from typing import Annotated, Literal
|
|
12
12
|
|
|
13
13
|
from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
|
|
14
14
|
from fastapi.responses import FileResponse, JSONResponse, Response, StreamingResponse
|
|
15
|
+
from pyxecm_customizer.payload import load_payload
|
|
15
16
|
|
|
16
|
-
from
|
|
17
|
-
from
|
|
18
|
-
from
|
|
19
|
-
from
|
|
20
|
-
|
|
21
|
-
from
|
|
22
|
-
from
|
|
17
|
+
from pyxecm_api.auth.functions import get_authorized_user
|
|
18
|
+
from pyxecm_api.auth.models import User
|
|
19
|
+
from pyxecm_api.common.functions import PAYLOAD_LIST, get_settings
|
|
20
|
+
from pyxecm_api.settings import CustomizerAPISettings
|
|
21
|
+
|
|
22
|
+
from .functions import prepare_dependencies, tail_log
|
|
23
|
+
from .models import PayloadListItem, PayloadListItems, UpdatedPayloadListItem
|
|
23
24
|
|
|
24
25
|
router = APIRouter(prefix="/api/v1/payload", tags=["payload"])
|
|
25
26
|
|
|
26
|
-
logger = logging.getLogger("
|
|
27
|
+
logger = logging.getLogger("pyxecm_api.v1_payload")
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
@router.post(path="")
|
|
@@ -255,7 +256,7 @@ async def update_payload_item(
|
|
|
255
256
|
payload_id,
|
|
256
257
|
)
|
|
257
258
|
|
|
258
|
-
now = datetime.now(
|
|
259
|
+
now = datetime.now(UTC)
|
|
259
260
|
old_log_name = (
|
|
260
261
|
os.path.dirname(data.logfile)
|
|
261
262
|
+ "/"
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
"""PYXECM classes for Customizer."""
|
|
2
2
|
|
|
3
|
+
from .__main__ import main
|
|
3
4
|
from .browser_automation import BrowserAutomation
|
|
4
5
|
from .customizer import Customizer
|
|
5
6
|
from .k8s import K8s
|
|
7
|
+
from .knowledge_graph import KnowledgeGraph
|
|
6
8
|
from .m365 import M365
|
|
7
9
|
from .payload import Payload
|
|
10
|
+
from .payload_list import PayloadList
|
|
8
11
|
from .salesforce import Salesforce
|
|
9
12
|
from .sap import SAP
|
|
10
13
|
from .servicenow import ServiceNow
|
|
14
|
+
from .settings import Settings
|
|
11
15
|
from .successfactors import SuccessFactors
|
|
12
16
|
|
|
13
17
|
__all__ = [
|
|
@@ -17,8 +21,12 @@ __all__ = [
|
|
|
17
21
|
"Customizer",
|
|
18
22
|
"Guidewire",
|
|
19
23
|
"K8s",
|
|
24
|
+
"KnowledgeGraph",
|
|
20
25
|
"Payload",
|
|
26
|
+
"PayloadList",
|
|
21
27
|
"Salesforce",
|
|
22
28
|
"ServiceNow",
|
|
29
|
+
"Settings",
|
|
23
30
|
"SuccessFactors",
|
|
31
|
+
"main",
|
|
24
32
|
]
|
|
@@ -10,20 +10,29 @@ import logging
|
|
|
10
10
|
import os
|
|
11
11
|
import sys
|
|
12
12
|
|
|
13
|
-
from
|
|
14
|
-
from
|
|
13
|
+
from .customizer import Customizer
|
|
14
|
+
from .payload import load_payload
|
|
15
15
|
|
|
16
16
|
logger = logging.getLogger("customizer")
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def main(
|
|
19
|
+
def main() -> int:
|
|
20
20
|
"""Start the Customizer."""
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
logging.basicConfig(
|
|
23
|
+
format="%(asctime)s %(levelname)s [%(name)s] %(message)s",
|
|
24
|
+
datefmt="%d-%b-%Y %H:%M:%S",
|
|
25
|
+
level=logging.INFO,
|
|
26
|
+
handlers=[
|
|
27
|
+
logging.StreamHandler(sys.stdout),
|
|
28
|
+
],
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
if len(sys.argv) < 2:
|
|
23
32
|
logger.error("No input file specified")
|
|
24
33
|
sys.exit(1)
|
|
25
34
|
|
|
26
|
-
payload_filename = argv[1]
|
|
35
|
+
payload_filename = sys.argv[1]
|
|
27
36
|
|
|
28
37
|
if not os.path.isfile(payload_filename):
|
|
29
38
|
logger.error("Input file does not exist")
|
|
@@ -37,22 +46,7 @@ def main(argv: list[str]) -> int:
|
|
|
37
46
|
|
|
38
47
|
my_customizer = Customizer(logger=logger, settings=customizer_settings)
|
|
39
48
|
|
|
40
|
-
my_customizer.customization_run()
|
|
41
|
-
|
|
42
|
-
return 0
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if __name__ == "__main__":
|
|
46
|
-
logging.basicConfig(
|
|
47
|
-
format="%(asctime)s %(levelname)s [%(name)s] %(message)s",
|
|
48
|
-
datefmt="%d-%b-%Y %H:%M:%S",
|
|
49
|
-
level=logging.INFO,
|
|
50
|
-
handlers=[
|
|
51
|
-
logging.StreamHandler(sys.stdout),
|
|
52
|
-
],
|
|
53
|
-
)
|
|
54
|
-
|
|
55
49
|
try:
|
|
56
|
-
|
|
50
|
+
my_customizer.customization_run()
|
|
57
51
|
except KeyboardInterrupt:
|
|
58
52
|
logger.warning("KeyboardInterrupt - exiting")
|