gooddata-flight-server 1.34.0__py3-none-any.whl → 1.56.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.
@@ -1,13 +1,29 @@
1
1
  # (C) 2024 GoodData Corporation
2
2
  import base64
3
3
  import traceback
4
- from typing import Callable, Optional, Union
4
+ from typing import Callable, Optional, Union, cast
5
5
 
6
6
  import orjson
7
7
  import pyarrow.flight
8
8
 
9
9
  from gooddata_flight_server.errors.error_code import ErrorCode
10
10
 
11
+ _ERROR_INFO_MAX_MSG = 256
12
+ _ERROR_INFO_MAX_DETAIL = 512
13
+
14
+
15
+ def _truncate_str_value(val: Optional[str], max_len: int) -> Optional[str]:
16
+ if val is None:
17
+ return None
18
+
19
+ if len(val) <= max_len:
20
+ return val
21
+
22
+ # no big deal that the actual max length is slightly exceeded
23
+ # all this truncating happens because ErrorInfo is eventually
24
+ # passed via gRPC headers which have 16k hard limit
25
+ return val[:max_len] + " [truncated]"
26
+
11
27
 
12
28
  class ErrorInfo:
13
29
  """
@@ -22,15 +38,15 @@ class ErrorInfo:
22
38
  body: Optional[bytes] = None,
23
39
  code: int = 0,
24
40
  ) -> None:
25
- self._msg = msg
26
- self._detail: Optional[str] = detail
41
+ self._msg = cast(str, _truncate_str_value(msg, _ERROR_INFO_MAX_MSG))
42
+ self._detail: Optional[str] = _truncate_str_value(detail, _ERROR_INFO_MAX_DETAIL)
27
43
  self._body: Optional[bytes] = body
28
44
  self._code: int = code
29
45
 
30
46
  @property
31
47
  def msg(self) -> str:
32
48
  """
33
- :return: human readable error message
49
+ :return: human-readable error message
34
50
  """
35
51
  return self._msg
36
52
 
@@ -60,26 +76,36 @@ class ErrorInfo:
60
76
  """
61
77
  Updates error message.
62
78
 
63
- :param msg: new message
79
+ :param msg: new message, up to 256 characters; will be truncated if the limit is exceeded
64
80
  :return: self, for call chaining sakes
65
81
  """
66
- self._msg = msg
82
+ self._msg = cast(str, _truncate_str_value(msg, _ERROR_INFO_MAX_MSG))
83
+
67
84
  return self
68
85
 
69
86
  def with_detail(self, detail: Optional[str] = None) -> "ErrorInfo":
70
87
  """
71
88
  Updates or resets the error detail.
72
89
 
73
- :param detail: detail to set; if None, the detail stored in the meta will be removed; default is None
90
+ :param detail: detail to set; if None, the detail stored in the meta will be removed; default is None;
91
+ detail can be up to 512 characters; will be truncated if the limit is exceeded
74
92
  :return: self, for call chaining sakes
75
93
  """
76
- self._detail = detail
94
+ self._detail = _truncate_str_value(detail, _ERROR_INFO_MAX_DETAIL)
95
+
77
96
  return self
78
97
 
79
98
  def with_body(self, body: Optional[Union[bytes, str]]) -> "ErrorInfo":
80
99
  """
81
100
  Updates or resets the error body.
82
101
 
102
+ IMPORTANT: the ErrorInfo (and thus the contents of `body`) are passed out via FlightError.extra_info
103
+ property. The Flight RPC implementations pass the `extra_info` via gRPC headers. In turn, the gRPC headers
104
+ do have size limit. Keep this in mind when designing the value of `body`.
105
+
106
+ If you set body that is too large, you will run into problems like this:
107
+ https://github.com/grpc/grpc/issues/37852.
108
+
83
109
  :param body: body to set; if None, the body stored in the meta will be removed; default is None
84
110
  :return: self, for call chaining sakes
