tracdap-runtime 0.8.0b3__py3-none-any.whl → 0.8.0rc1__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.
Files changed (40) hide show
  1. tracdap/rt/_impl/core/config_parser.py +55 -37
  2. tracdap/rt/_impl/core/data.py +63 -32
  3. tracdap/rt/_impl/core/storage.py +4 -1
  4. tracdap/rt/_impl/core/struct.py +547 -0
  5. tracdap/rt/_impl/core/type_system.py +73 -33
  6. tracdap/rt/_impl/core/validation.py +56 -15
  7. tracdap/rt/_impl/exec/context.py +64 -10
  8. tracdap/rt/_impl/exec/dev_mode.py +25 -14
  9. tracdap/rt/_impl/exec/functions.py +79 -29
  10. tracdap/rt/_impl/grpc/codec.py +1 -1
  11. tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2.py +2 -2
  12. tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2_grpc.py +1 -1
  13. tracdap/rt/_impl/grpc/tracdap/metadata/data_pb2.py +31 -19
  14. tracdap/rt/_impl/grpc/tracdap/metadata/data_pb2.pyi +48 -2
  15. tracdap/rt/_impl/grpc/tracdap/metadata/object_pb2.py +2 -2
  16. tracdap/rt/_impl/grpc/tracdap/metadata/object_pb2.pyi +3 -3
  17. tracdap/rt/_impl/grpc/tracdap/metadata/{stoarge_pb2.py → storage_pb2.py} +3 -3
  18. tracdap/rt/_impl/static_api.py +9 -1
  19. tracdap/rt/_plugins/storage_sql.py +12 -5
  20. tracdap/rt/_version.py +1 -1
  21. tracdap/rt/api/__init__.py +1 -23
  22. tracdap/rt/api/constants.py +57 -0
  23. tracdap/rt/api/experimental.py +32 -0
  24. tracdap/rt/api/hook.py +11 -0
  25. tracdap/rt/api/static_api.py +54 -2
  26. tracdap/rt/config/__init__.py +1 -4
  27. tracdap/rt/config/common.py +0 -34
  28. tracdap/rt/config/platform.py +6 -26
  29. tracdap/rt/metadata/__init__.py +31 -29
  30. tracdap/rt/metadata/data.py +40 -0
  31. tracdap/rt/metadata/file.py +2 -0
  32. tracdap/rt/metadata/object.py +1 -1
  33. {tracdap_runtime-0.8.0b3.dist-info → tracdap_runtime-0.8.0rc1.dist-info}/METADATA +17 -14
  34. {tracdap_runtime-0.8.0b3.dist-info → tracdap_runtime-0.8.0rc1.dist-info}/RECORD +39 -38
  35. {tracdap_runtime-0.8.0b3.dist-info → tracdap_runtime-0.8.0rc1.dist-info}/WHEEL +1 -1
  36. tracdap/rt/api/file_types.py +0 -29
  37. /tracdap/rt/_impl/grpc/tracdap/metadata/{stoarge_pb2.pyi → storage_pb2.pyi} +0 -0
  38. /tracdap/rt/metadata/{stoarge.py → storage.py} +0 -0
  39. {tracdap_runtime-0.8.0b3.dist-info → tracdap_runtime-0.8.0rc1.dist-info}/LICENSE +0 -0
  40. {tracdap_runtime-0.8.0b3.dist-info → tracdap_runtime-0.8.0rc1.dist-info}/top_level.txt +0 -0
@@ -70,6 +70,8 @@ PANDAS = DataFramework.pandas()
70
70
  POLARS = DataFramework.polars()
71
71
  """Data framework constant for the Polars data library"""
72
72
 
73
+ STRUCT_TYPE = _tp.TypeVar('STRUCT_TYPE')
74
+
73
75
 
74
76
  class TracContext(TracContext):
75
77
 
@@ -83,6 +85,14 @@ class TracContext(TracContext):
83
85
 
84
86
  pass
85
87
 
88
+ def get_struct(self, struct_name: str, python_class: _tp.Type[STRUCT_TYPE]) -> STRUCT_TYPE:
89
+
90
+ pass
91
+
92
+ def put_struct(self, struct_name: str, struct_data: STRUCT_TYPE):
93
+
94
+ pass
95
+
86
96
 
87
97
  def init_static():
