datatailr 0.1.71__py3-none-any.whl → 0.1.73__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 datatailr might be problematic. Click here for more details.

datatailr/excel/addin.py CHANGED
@@ -13,7 +13,11 @@ import importlib
13
13
  import subprocess
14
14
  import inspect
15
15
  import numpy as np
16
- from dt.excel_base import Addin as AddinBase, Queue # type: ignore
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
- id = args[0]
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
- queue = Queue(self.name.lower() + "." + func.__name__, id)
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(Queue(self.name.lower() + "." + func.__name__, id), **kwargs)
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}")
@@ -75,11 +75,15 @@ def create_user_and_group() -> Tuple[str, str]:
75
75
  gid = get_env_var("DATATAILR_GID")
76
76
 
77
77
  # Create group if it does not exist
78
+ # -o: allow to create a group with a non-unique GID
78
79
  os.system(f"getent group {group} || groupadd {group} -g {gid} -o")
79
80
 
80
81
  # Create user if it does not exist
82
+ # -s /bin/bash: set the shell to bash
83
+ # -M: do not create home directory (it is already created on the NFS volume)
84
+ # -o: allow to create a user with a non-unique UID
81
85
  os.system(
82
- f"getent passwd {user} || useradd -g {group} -s /bin/bash -m {user} -u {uid} -o"
86
+ f"getent passwd {user} || useradd -g {group} -s /bin/bash -M {user} -u {uid} -o"
83
87
  )
84
88
 
85
89
  permissions = (
@@ -93,11 +97,8 @@ def create_user_and_group() -> Tuple[str, str]:
93
97
  | stat.S_IXGRP
94
98
  )
95
99
 
96
- if os.path.exists(f"/home/{user}"):
97
- os.chmod(f"/home/{user}", permissions)
98
-
99
- if os.path.exists(f"/home/{user}/tmp/.dt"):
100
- os.chmod(f"/home/{user}/tmp/.dt", permissions)
100
+ os.makedirs(f"/home/{user}/tmp/.dt", exist_ok=True)
101
+ os.chmod(f"/home/{user}/tmp/.dt", permissions)
101
102
 
102
103
  return user, group
103
104
 
@@ -231,21 +232,17 @@ def main():
231
232
  } | env
232
233
  run_single_command_non_blocking("datatailr_run_excel", user, env)
233
234
  elif job_type == "workspace":