85
111
  """
@@ -30,12 +30,10 @@ T = TypeVar("T")
30
30
  P = ParamSpec("P")
31
31
 
32
32
 
33
- def rpc_decorator() -> (
34
- Callable[
35
- [Callable[Concatenate[Any, pyarrow.flight.ServerCallContext, P], T]],
36
- Callable[Concatenate[Any, pyarrow.flight.ServerCallContext, P], T],
37
- ]
38
- ):
33
+ def rpc_decorator() -> Callable[
34
+ [Callable[Concatenate[Any, pyarrow.flight.ServerCallContext, P], T]],
35
+ Callable[Concatenate[Any, pyarrow.flight.ServerCallContext, P], T],
36
+ ]:
39
37
  def _factory(
40
38
  fun: Callable[Concatenate[Any, pyarrow.flight.ServerCallContext, P], T],
41
39
  ) -> Callable[Concatenate[Any, pyarrow.flight.ServerCallContext, P], T]:
@@ -264,9 +264,7 @@ class FlightRpcService:
264
264
  def wait_for_stop(self, timeout: Optional[float] = None) -> bool:
265
265
  if self._flight_shutdown_thread is None:
266
266
  # this is really some mess in the caller code.. did not call stop() but tries to wait for it..
267
- raise AssertionError(
268
- "Flight server stop() was not issued yet attempting to wait for " "the server to stop."
269
- )
267
+ raise AssertionError("Flight server stop() was not issued yet attempting to wait for the server to stop.")
270
268
 
271
269
  if self._flight_shutdown_thread.is_alive():
272
270
  self._flight_shutdown_thread.join(timeout=timeout)
@@ -54,6 +54,15 @@ class TaskExecutor(abc.ABC):
54
54
  """
55
55
  raise NotImplementedError
56
56
 
57
+ @abc.abstractmethod
58
+ def get_task_submitted_timestamp(self, task_id: str) -> Optional[float]:
59
+ """
60
+ Returns the timestamp of when the task with the given id was submitted.
61
+ :param task_id: task id to get the timestamp for
62
+ :return: Timestamp in seconds since epoch of when the task was submitted or None if there is no such task
63
+ """
64
+ raise NotImplementedError
65
+
57
66
  @abc.abstractmethod
58
67
  def wait_for_result(self, task_id: str, timeout: Optional[float] = None) -> Optional[TaskExecutionResult]:
59
68
  """
@@ -565,6 +565,14 @@ class ThreadTaskExecutor(TaskExecutor, _TaskExecutionCallbacks):
565
565
  execution.start()
566
566
  self._metrics.queue_size.set(self._queue_size)
567
567
 
568
+ def get_task_submitted_timestamp(self, task_id: str) -> Optional[float]:
569
+ with self._task_lock:
570
+ execution = self._executions.get(task_id)
571
+
572
+ if execution is not None:
573
+ return execution.stats.created
574
+ return None
575
+
568
576
  def wait_for_result(self, task_id: str, timeout: Optional[float] = None) -> Optional[TaskExecutionResult]:
569
577
  with self._task_lock:
570
578
  execution = self._executions.get(task_id)
@@ -597,8 +605,8 @@ class ThreadTaskExecutor(TaskExecutor, _TaskExecutionCallbacks):
597
605
  return True
598
606
 
599
607
  if execution is None:
600
- # the task was not and is not running - cancel not possible
601
- return False
608
+ # the task was not and is not running - cancel not necessary
609
+ return True
602
610
 
603
611
  return execution.cancel()
604
612
 
@@ -1,28 +1,25 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: gooddata-flight-server
3
- Version: 1.34.0
3
+ Version: 1.56.0
4
4
  Summary: Flight RPC server to host custom functions
5
- Author: GoodData
6
- Author-email: support@gooddata.com
7
- License: MIT
8
- Project-URL: Documentation, https://gooddata-flight-server.readthedocs.io/en/v1.34.0
5
+ Project-URL: Documentation, https://gooddata-flight-server.readthedocs.io/en/v1.56.0
9
6
  Project-URL: Source, https://github.com/gooddata/gooddata-python-sdk
10
- Keywords: gooddata,flight,rpc,flight rpc,custom functions,analytics,headless,business,intelligence,headless-bi,cloud,native,semantic,layer,sql,metrics
7
+ Author-email: GoodData <support@gooddata.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE.txt
10
+ Keywords: analytics,business,cloud,custom functions,flight,flight rpc,gooddata,headless,headless-bi,intelligence,layer,metrics,native,rpc,semantic,sql
11
11
  Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Environment :: Console
13
- Classifier: License :: OSI Approved :: MIT License
14
- Classifier: Programming Language :: Python :: 3.9
15
13
  Classifier: Programming Language :: Python :: 3.10
16
14
  Classifier: Programming Language :: Python :: 3.11
17
15
  Classifier: Programming Language :: Python :: 3.12
18
16
  Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
19
18
  Classifier: Topic :: Database
20
19
  Classifier: Topic :: Scientific/Engineering
21
20
  Classifier: Topic :: Software Development
22
21
  Classifier: Typing :: Typed
23
- Requires-Python: >=3.9.0
24
- Description-Content-Type: text/markdown
25
- License-File: LICENSE.txt
22
+ Requires-Python: >=3.10
26
23
  Requires-Dist: dynaconf<4.0.0,>=3.1.11
27
24
  Requires-Dist: opentelemetry-api<=2.0.0,>=1.24.0
28
25
  Requires-Dist: opentelemetry-sdk<=2.0.0,>=1.24.0
@@ -31,17 +28,7 @@ Requires-Dist: prometheus-client~=0.20.0
31
28
  Requires-Dist: pyarrow>=16.1.0
32
29
  Requires-Dist: readerwriterlock~=1.0.9
33
30
  Requires-Dist: structlog<25.0.0,>=24.0.0
34
- Dynamic: author
35
- Dynamic: author-email
36
- Dynamic: classifier
37
- Dynamic: description
38
- Dynamic: description-content-type
39
- Dynamic: keywords
40
- Dynamic: license
41
- Dynamic: project-url
42
- Dynamic: requires-dist
43
- Dynamic: requires-python
44
- Dynamic: summary
31
+ Description-Content-Type: text/markdown
45
32
 
46
33
  # GoodData Flight Server
47
34
 
@@ -8,7 +8,7 @@ gooddata_flight_server/config/__init__.py,sha256=QL4TGz0QQfsNakkgMkve9k8wiR73dfo
8
8
  gooddata_flight_server/config/config.py,sha256=vMdBzGnBrxPCAsfJgpOxQKjxXl5xjEFNu32_4Bk5Qdw,17108
9
9
  gooddata_flight_server/errors/__init__.py,sha256=QL4TGz0QQfsNakkgMkve9k8wiR73dfoOF2_18ESSPRE,33
10
10
  gooddata_flight_server/errors/error_code.py,sha256=s7wcNlsGKG0PSPXNMBMQMekViZeaoJKWVboEL12kogE,5808
11
- gooddata_flight_server/errors/error_info.py,sha256=blpMWCABxSj5j4mLuL7PW4mXKmWBeywKNMLp70WAd44,17599
11
+ gooddata_flight_server/errors/error_info.py,sha256=akYJk-QT0O2GQno__yc67YAxG5iBm-Fz4JDG2MQ6y4I,18852
12
12
  gooddata_flight_server/health/__init__.py,sha256=QL4TGz0QQfsNakkgMkve9k8wiR73dfoOF2_18ESSPRE,33
13
13
  gooddata_flight_server/health/health_check_http_server.py,sha256=A-wJ5L22s4PtJisNSOolrABp703w-0rhvDKKev_iN9I,3393
14
14
  gooddata_flight_server/health/server_health_monitor.py,sha256=vDe3Z5u5SPPG3RWGtrexzoJJ4HLFl7A38_hA6LfS71I,2690
@@ -24,26 +24,25 @@ gooddata_flight_server/server/auth/token_verifier_factory.py,sha256=P-ktBUcl7YNa
24
24
  gooddata_flight_server/server/auth/token_verifier_impl.py,sha256=F3phLqscCNFKOm3eF7w_KSfmM5_Nf9Kh5R9Rtr63eTU,1626
25
25
  gooddata_flight_server/server/flight_rpc/__init__.py,sha256=nfaUa69U3uZAB1udH6tza0se-3fhrsSurgPUQldoGnE,32
26
26
  gooddata_flight_server/server/flight_rpc/flight_middleware.py,sha256=Yb44PkgIL8MlYTGSPzHcnII6x9Hxlw5Y88YKeKIFeQI,5738
27
- gooddata_flight_server/server/flight_rpc/flight_server.py,sha256=mmdFTJwBw3dZhnYpDA9Txy9durOo3WOmlMvznv5-rBQ,8993
28
- gooddata_flight_server/server/flight_rpc/flight_service.py,sha256=N30rMsSjEqIgTHAARW_oiRz9AYvbm6GwRqR1jq9eP7E,10555
27
+ gooddata_flight_server/server/flight_rpc/flight_server.py,sha256=i1-HByn0_MhRG-d6qOCiwk29LDB4M0e7UZqPoatJYA0,8973
28
+ gooddata_flight_server/server/flight_rpc/flight_service.py,sha256=LqdZPl999_y1BXNB6GBNGEEdEDv0Y6guqa-Daqw_lgg,10522
29
29
  gooddata_flight_server/server/flight_rpc/server_methods.py,sha256=fCUndugFTlAUKG7rHpkmjQ_wkXIeRZty65WAeIhS1r0,7708
30
30
  gooddata_flight_server/tasks/__init__.py,sha256=QL4TGz0QQfsNakkgMkve9k8wiR73dfoOF2_18ESSPRE,33
31
31
  gooddata_flight_server/tasks/base.py,sha256=e_8sV9JROtXo4rhAWXKvaPbKjm5T_0iFQyXnfGtLLwg,593
32
32
  gooddata_flight_server/tasks/metrics.py,sha256=PY5FAp0lCEvsDX_xJNJ_soRZeTQ795OVh9CmBWSto7k,4085
33
33
  gooddata_flight_server/tasks/task.py,sha256=9Qzhssw53vnlUf5ULL1LsrMrjpG1jAbQBXOc1apHBH4,6485
34
34
  gooddata_flight_server/tasks/task_error.py,sha256=1Z2vJfRqRXaQk7fGMo2kGP9wLyxqngutjWyQIYpRNy8,2377
35
- gooddata_flight_server/tasks/task_executor.py,sha256=W7Ml5W1mIi_5L6C4a0c3YgDR1YGVQn48lXYGj_rRaKw,3728
35
+ gooddata_flight_server/tasks/task_executor.py,sha256=xNO4UcBfdgs8aWr4KF7GNjfpXH5xy305sYyCArqFMu0,4139
36
36
  gooddata_flight_server/tasks/task_result.py,sha256=1EqgP6xmhDDiWZYqJEOZxYZzUqAkRYF7ogsqNWAF4O4,12152
37
37
  gooddata_flight_server/tasks/temporal_container.py,sha256=biNEUOSmp3D6iVoGBZnHo88tALdIwkb-SzR5besKmNo,8503
38
- gooddata_flight_server/tasks/thread_task_executor.py,sha256=uWC7PX8FvPHfwkwPxqeUOr_BaHNb1CUXsQZcmjZAy0E,21949
38
+ gooddata_flight_server/tasks/thread_task_executor.py,sha256=QfluNnrm4LivPjfcXBJMyyUa-zX-EN65dnFayInd34A,22209
39
39
  gooddata_flight_server/utils/__init__.py,sha256=nfaUa69U3uZAB1udH6tza0se-3fhrsSurgPUQldoGnE,32
40
40
  gooddata_flight_server/utils/libc_utils.py,sha256=_ZwKeeB0lk2xh-gSC_7rc9felHu_hq9__GgLKZBI9sI,946
41
41
  gooddata_flight_server/utils/logging.py,sha256=3sip4Xte5YHjZNyQEQVo96rCsknxG1JPj7cIbnz0iBo,6081
42
42
  gooddata_flight_server/utils/methods_discovery.py,sha256=ZcBJU5dHBsnZD5zDXajE5merwCISfjHGcIlIWCQtNLY,3618
43
43
  gooddata_flight_server/utils/otel_tracing.py,sha256=MfKFh0TkVSUmPC6f8Oobp5XSCYxAsQyS0UaSJQF1nCw,4540
44
- gooddata_flight_server-1.34.0.data/scripts/gooddata-flight-server,sha256=cXl4cF_pNme_0ns-Dap825C_L-0ovWs9hmlNl7kN9kU,239
45
- gooddata_flight_server-1.34.0.dist-info/LICENSE.txt,sha256=o90MhGat28171lD8r77bLXsSnvDVu9CQAsWxAzx1Z2E,1064
46
- gooddata_flight_server-1.34.0.dist-info/METADATA,sha256=VLSBELJWAUvyUXZ0vCTj46q7Mt03mnb-6Ac34NruY-k,30237
47
- gooddata_flight_server-1.34.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
48
- gooddata_flight_server-1.34.0.dist-info/top_level.txt,sha256=fkhUrPUK9CeUzu3qMaEXJbY-HVuY-sqUx8ct7AtZH0s,23
49
- gooddata_flight_server-1.34.0.dist-info/RECORD,,
44
+ gooddata_flight_server-1.56.0.dist-info/METADATA,sha256=vAil4A3XK7f4mM5D3RX6UkgF1-ip3ziSSw4wwTADV78,29957
45
+ gooddata_flight_server-1.56.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
46
+ gooddata_flight_server-1.56.0.dist-info/entry_points.txt,sha256=uew4_TNofSLf7ppUmUNtD0o2KVDr-g_7Hl3D6Dsj71g,81
47
+ gooddata_flight_server-1.56.0.dist-info/licenses/LICENSE.txt,sha256=o90MhGat28171lD8r77bLXsSnvDVu9CQAsWxAzx1Z2E,1064
48
+ gooddata_flight_server-1.56.0.dist-info/RECORD,,
@@ -1,5 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
-
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ gooddata-flight-server = gooddata_flight_server.cli:server_cli
@@ -1,10 +0,0 @@
1
- #!python
2
- # (C) 2024 GoodData Corporation
3
- import re
4
- import sys
5
-
6
- import gooddata_flight_server.cli as server
7
-
8
- if __name__ == "__main__":
9
- sys.argv[0] = re.sub(r"(-script\.pyw?|\.exe)?$", "", sys.argv[0])
10
- sys.exit(server.server_cli())
@@ -1 +0,0 @@
1
- gooddata_flight_server