88
98
  """Ensure TRAC's static model API is available to use (for static definitions at module or class scope)"""
@@ -108,6 +118,28 @@ def map_type(entry_type: BasicType) -> TypeDescriptor:
108
118
  return sa.map_type(entry_type)
109
119
 
110
120
 
121
+ def define_struct(python_type: _tp.Type[STRUCT_TYPE]) -> SchemaDefinition:
122
+ """Build schema definition for a STRUCT"""
123
+ sa = _StaticApiHook.get_instance()
124
+ return sa.define_struct(python_type)
125
+
126
+ def define_input_struct(
127
+ python_type: _tp.Type[STRUCT_TYPE], *,
128
+ label: _tp.Optional[str] = None, optional: bool = False,
129
+ input_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) -> ModelInputSchema:
130
+
131
+ schema = define_struct(python_type)
132
+ return define_input(schema, label=label, optional=optional, input_props=input_props)
133
+
134
+ def define_output_struct(
135
+ python_type: _tp.Type[STRUCT_TYPE], *,
136
+ label: _tp.Optional[str] = None, optional: bool = False,
137
+ output_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) -> ModelOutputSchema:
138
+
139
+ schema = define_struct(python_type)
140
+ return define_output(schema, label=label, optional=optional, output_props=output_props)
141
+
142
+
111
143
  class FileType(_enum.Enum):
112
144
 
113
145
  FILE = 1
tracdap/rt/api/hook.py CHANGED
@@ -121,6 +121,11 @@ class _StaticApiHook:
121
121
 
122
122
  pass
123
123
 
124
+ @_abc.abstractmethod
125
+ def define_struct(self, python_type: type) -> _meta.SchemaDefinition:
126
+
127
+ pass
128
+
124
129
  @_abc.abstractmethod
