datatailr 0.1.72__tar.gz → 0.1.74__tar.gz
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 datatailr might be problematic. Click here for more details.
- {datatailr-0.1.72/src/datatailr.egg-info → datatailr-0.1.74}/PKG-INFO +1 -1
- {datatailr-0.1.72 → datatailr-0.1.74}/pyproject.toml +1 -1
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/excel/addin.py +11 -6
- datatailr-0.1.74/src/datatailr/excel/stubs.py +37 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/scheduler/base.py +9 -4
- {datatailr-0.1.72 → datatailr-0.1.74/src/datatailr.egg-info}/PKG-INFO +1 -1
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr.egg-info/SOURCES.txt +1 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/sbin/datatailr_run.py +18 -17
- {datatailr-0.1.72 → datatailr-0.1.74}/LICENSE +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/README.md +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/setup.cfg +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/setup.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/__init__.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/acl.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/blob.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/build/__init__.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/build/image.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/dt_json.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/errors.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/excel/__init__.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/group.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/logging.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/scheduler/__init__.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/scheduler/arguments_cache.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/scheduler/batch.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/scheduler/batch_decorator.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/scheduler/constants.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/scheduler/schedule.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/scheduler/utils.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/tag.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/user.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/utils.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/version.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr/wrapper.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr.egg-info/dependency_links.txt +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr.egg-info/entry_points.txt +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr.egg-info/requires.txt +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/datatailr.egg-info/top_level.txt +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/sbin/datatailr_run_app.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/sbin/datatailr_run_batch.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/sbin/datatailr_run_excel.py +0 -0
- {datatailr-0.1.72 → datatailr-0.1.74}/src/sbin/datatailr_run_service.py +0 -0
|
@@ -13,7 +13,11 @@ import importlib
|
|
|
13
13
|
import subprocess
|
|
14
14
|
import inspect
|
|
15
15
|
import numpy as np
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
from dt.excel_base import Addin as AddinBase, Queue # type: ignore
|
|
19
|
+
except ImportError as e:
|
|
20
|
+
from datatailr.excel.stubs import AddinBase, Queue
|
|
17
21
|
|
|
18
22
|
|
|
19
23
|
def __progress__(queue, stop):
|
|
@@ -107,7 +111,9 @@ class Addin(AddinBase):
|
|
|
107
111
|
signature = inspect.signature(func)
|
|
108
112
|
|
|
109
113
|
def wrapper(*args, **kwargs):
|
|
110
|
-
|
|
114
|
+
# TODO: check whether it's possible to use a kwarg instead so that a decorated function can
|
|
115
|
+
# be called directly from python code without requiring positional argument for _id
|
|
116
|
+
_id = args[0]
|
|
111
117
|
|
|
112
118
|
for arg in signature.parameters.values():
|
|
113
119
|
if streaming and arg.name == "queue":
|
|
@@ -121,7 +127,7 @@ class Addin(AddinBase):
|
|
|
121
127
|
"excel/python/dt/excel.py: Got argument of wrong type, expected %s or numpy.ndarray, got %s"
|
|
122
128
|
% (arg.annotation, type(kwargs[arg.name]))
|
|
123
129
|
)
|
|
124
|
-
|
|
130
|
+
queue = Queue(self.name.lower() + "." + func.__name__, _id)
|
|
125
131
|
if not streaming:
|
|
126
132
|
if not progressbar:
|
|
127
133
|
result = func(**kwargs)
|
|
@@ -132,7 +138,7 @@ class Addin(AddinBase):
|
|
|
132
138
|
from threading import Event, Thread
|
|
133
139
|
|
|
134
140
|
error = None
|
|
135
|
-
|
|
141
|
+
|
|
136
142
|
stop = Event()
|
|
137
143
|
thread = Thread(target=__progress__, args=(queue, stop))
|
|
138
144
|
thread.start()
|
|
@@ -149,9 +155,8 @@ class Addin(AddinBase):
|
|
|
149
155
|
else:
|
|
150
156
|
queue.push(result)
|
|
151
157
|
return
|
|
152
|
-
|
|
153
158
|
try:
|
|
154
|
-
func(
|
|
159
|
+
func(queue, **kwargs)
|
|
155
160
|
except Exception as exception:
|
|
156
161
|
queue.error(str(exception))
|
|
157
162
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyright (c) 2025 - Datatailr Inc.
|
|
3
|
+
All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
This file is part of Datatailr and subject to the terms and conditions
|
|
6
|
+
defined in 'LICENSE.txt'. Unauthorized copying and/or distribution
|
|
7
|
+
of this file, in parts or full, via any medium is strictly prohibited.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AddinBase:
|
|
12
|
+
def __init__(self, name, *args, **kwargs):
|
|
13
|
+
self.name = name
|
|
14
|
+
|
|
15
|
+
def decorator_impl(
|
|
16
|
+
self,
|
|
17
|
+
signature,
|
|
18
|
+
wrapper,
|
|
19
|
+
func_name,
|
|
20
|
+
description,
|
|
21
|
+
help,
|
|
22
|
+
volatile,
|
|
23
|
+
streaming,
|
|
24
|
+
):
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Queue:
|
|
29
|
+
def __init__(self, name, _id):
|
|
30
|
+
self.name = name
|
|
31
|
+
self.id = _id
|
|
32
|
+
|
|
33
|
+
def push(self, value):
|
|
34
|
+
print(f"Queue {self.name} ({self.id}): {value}")
|
|
35
|
+
|
|
36
|
+
def error(self, message):
|
|
37
|
+
print(f"Queue {self.name} ({self.id}) Error: {message}")
|
|
@@ -245,6 +245,7 @@ class Job:
|
|
|
245
245
|
if self.type == JobType.EXCEL:
|
|
246
246
|
if "DATATAILR_LOCAL" not in self.__env_vars:
|
|
247
247
|
self.__env_vars.update({"DATATAILR_LOCAL": "false"})
|
|
248
|
+
job_dict["per_user_job"] = True
|
|
248
249
|
if self.type != JobType.BATCH:
|
|
249
250
|
job_dict["entrypoint"] = str(self.entrypoint) if self.entrypoint else None
|
|
250
251
|
job_dict["env"] = dict_to_env_vars(self.__env_vars)
|
|
@@ -293,6 +294,7 @@ class Job:
|
|
|
293
294
|
Returns a tuple of (branch: str, commit_hash: str).
|
|
294
295
|
"""
|
|
295
296
|
path_to_repo = self.image.path_to_repo or "."
|
|
297
|
+
branch_name, local_commit, return_code = "unknown", "unknown", None
|
|
296
298
|
try:
|
|
297
299
|
local_commit = run_shell_command(
|
|
298
300
|
f"cd {path_to_repo} && git rev-parse HEAD"
|
|
@@ -300,6 +302,13 @@ class Job:
|
|
|
300
302
|
branch_name = run_shell_command(
|
|
301
303
|
f"cd {path_to_repo} && git rev-parse --abbrev-ref HEAD"
|
|
302
304
|
)[0]
|
|
305
|
+
|
|
306
|
+
if (
|
|
307
|
+
os.getenv("DATATAILR_ALLOW_UNSAFE_SCHEDULING", "false").lower()
|
|
308
|
+
== "true"
|
|
309
|
+
):
|
|
310
|
+
return branch_name, local_commit
|
|
311
|
+
|
|
303
312
|
return_code = run_shell_command(
|
|
304
313
|
f"cd {path_to_repo} && git diff --exit-code"
|
|
305
314
|
)
|
|
@@ -308,15 +317,11 @@ class Job:
|
|
|
308
317
|
logger.warning(
|
|
309
318
|
"Git is not installed or not found in PATH. Repository validation is not possible."
|
|
310
319
|
)
|
|
311
|
-
branch_name, local_commit, return_code = "unknown", "unknown", None
|
|
312
320
|
else:
|
|
313
321
|
raise RepoValidationError(
|
|
314
322
|
f"Error accessing git repository at {path_to_repo}: {e}"
|
|
315
323
|
) from e
|
|
316
324
|
|
|
317
|
-
if os.getenv("DATATAILR_ALLOW_UNSAFE_SCHEDULING", "false").lower() == "true":
|
|
318
|
-
return branch_name, local_commit
|
|
319
|
-
|
|
320
325
|
is_committed = return_code is not None and return_code[1] == 0
|
|
321
326
|
|
|
322
327
|
if not is_committed:
|
|
@@ -24,6 +24,7 @@ src/datatailr/build/__init__.py
|
|
|
24
24
|
src/datatailr/build/image.py
|
|
25
25
|
src/datatailr/excel/__init__.py
|
|
26
26
|
src/datatailr/excel/addin.py
|
|
27
|
+
src/datatailr/excel/stubs.py
|
|
27
28
|
src/datatailr/scheduler/__init__.py
|
|
28
29
|
src/datatailr/scheduler/arguments_cache.py
|
|
29
30
|
src/datatailr/scheduler/base.py
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
import concurrent.futures
|
|
36
36
|
import subprocess
|
|
37
37
|
import os
|
|
38
|
+
import sys
|
|
38
39
|
import stat
|
|
39
40
|
import shlex
|
|
40
41
|
import sysconfig
|
|
@@ -46,7 +47,7 @@ logger = DatatailrLogger(os.path.abspath(__file__)).get_logger()
|
|
|
46
47
|
|
|
47
48
|
if not is_dt_installed():
|
|
48
49
|
logger.error("Datatailr is not installed.")
|
|
49
|
-
|
|
50
|
+
sys.exit(1)
|
|
50
51
|
|
|
51
52
|
|
|
52
53
|
def get_env_var(name: str, default: str | None = None) -> str:
|
|
@@ -75,11 +76,15 @@ def create_user_and_group() -> Tuple[str, str]:
|
|
|
75
76
|
gid = get_env_var("DATATAILR_GID")
|
|
76
77
|
|
|
77
78
|
# Create group if it does not exist
|
|
79
|
+
# -o: allow to create a group with a non-unique GID
|
|
78
80
|
os.system(f"getent group {group} || groupadd {group} -g {gid} -o")
|
|
79
81
|
|
|
80
82
|
# Create user if it does not exist
|
|
83
|
+
# -s /bin/bash: set the shell to bash
|
|
84
|
+
# -M: do not create home directory (it is already created on the NFS volume)
|
|
85
|
+
# -o: allow to create a user with a non-unique UID
|
|
81
86
|
os.system(
|
|
82
|
-
f"getent passwd {user} || useradd -g {group} -s /bin/bash -
|
|
87
|
+
f"getent passwd {user} || useradd -g {group} -s /bin/bash -M {user} -u {uid} -o"
|
|
83
88
|
)
|
|
84
89
|
|
|
85
90
|
permissions = (
|
|
@@ -201,7 +206,7 @@ def main():
|
|
|
201
206
|
"DATATAILR_BATCH_ID": batch_id,
|
|
202
207
|
"DATATAILR_BATCH_ENTRYPOINT": entrypoint,
|
|
203
208
|
} | env
|
|
204
|
-
run_single_command_non_blocking("datatailr_run_batch", user, env)
|
|
209
|
+
return run_single_command_non_blocking("datatailr_run_batch", user, env)
|
|
205
210
|
elif job_type == "service":
|
|
206
211
|
port = get_env_var("DATATAILR_SERVICE_PORT", 8080)
|
|
207
212
|
entrypoint = get_env_var("DATATAILR_ENTRYPOINT")
|
|
@@ -209,16 +214,15 @@ def main():
|
|
|
209
214
|
"DATATAILR_ENTRYPOINT": entrypoint,
|
|
210
215
|
"DATATAILR_SERVICE_PORT": port,
|
|
211
216
|
} | env
|
|
212
|
-
run_single_command_non_blocking("datatailr_run_service", user, env)
|
|
217
|
+
return run_single_command_non_blocking("datatailr_run_service", user, env)
|
|
213
218
|
elif job_type == "app":
|
|
214
219
|
entrypoint = get_env_var("DATATAILR_ENTRYPOINT")
|
|
215
220
|
env = {
|
|
216
221
|
"DATATAILR_ENTRYPOINT": entrypoint,
|
|
217
222
|
} | env
|
|
218
|
-
run_single_command_non_blocking("datatailr_run_app", user, env)
|
|
223
|
+
return run_single_command_non_blocking("datatailr_run_app", user, env)
|
|
219
224
|
elif job_type == "excel":
|
|
220
225
|
host = get_env_var("DATATAILR_HOST", "")
|
|
221
|
-
local = get_env_var("DATATAILR_LOCAL", "")
|
|
222
226
|
entrypoint = get_env_var("DATATAILR_ENTRYPOINT")
|
|
223
227
|
local = get_env_var("DATATAILR_LOCAL", False)
|
|
224
228
|
env = {
|
|
@@ -226,23 +230,19 @@ def main():
|
|
|
226
230
|
"DATATAILR_HOST": host,
|
|
227
231
|
"DATATAILR_LOCAL": local,
|
|
228
232
|
} | env
|
|
229
|
-
run_single_command_non_blocking("datatailr_run_excel", user, env)
|
|
233
|
+
return run_single_command_non_blocking("datatailr_run_excel", user, env)
|
|
230
234
|
elif job_type == "workspace":
|
|
231
|
-
# Set a custom PS1 for the IDE terminal: 17:38|user@my-ide/~/dir/path:$
|
|
232
|
-
env["PS1"] = (
|
|
233
|
-
r"""\[\e[2m\]\A\[\e[0m\]|\[\e[38;5;40m\]\u\[\e[92m\]@${DATATAILR_JOB_NAME:-datatailr}\[\e[0m\]/\[\e[94;1m\]\w\[\e[0m\]\$"""
|
|
234
|
-
)
|
|
235
235
|
os.makedirs("/opt/datatailr/var/log", exist_ok=True)
|
|
236
236
|
ide_command = [
|
|
237
237
|
"code-server",
|
|
238
238
|
"--auth=none",
|
|
239
|
-
"--bind-addr=
|
|
239
|
+
"--bind-addr=127.0.0.1:9090",
|
|
240
240
|
f'--app-name="Datatailr IDE {get_env_var("DATATAILR_USER")}"',
|
|
241
241
|
]
|
|
242
242
|
job_name = get_env_var("DATATAILR_JOB_NAME")
|
|
243
243
|
jupyter_command = [
|
|
244
244
|
"jupyter-lab",
|
|
245
|
-
"--ip='
|
|
245
|
+
"--ip='127.0.0.1'",
|
|
246
246
|
"--port=7070",
|
|
247
247
|
"--no-browser",
|
|
248
248
|
"--NotebookApp.token=''",
|
|
@@ -251,7 +251,7 @@ def main():
|
|
|
251
251
|
f"--ServerApp.static_url_prefix=/workspace/{job_name}/jupyter/static/",
|
|
252
252
|
f"--ServerApp.root_dir=/home/{user}",
|
|
253
253
|
]
|
|
254
|
-
run_commands_in_parallel(
|
|
254
|
+
return run_commands_in_parallel(
|
|
255
255
|
[ide_command, jupyter_command], user, env, ["code-server", "jupyter"]
|
|
256
256
|
)
|
|
257
257
|
|
|
@@ -262,8 +262,9 @@ def main():
|
|
|
262
262
|
if __name__ == "__main__":
|
|
263
263
|
try:
|
|
264
264
|
logger.debug("Starting job execution...")
|
|
265
|
-
main()
|
|
266
|
-
logger.debug("Job executed successfully
|
|
265
|
+
rc = main()
|
|
266
|
+
logger.debug(f"Job executed successfully, with code {rc}")
|
|
267
|
+
raise SystemExit(rc)
|
|
267
268
|
except Exception as e:
|
|
268
269
|
logger.error(f"Error during job execution: {e}")
|
|
269
|
-
raise
|
|
270
|
+
raise SystemExit(1)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|