234
- # Set a custom PS1 for the IDE terminal: 17:38|user@my-ide/~/dir/path:$
235
- env["PS1"] = (
236
- 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\]\$"""
237
- )
238
235
  os.makedirs("/opt/datatailr/var/log", exist_ok=True)
239
236
  ide_command = [
240
237
  "code-server",
241
238
  "--auth=none",
242
- "--bind-addr=0.0.0.0:9090",
239
+ "--bind-addr=127.0.0.1:9090",
243
240
  f'--app-name="Datatailr IDE {get_env_var("DATATAILR_USER")}"',
244
241
  ]
245
242
  job_name = get_env_var("DATATAILR_JOB_NAME")
246
243
  jupyter_command = [
247
244
  "jupyter-lab",
248
- "--ip='*'",
245
+ "--ip='127.0.0.1'",
249
246
  "--port=7070",
250
247
  "--no-browser",
251
248
  "--NotebookApp.token=''",
@@ -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)
@@ -294,7 +294,7 @@ class BatchJob:
294
294
  env = {
295
295
  "DATATAILR_BATCH_ID": str(self.dag.id),
296
296
  "DATATAILR_JOB_ID": str(self.__id),
297
- "DATATAILR_JOB_NAME": self.name,
297
+ "DATATAILR_JOB_NAME": f"{self.dag.name}[{self.__id}]",
298
298
  }
299
299
  self.entrypoint(env=env)
300
300
  else:
@@ -479,10 +479,26 @@ class Batch(Job):
479
479
 
480
480
  def prepare_args(self) -> None:
481
481
  def arg_name(arg: Union[BatchJob, str]) -> str:
482
- return arg.name if isinstance(arg, BatchJob) else arg
482
+ return f"{self.name}[{arg.id}]" if isinstance(arg, BatchJob) else arg
483
+
484
+ def adjust_mapping(mapping: Dict[str, str]) -> Dict[str, str]:
485
+ result = {}
486
+ for k, v in mapping.items():
487
+ if isinstance(v, BatchJob):
488
+ result[k] = f"{self.name}[{v.id}]"
489
+ elif isinstance(v, str):
490
+ job = self.get_job_by_name(v)
491
+ if job is not None:
492
+ result[k] = f"{self.name}[{job.id}]"
493
+ else:
494
+ result[k] = v
495
+ else:
496
+ raise TypeError(
497
+ f"Unsupported type in argument mapping: {type(v)} for key {k}"
498
+ )
499
+ return result
483
500
 
484
501
  def merged(dst: dict[str, str], src: dict[str, str]) -> dict[str, str]:
485
- # copy so we don't mutate the original mapping
486
502
  out = dict(dst)
487
503
  seen_vals = set(out.values())
488
504
  for k, v in src.items():
@@ -492,12 +508,12 @@ class Batch(Job):
492
508
  return out
493
509
 
494
510
  args = {
495
- j.name: merged(
496
- j.argument_mapping, {k: arg_name(v) for k, v in j.args.items()}
511
+ f"{self.name}[{j.id}]": merged(
512
+ adjust_mapping(j.argument_mapping),
513
+ {j.argument_mapping.get(k, k): arg_name(v) for k, v in j.args.items()},
497
514
  )
498
515
  for j in self.__jobs
499
516
  }
500
-
501
517
  __ARGUMENTS_CACHE__.add_arguments(self.id, args)
502
518
 
503
519
  def save(self) -> Tuple[bool, str]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datatailr
3
- Version: 0.1.71
3
+ Version: 0.1.73
4
4
  Summary: Ready-to-Use Platform That Drives Business Insights
5
5
  Author-email: Datatailr <info@datatailr.com>
6
6
  License-Expression: MIT
@@ -13,23 +13,24 @@ datatailr/wrapper.py,sha256=45RrMeYIFFWJAtOlQZRe1fT9daeq4vFlj6nIajbewEY,8080
13
13
  datatailr/build/__init__.py,sha256=_dA7b4L6wsaAFaSxUoYSJ1oaRqDHDMR20kqoCocSOss,487
14
14
  datatailr/build/image.py,sha256=YC8ML-l-sj6TcIBY-DCx_vaeI_7SmL9fPFhHnuxzRh0,5509
15
15
  datatailr/excel/__init__.py,sha256=wox5ltPeOYZcZoRDW4R6tJsfOjf-0WZM2_pGgltGjdo,682
16
- datatailr/excel/addin.py,sha256=at0S1cNHShCOCXAml1W2sJmJ5DdNroTN6Bp6KWnYZ94,6104
17
- datatailr/sbin/datatailr_run.py,sha256=MKNlI6YM1UvBwdk90YUYYQbrbAEdba5ZryFIbYT2CiE,10051
16
+ datatailr/excel/addin.py,sha256=3UiA7z71ewnEvLSTbcJdPNGWf-uYbeSt_3vbgN42h4E,6354
17
+ datatailr/excel/stubs.py,sha256=RU0Y6PWKRAtK-tgBP5uWrWYW-L3TIGRJwcUUhkA5yxU,830
18
+ datatailr/sbin/datatailr_run.py,sha256=qKMTKjJWX8bOc8GLAvTUR7ZL056-amLvXdAncqJMAEU,9962
18
19
  datatailr/sbin/datatailr_run_app.py,sha256=itF76XC2F4RK9s6bkoEppEiYwSLHK_5Jai3yvC-kFhY,1501
19
20
  datatailr/sbin/datatailr_run_batch.py,sha256=UWnp96j_G66R_Cape7Bb-rbK6UBLF7Y5_mTlWyGJAVQ,1818
20
21
  datatailr/sbin/datatailr_run_excel.py,sha256=BLWmvxpKEE_8vJhs8E4VWq07FOBof5tlow-AkIEXtHw,1470
21
22
  datatailr/sbin/datatailr_run_service.py,sha256=DO9LGOpz3CVZOJJRHb4ac7AgY_mLbXHGadSyVCeIknc,1212
22
23
  datatailr/scheduler/__init__.py,sha256=qydHYVtEP6SUWd2CQ6FRdTdRWNz3SbYPJy4FK_wOvMk,1772
23
24
  datatailr/scheduler/arguments_cache.py,sha256=00OE0DhobYteBOnirjulO1ltgGBRamAdCO168O3_Zes,6236
24
- datatailr/scheduler/base.py,sha256=WWi_VnDxev0GG6QolF3Wtj-p_JS5t2CN9VALYPl1OYo,16994
25
- datatailr/scheduler/batch.py,sha256=CQCH1wHhW1qx09J7iQNQleErJ4n0nssAbd6u9YS6FMY,17735
25
+ datatailr/scheduler/base.py,sha256=GlTsp2Qcoy14DTfLSPhiFFBRE_cMfz_uA_ASQSx4tL0,17038
26
+ datatailr/scheduler/batch.py,sha256=ZhEf3YkXf1_ieV5ivk4-me60ov9v5r9f9BdkJw84i_0,18475
26
27
  datatailr/scheduler/batch_decorator.py,sha256=LqL1bsupWLn-YEQUvFJYae7R3ogrL5-VodyiiScrkRw,5806
27
28
  datatailr/scheduler/constants.py,sha256=5WWTsfwZ_BA8gVDOTa2AQX9DJ0NzfaWgtY3vrODS2-8,606
28
29
  datatailr/scheduler/schedule.py,sha256=0XJJen2nL1xplRs0Xbjwgq3T-0bFCOrJzkSALdio998,3741
29
30
  datatailr/scheduler/utils.py,sha256=up6oR2iwe6G52LkvgfO394xchXgCYNjOMGRQW3e8PQk,1082
30
- datatailr-0.1.71.dist-info/licenses/LICENSE,sha256=ikKP4_O-UD_b8FuNdKmbzTb6odd0JX085ZW_FAPN3VI,1066
31
- datatailr-0.1.71.dist-info/METADATA,sha256=jtM6J7uHqGgQ_MHJBvKDuIdYAMvQ8T4XM16b0RyF09M,5146
32
- datatailr-0.1.71.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
- datatailr-0.1.71.dist-info/entry_points.txt,sha256=YqXfk2At-olW4PUSRkqvy_O3Mbv7uTKCCPuAAiz3Qbg,312
34
- datatailr-0.1.71.dist-info/top_level.txt,sha256=75gntW0X_SKpqxLL6hAPipvpk28GAhJBvoyqN_HohWU,10
35
- datatailr-0.1.71.dist-info/RECORD,,
31
+ datatailr-0.1.73.dist-info/licenses/LICENSE,sha256=ikKP4_O-UD_b8FuNdKmbzTb6odd0JX085ZW_FAPN3VI,1066
32
+ datatailr-0.1.73.dist-info/METADATA,sha256=gl76JiXGJXes-34NGbHzW0Jmauiohad2CaQuvvpWon0,5146
33
+ datatailr-0.1.73.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
+ datatailr-0.1.73.dist-info/entry_points.txt,sha256=YqXfk2At-olW4PUSRkqvy_O3Mbv7uTKCCPuAAiz3Qbg,312
35
+ datatailr-0.1.73.dist-info/top_level.txt,sha256=75gntW0X_SKpqxLL6hAPipvpk28GAhJBvoyqN_HohWU,10
36
+ datatailr-0.1.73.dist-info/RECORD,,