125
130
  def load_schema(
126
131
  self, package: _tp.Union[_ts.ModuleType, str], schema_file: str,
@@ -158,3 +163,9 @@ class _StaticApiHook:
158
163
  -> _meta.ModelOutputSchema:
159
164
 
160
165
  pass
166
+
167
+ X = _tp.TypeVar("X")
168
+
169
+ def do_x(x: type[X]) -> X:
170
+
171
+ return x.__new__(x)
@@ -384,6 +384,14 @@ def load_schema(
384
384
 
385
385
  def define_file_type(extension: str, mime_type: str) -> FileType:
386
386
 
387
+ """
388
+ Define a :py:class:`FileType <tracdap.rt.metadata.FileType>` for use as a model input or output
389
+
390
+ :type extension: str
391
+ :type mime_type: str
392
+ :rtype: :py:class:`FileType <tracdap.rt.metadata.FileType>`
393
+ """
394
+
387
395
  sa = _StaticApiHook.get_instance()
388
396
  return sa.define_file_type(extension, mime_type)
389
397
 
@@ -394,6 +402,17 @@ def define_input(
394
402
  optional: bool = False, dynamic: bool = False,
395
403
  input_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None):
396
404
 
405
+ """
406
+ Define a model input, which can be any type of dataset or file
407
+
408
+ :type requirement: :py:class:`SchemaDefinition <tracdap.rt.metadata.SchemaDefinition>` | :py:class:`FileType <tracdap.rt.metadata.FileType>`
409
+ :type label: str | None
410
+ :type optional: bool
411
+ :type dynamic: bool
412
+ :type input_props: dict[str, :py:class:`Value <tracdap.rt.metadata.Value>`
413
+ :rtype: :py:class:`ModelInputSchema <tracdap.rt.metadata.ModelInputSchema>`
414
+ """
415
+
397
416
  sa = _StaticApiHook.get_instance()
398
417
  return sa.define_input(requirement, label=label, optional=optional, dynamic=dynamic, input_props=input_props)
399
418
 
@@ -404,6 +423,17 @@ def define_output(
404
423
  optional: bool = False, dynamic: bool = False,
405
424
  output_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None):
406
425
 
426
+ """
427
+ Define a model output, which can be any type of dataset or file
428
+
429
+ :type requirement: :py:class:`SchemaDefinition <tracdap.rt.metadata.SchemaDefinition>` | :py:class:`FileType <tracdap.rt.metadata.FileType>`
430
+ :type label: str | None
431
+ :type optional: bool
432
+ :type dynamic: bool
433
+ :type output_props: dict[str, :py:class:`Value <tracdap.rt.metadata.Value>`
434
+ :rtype: :py:class:`ModelOutputSchema <tracdap.rt.metadata.ModelOutputSchema>`
435
+ """
436
+
407
437
  sa = _StaticApiHook.get_instance()
408
438
  return sa.define_output(requirement, label=label, optional=optional, dynamic=dynamic, output_props=output_props)
409
439
 
@@ -415,7 +445,7 @@ def define_input_table(
415
445
  -> ModelInputSchema:
416
446
 
417
447
  """
418
- Define a model input with a table schema
448
+ Define a model input for a :py:class:`TableSchema <tracdap.rt.metadata.TableSchema>`
419
449
 
420
450
  Individual fields can be defined using :py:func:`define_field` or the shorthand alias :py:func:`F`.
421
451
  This function takes a number of fields, either as individual arguments or as a list, and uses them
@@ -460,7 +490,7 @@ def define_output_table(
460
490
  -> ModelOutputSchema:
461
491
 
462
492
  """
463
- Define a model output with a table schema
493
+ Define a model output for a :py:class:`TableSchema <tracdap.rt.metadata.TableSchema>`
464
494
 
465
495
  Individual fields can be defined using :py:func:`define_field` or the shorthand alias :py:func:`F`.
466
496
  This function takes a number of fields, either as individual arguments or as a list, and uses them
@@ -502,6 +532,17 @@ def define_input_file(
502
532
  input_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
503
533
  -> ModelInputSchema:
504
534
 
535
+ """
536
+ Define a model input for a :py:class:`FileType <tracdap.rt.metadata.FileType>`
537
+
538
+ :type extension str
539
+ :type mime_type: sr
540
+ :type label: str | None
541
+ :type optional: bool
542
+ :type input_props: dict[str, Any] | None
543
+ :rtype: :py:class:`ModelInputSchema <tracdap.rt.metadata.ModelInputSchema>`
544
+ """
545
+
505
546
  file_type = define_file_type(extension, mime_type)
506
547
  return define_input(file_type, label=label, optional=optional, input_props=input_props)
507
548
 
@@ -512,6 +553,17 @@ def define_output_file(
512
553
  output_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
513
554
  -> ModelOutputSchema:
514
555
 
556
+ """
557
+ Define a model output for a :py:class:`FileType <tracdap.rt.metadata.FileType>`
558
+
559
+ :type extension str
560
+ :type mime_type: sr
561
+ :type label: str | None
562
+ :type optional: bool
563
+ :type output_props: dict[str, Any] | None
564
+ :rtype: :py:class:`ModelOutputSchema <tracdap.rt.metadata.ModelOutputSchema>`
565
+ """
566
+
515
567
  file_type = define_file_type(extension, mime_type)
516
568
  return define_output(file_type, label=label, optional=optional, output_props=output_props)
517
569
 
@@ -5,7 +5,6 @@ from .job import JobConfig
5
5
  from .common import _ConfigFile
6
6
  from .common import PluginConfig
7
7
  from .common import PlatformInfo
8
- from .common import AuthenticationConfig
9
8
  from .common import StorageConfig
10
9
  from .common import ServiceConfig
11
10
 
@@ -17,10 +16,8 @@ from .platform import DeploymentLayout
17
16
  from .platform import PlatformConfig
18
17
  from .platform import MetadataConfig
19
18
  from .platform import TenantConfig
20
- from .platform import WebServerConfig
21
- from .platform import WebServerRewriteRule
22
- from .platform import WebServerRedirect
23
19
  from .platform import GatewayConfig
20
+ from .platform import GatewayRedirect
24
21
  from .platform import RouteConfig
25
22
  from .platform import RoutingMatch
26
23
  from .platform import RoutingTarget
@@ -33,40 +33,6 @@ class PlatformInfo:
33
33
  deploymentInfo: "_tp.Dict[str, str]" = _dc.field(default_factory=dict)
34
34
 
35
35
 
36
- @_dc.dataclass
37
- class AuthenticationConfig:
38
-
39
- jwtIssuer: "str" = ""
40
-
41
- jwtExpiry: "int" = 0
42
-
43
- jwtLimit: "int" = 0
44
-
45
- jwtRefresh: "int" = 0
46
-
47
- provider: "PluginConfig" = _dc.field(default_factory=lambda: PluginConfig())
48
-
49
- loginPath: "_tp.Optional[str]" = None
50
-
51
- refreshPath: "_tp.Optional[str]" = None
52
-
53
- returnPath: "_tp.Optional[str]" = None
54
-
55
- disableAuth: "bool" = False
56
-
57
- disableSigning: "bool" = False
58
-
59
- systemUserId: "str" = ""
60
-
61
- systemUserName: "str" = ""
62
-
63
- systemTicketDuration: "int" = 0
64
-
65
- systemTicketRefresh: "int" = 0
66
-
67
- externalSystems: "_tp.Dict[str, PluginConfig]" = _dc.field(default_factory=dict)
68
-
69
-
70
36
  @_dc.dataclass
71
37
  class StorageConfig:
72
38
 
@@ -39,8 +39,6 @@ class PlatformConfig:
39
39
 
40
40
  platformInfo: "PlatformInfo" = _dc.field(default_factory=lambda: PlatformInfo())
41
41
 
42
- authentication: "AuthenticationConfig" = _dc.field(default_factory=lambda: AuthenticationConfig())
43
-
44
42
  metadata: "MetadataConfig" = _dc.field(default_factory=lambda: MetadataConfig())
45
43
 
46
44
  storage: "StorageConfig" = _dc.field(default_factory=lambda: StorageConfig())
@@ -53,8 +51,6 @@ class PlatformConfig:
53
51
 
54
52
  tenants: "_tp.Dict[str, TenantConfig]" = _dc.field(default_factory=dict)
55
53
 
56
- webServer: "WebServerConfig" = _dc.field(default_factory=lambda: WebServerConfig())
57
-
58
54
  gateway: "GatewayConfig" = _dc.field(default_factory=lambda: GatewayConfig())
59
55
 
60
56
  services: "_tp.Dict[str, ServiceConfig]" = _dc.field(default_factory=dict)
@@ -63,6 +59,8 @@ class PlatformConfig:
63
59
 
64
60
  clientConfig: "_tp.Dict[str, ClientConfig]" = _dc.field(default_factory=dict)
65
61
 
62
+ extensions: "_tp.Dict[str, protobuf.Any]" = _dc.field(default_factory=dict)
63
+
66
64
 
67
65
  @_dc.dataclass
68
66
  class MetadataConfig:
@@ -81,25 +79,15 @@ class TenantConfig:
81
79
 
82
80
 
83
81
  @_dc.dataclass
84
- class WebServerConfig:
85
-
86
- contentRoot: "PluginConfig" = _dc.field(default_factory=lambda: PluginConfig())
87
-
88
- rewriteRules: "_tp.List[WebServerRewriteRule]" = _dc.field(default_factory=list)
89
-
90
- redirects: "_tp.List[WebServerRedirect]" = _dc.field(default_factory=list)
91
-
92
-
93
- @_dc.dataclass
94
- class WebServerRewriteRule:
82
+ class GatewayConfig:
95
83
 
96
- source: "str" = ""
84
+ routes: "_tp.List[RouteConfig]" = _dc.field(default_factory=list)
97
85
 
98
- target: "str" = ""
86
+ redirects: "_tp.List[GatewayRedirect]" = _dc.field(default_factory=list)
99
87
 
100
88
 
101
89
  @_dc.dataclass
102
- class WebServerRedirect:
90
+ class GatewayRedirect:
103
91
 
104
92
  source: "str" = ""
105
93
 
@@ -108,14 +96,6 @@ class WebServerRedirect:
108
96
  status: "int" = 0
109
97
 
110
98
 
111
- @_dc.dataclass
112
- class GatewayConfig:
113
-
114
- routes: "_tp.List[RouteConfig]" = _dc.field(default_factory=list)
115
-
116
- redirects: "_tp.List[WebServerRedirect]" = _dc.field(default_factory=list)
117
-
118
-
119
99
  @_dc.dataclass
120
100
  class RouteConfig:
121
101
 
@@ -9,14 +9,39 @@ from .type import Value
9
9
  from .type import ArrayValue
10
10
  from .type import MapValue
11
11
 
12
+ from .tag_update import TagOperation
13
+ from .tag_update import TagUpdate
14
+
12
15
  from .object_id import ObjectType
13
16
  from .object_id import TagHeader
14
17
  from .object_id import TagSelector
15
18
 
19
+ from .job import JobType
20
+ from .job import JobStatusCode
21
+ from .job import JobGroupType
22
+ from .job import JobDefinition
23
+ from .job import ResultDefinition
24
+ from .job import RunModelJob
25
+ from .job import RunFlowJob
26
+ from .job import ImportModelJob
27
+ from .job import ImportDataJob
28
+ from .job import ExportDataJob
29
+ from .job import JobGroup
30
+ from .job import SequentialJobGroup
31
+ from .job import ParallelJobGroup
32
+
33
+ from .common import MetadataFormat
34
+ from .common import MetadataVersion
35
+ from .common import TenantInfo
36
+
37
+ from .custom import CustomDefinition
38
+
16
39
  from .data import SchemaType
17
40
  from .data import PartType
18
41
  from .data import FieldSchema
19
42
  from .data import TableSchema
43
+ from .data import StructField
44
+ from .data import StructSchema
20
45
  from .data import SchemaDefinition
21
46
  from .data import PartKey
22
47
  from .data import DataDefinition
@@ -37,41 +62,18 @@ from .search import LogicalExpression
37
62
  from .search import SearchExpression
38
63
  from .search import SearchParameters
39
64
 
40
- from .tag_update import TagOperation
41
- from .tag_update import TagUpdate
42
-
43
65
  from .flow import FlowNodeType
44
66
  from .flow import FlowNode
45
67
  from .flow import FlowSocket
46
68
  from .flow import FlowEdge
47
69
  from .flow import FlowDefinition
48
70
 
49
- from .job import JobType
50
- from .job import JobStatusCode
51
- from .job import JobGroupType
52
- from .job import JobDefinition
53
- from .job import ResultDefinition
54
- from .job import RunModelJob
55
- from .job import RunFlowJob
56
- from .job import ImportModelJob
57
- from .job import ImportDataJob
58
- from .job import ExportDataJob
59
- from .job import JobGroup
60
- from .job import SequentialJobGroup
61
- from .job import ParallelJobGroup
62
-
63
- from .common import MetadataFormat
64
- from .common import MetadataVersion
65
- from .common import TenantInfo
66
-
67
- from .stoarge import CopyStatus
68
- from .stoarge import IncarnationStatus
69
- from .stoarge import StorageCopy
70
- from .stoarge import StorageIncarnation
71
- from .stoarge import StorageItem
72
- from .stoarge import StorageDefinition
73
-
74
- from .custom import CustomDefinition
71
+ from .storage import CopyStatus
72
+ from .storage import IncarnationStatus
73
+ from .storage import StorageCopy
74
+ from .storage import StorageIncarnation
75
+ from .storage import StorageItem
76
+ from .storage import StorageDefinition
75
77
 
76
78
  from .object import ObjectDefinition
77
79
 
@@ -25,6 +25,10 @@ class SchemaType(_enum.Enum):
25
25
 
26
26
  """Tabular data"""
27
27
 
28
+ STRUCT = 2
29
+
30
+ """Structured objects"""
31
+
28
32
 
29
33
  class PartType(_enum.Enum):
30
34
 
@@ -80,6 +84,40 @@ class TableSchema:
80
84
  fields: "_tp.List[FieldSchema]" = _dc.field(default_factory=list)
81
85
 
82
86
 
87
+ @_dc.dataclass
88
+ class StructField:
89
+
90
+ """Schema for an individual field in a structured object dataset"""
91
+
92
+ fieldType: "TypeDescriptor" = _dc.field(default_factory=lambda: TypeDescriptor())
93
+
94
+ label: "str" = ""
95
+
96
+ businessKey: "bool" = False
97
+
98
+ categorical: "bool" = False
99
+
100
+ notNull: "_tp.Optional[bool]" = None
101
+
102
+ """This could become mandatory with the next metadata update"""
103
+
104
+ formatCode: "_tp.Optional[str]" = None
105
+
106
+ defaultValue: "Value" = _dc.field(default_factory=lambda: Value())
107
+
108
+ structType: "_tp.Optional[str]" = None
109
+
110
+
111
+ @_dc.dataclass
112
+ class StructSchema:
113
+
114
+ """Schema for a structured object dataset"""
115
+
116
+ fields: "_tp.Dict[str, StructField]" = _dc.field(default_factory=dict)
117
+
118
+ namedTypes: "_tp.Dict[str, StructSchema]" = _dc.field(default_factory=dict)
119
+
120
+
83
121
  @_dc.dataclass
84
122
  class SchemaDefinition:
85
123
 
@@ -103,6 +141,8 @@ class SchemaDefinition:
103
141
 
104
142
  table: "_tp.Optional[TableSchema]" = None
105
143
 
144
+ struct: "_tp.Optional[StructSchema]" = None
145
+
106
146
 
107
147
  @_dc.dataclass
108
148
  class PartKey:
@@ -29,6 +29,8 @@ class FileDefinition:
29
29
  @_dc.dataclass
30
30
  class FileType:
31
31
 
32
+ """Specify a file type that is produced or consumed by a model, flow or job"""
33
+
32
34
  extension: "str" = ""
33
35
 
34
36
  mimeType: "str" = ""
@@ -12,7 +12,7 @@ from .flow import * # noqa
12
12
  from .job import * # noqa
13
13
  from .file import * # noqa
14
14
  from .custom import * # noqa
15
- from .stoarge import * # noqa
15
+ from .storage import * # noqa
16
16
 
17
17
 
18
18
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tracdap-runtime
3
- Version: 0.8.0b3
3
+ Version: 0.8.0rc1
4
4
  Summary: Runtime package for building models on the TRAC Data & Analytics Platform
5
5
  Home-page: https://tracdap.finos.org/
6
6
  Author: Martin Traverse
@@ -13,19 +13,20 @@ Platform: any
13
13
  Classifier: Programming Language :: Python :: 3
14
14
  Classifier: License :: OSI Approved :: Apache Software License
15
15
  Classifier: Operating System :: OS Independent
16
- Requires-Python: <3.13,>=3.8
16
+ Requires-Python: <3.14,>=3.9
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: protobuf==5.28.2
20
- Requires-Dist: pyarrow==16.1.0
19
+ Requires-Dist: protobuf==5.29.3
20
+ Requires-Dist: pyarrow==18.1.0
21
21
  Requires-Dist: pyyaml==6.0.2
22
- Requires-Dist: dulwich==0.22.1
22
+ Requires-Dist: dulwich==0.22.7
23
23
  Requires-Dist: requests==2.32.3
24
- Requires-Dist: pandas<2.3.0,>=1.2.0
25
- Requires-Dist: numpy<2.0.0
26
24
  Provides-Extra: grpc
27
- Requires-Dist: grpcio==1.66.1; extra == "grpc"
28
- Requires-Dist: grpcio-status==1.66.1; extra == "grpc"
25
+ Requires-Dist: grpcio==1.70.0; extra == "grpc"
26
+ Requires-Dist: grpcio-status==1.70.0; extra == "grpc"
27
+ Provides-Extra: pandas
28
+ Requires-Dist: pandas<2.3.0,>=1.2.0; extra == "pandas"
29
+ Requires-Dist: numpy<2.3.0,>=1.20; extra == "pandas"
29
30
  Provides-Extra: polars
30
31
  Requires-Dist: polars<2.0.0,>=1.0.0; extra == "polars"
31
32
  Provides-Extra: pyspark
@@ -64,12 +65,14 @@ Documentation for the TRAC platform is available on our website at
64
65
 
65
66
  The TRAC runtime for Python has these requirements:
66
67
 
67
- * Python: 3.8 up to 3.12
68
- * Pandas: 1.2 up to 2.2
69
- * PySpark 3.0 up to 3.5 (optional)
68
+ * Python: 3.9 up to 3.13
69
+ * Pandas: 1.2 up to 2.2 (optional)
70
+ * NumPy: 1.2 up to 2.2 (optional, required by Pandas)
71
+ * Polars: 1.X (optional)
70
72
 
71
- 3rd party libraries may impose additional constraints on supported versions of Python, Pandas or PySpark.
72
- As of February 2024, the Python libraries for GCP do not yet support Python 3.12.
73
+ 3rd party libraries may impose additional constraints on supported versions of key libraries.
74
+ For example, Pandas 1.5 is not available for Python 3.12 or 3.13, while NumPy 2.0 is only
75
+ compatible with Pandas 2.1 and later.
73
76
 
74
77
  ## Installing the runtime
75
78