pytrilogy 0.0.3.23__tar.gz → 0.0.3.24__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 pytrilogy might be problematic. Click here for more details.

Files changed (133) hide show
  1. {pytrilogy-0.0.3.23/pytrilogy.egg-info → pytrilogy-0.0.3.24}/PKG-INFO +1 -1
  2. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24/pytrilogy.egg-info}/PKG-INFO +1 -1
  3. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_typing.py +71 -0
  4. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/__init__.py +1 -1
  5. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/environment_helpers.py +2 -2
  6. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/functions.py +0 -1
  7. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/models/author.py +7 -0
  8. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/models/build.py +9 -1
  9. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/models/core.py +5 -0
  10. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/models/environment.py +7 -0
  11. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/utility.py +2 -0
  12. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/dialect/base.py +4 -0
  13. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/parsing/parse_engine.py +11 -3
  14. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/LICENSE.md +0 -0
  15. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/README.md +0 -0
  16. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/pyproject.toml +0 -0
  17. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/pytrilogy.egg-info/SOURCES.txt +0 -0
  18. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/pytrilogy.egg-info/dependency_links.txt +0 -0
  19. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/pytrilogy.egg-info/entry_points.txt +0 -0
  20. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/pytrilogy.egg-info/requires.txt +0 -0
  21. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/pytrilogy.egg-info/top_level.txt +0 -0
  22. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/setup.cfg +0 -0
  23. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/setup.py +0 -0
  24. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_datatypes.py +0 -0
  25. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_declarations.py +0 -0
  26. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_derived_concepts.py +0 -0
  27. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_discovery_nodes.py +0 -0
  28. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_enums.py +0 -0
  29. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_environment.py +0 -0
  30. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_executor.py +0 -0
  31. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_functions.py +0 -0
  32. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_imports.py +0 -0
  33. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_metadata.py +0 -0
  34. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_models.py +0 -0
  35. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_multi_join_assignments.py +0 -0
  36. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_parse_engine.py +0 -0
  37. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_parsing.py +0 -0
  38. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_partial_handling.py +0 -0
  39. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_query_processing.py +0 -0
  40. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_query_render.py +0 -0
  41. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_select.py +0 -0
  42. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_show.py +0 -0
  43. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_statements.py +0 -0
  44. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_undefined_concept.py +0 -0
  45. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_user_functions.py +0 -0
  46. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/tests/test_where_clause.py +0 -0
  47. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/authoring/__init__.py +0 -0
  48. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/compiler.py +0 -0
  49. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/constants.py +0 -0
  50. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/__init__.py +0 -0
  51. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/constants.py +0 -0
  52. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/enums.py +0 -0
  53. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/env_processor.py +0 -0
  54. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/ergonomics.py +0 -0
  55. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/exceptions.py +0 -0
  56. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/graph_models.py +0 -0
  57. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/internal.py +0 -0
  58. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/models/__init__.py +0 -0
  59. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/models/build_environment.py +0 -0
  60. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/models/datasource.py +0 -0
  61. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/models/execute.py +0 -0
  62. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/optimization.py +0 -0
  63. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/optimizations/__init__.py +0 -0
  64. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/optimizations/base_optimization.py +0 -0
  65. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/optimizations/inline_constant.py +0 -0
  66. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/optimizations/inline_datasource.py +0 -0
  67. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/optimizations/predicate_pushdown.py +0 -0
  68. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/__init__.py +0 -0
  69. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/concept_strategies_v3.py +0 -0
  70. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/graph_utils.py +0 -0
  71. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/__init__.py +0 -0
  72. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/basic_node.py +0 -0
  73. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/common.py +0 -0
  74. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/filter_node.py +0 -0
  75. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/group_node.py +0 -0
  76. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/group_to_node.py +0 -0
  77. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/multiselect_node.py +0 -0
  78. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/node_merge_node.py +0 -0
  79. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/rowset_node.py +0 -0
  80. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
  81. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +0 -0
  82. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/select_merge_node.py +0 -0
  83. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/select_node.py +0 -0
  84. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/synonym_node.py +0 -0
  85. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/union_node.py +0 -0
  86. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/unnest_node.py +0 -0
  87. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/node_generators/window_node.py +0 -0
  88. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/nodes/__init__.py +0 -0
  89. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/nodes/base_node.py +0 -0
  90. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/nodes/filter_node.py +0 -0
  91. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/nodes/group_node.py +0 -0
  92. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/nodes/merge_node.py +0 -0
  93. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/nodes/select_node_v2.py +0 -0
  94. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/nodes/union_node.py +0 -0
  95. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/nodes/unnest_node.py +0 -0
  96. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/processing/nodes/window_node.py +0 -0
  97. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/query_processor.py +0 -0
  98. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/statements/__init__.py +0 -0
  99. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/statements/author.py +0 -0
  100. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/statements/build.py +0 -0
  101. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/statements/common.py +0 -0
  102. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/core/statements/execute.py +0 -0
  103. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/dialect/__init__.py +0 -0
  104. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/dialect/bigquery.py +0 -0
  105. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/dialect/common.py +0 -0
  106. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/dialect/config.py +0 -0
  107. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/dialect/dataframe.py +0 -0
  108. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/dialect/duckdb.py +0 -0
  109. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/dialect/enums.py +0 -0
  110. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/dialect/postgres.py +0 -0
  111. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/dialect/presto.py +0 -0
  112. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/dialect/snowflake.py +0 -0
  113. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/dialect/sql_server.py +0 -0
  114. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/engine.py +0 -0
  115. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/executor.py +0 -0
  116. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/hooks/__init__.py +0 -0
  117. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/hooks/base_hook.py +0 -0
  118. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/hooks/graph_hook.py +0 -0
  119. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/hooks/query_debugger.py +0 -0
  120. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/metadata/__init__.py +0 -0
  121. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/parser.py +0 -0
  122. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/parsing/__init__.py +0 -0
  123. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/parsing/common.py +0 -0
  124. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/parsing/config.py +0 -0
  125. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/parsing/exceptions.py +0 -0
  126. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/parsing/helpers.py +0 -0
  127. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/parsing/render.py +0 -0
  128. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/parsing/trilogy.lark +0 -0
  129. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/py.typed +0 -0
  130. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/render.py +0 -0
  131. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/scripts/__init__.py +0 -0
  132. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/scripts/trilogy.py +0 -0
  133. {pytrilogy-0.0.3.23 → pytrilogy-0.0.3.24}/trilogy/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.23
3
+ Version: 0.0.3.24
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.23
3
+ Version: 0.0.3.24
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -1,6 +1,25 @@
1
1
  from decimal import Decimal
2
+ from pathlib import Path
3
+
4
+ from pytest import raises
2
5
 
3
6
  from trilogy import Dialects
7
+ from trilogy.parsing.exceptions import ParseError
8
+
9
+ FILE = Path(__file__)
10
+
11
+
12
+ def test_invalid_typing():
13
+ env = Dialects.DUCK_DB.default_executor()
14
+ with raises(ParseError):
15
+ env.environment.parse(
16
+ """
17
+ key customer_id int;
18
+ property customer_id.email string::email;
19
+
20
+
21
+ """
22
+ )
4
23
 
5
24
 
6
25
  def test_typing():
@@ -44,6 +63,58 @@ customer_id,
44
63
  assert env.environment.concepts["email"].datatype.traits == ["email"]
45
64
 
46
65
 
66
+ def test_type_import_and_cast():
67
+ env = Dialects.DUCK_DB.default_executor()
68
+ env.environment.add_file_import(FILE.parent / "test_env_types.preql", "dtypes")
69
+ env.environment.parse(
70
+ """
71
+
72
+ type year int;
73
+ key customer_id int;
74
+ property customer_id.signup_date date;
75
+
76
+ datasource customers (
77
+ id:customer_id,
78
+ signup_date: signup_date
79
+ )
80
+ grain (customer_id)
81
+ query '''
82
+ select 1 as id, cast('2023-01-01' as date) as signup_date
83
+ union all
84
+ select 2 as id, cast('2023-01-02' as date) as signup_date
85
+ ''';
86
+
87
+ """
88
+ )
89
+ assert env.environment.concepts["signup_date"].keys == {"local.customer_id"}
90
+ assert env.environment.concepts["signup_date.year"].keys == {"local.signup_date"}
91
+ results = env.execute_query(
92
+ """SELECT
93
+ signup_date.year::int::year as signup_year;"""
94
+ )
95
+
96
+ for row in results.fetchall():
97
+ assert row.signup_year == 2023
98
+
99
+ assert "year" in env.environment.data_types
100
+
101
+ assert env.environment.concepts["signup_year"].datatype.traits == ["year"]
102
+
103
+ results = env.execute_query(
104
+ """SELECT
105
+ signup_date.year::int::dtypes.year as signup_year_two;"""
106
+ )
107
+
108
+ for row in results.fetchall():
109
+ assert row.signup_year_two == 2023
110
+
111
+ assert "dtypes.year" in env.environment.data_types
112
+
113
+ assert env.environment.concepts["signup_year_two"].datatype.traits == [
114
+ "dtypes.year"
115
+ ]
116
+
117
+
47
118
  def test_typing_aggregate():
48
119
  env = Dialects.DUCK_DB.default_executor()
49
120
  env.environment.parse(
@@ -4,6 +4,6 @@ from trilogy.dialect.enums import Dialects
4
4
  from trilogy.executor import Executor
5
5
  from trilogy.parser import parse
6
6
 
7
- __version__ = "0.0.3.23"
7
+ __version__ = "0.0.3.24"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -54,7 +54,7 @@ def generate_date_concepts(concept: Concept, environment: Environment):
54
54
  grain=concept.grain,
55
55
  namespace=concept.namespace,
56
56
  keys=set(
57
- concept.address,
57
+ [concept.address],
58
58
  ),
59
59
  metadata=Metadata(
60
60
  description=f"Auto-derived from {base_description}. {FUNCTION_DESCRIPTION_MAPS.get(ftype, ftype.value)}. ",
@@ -102,7 +102,7 @@ def generate_datetime_concepts(concept: Concept, environment: Environment):
102
102
  grain=concept.grain,
103
103
  namespace=concept.namespace,
104
104
  keys=set(
105
- concept.address,
105
+ [concept.address],
106
106
  ),
107
107
  metadata=Metadata(
108
108
  description=f"Auto-derived from {base_description}. {FUNCTION_DESCRIPTION_MAPS.get(ftype, ftype.value)}.",
@@ -717,7 +717,6 @@ class FunctionFactory:
717
717
  output_purpose = Purpose.METRIC
718
718
  else:
719
719
  output_purpose = Purpose.PROPERTY
720
-
721
720
  return Function(
722
721
  operator=operator,
723
722
  arguments=full_args,
@@ -1035,6 +1035,7 @@ class Concept(Addressable, DataTyped, ConceptArgs, Mergeable, Namespaced, BaseMo
1035
1035
  pkeys.update(parent_keys)
1036
1036
  raw_keys = pkeys
1037
1037
  # deduplicate
1038
+
1038
1039
  final_grain = Grain.from_concepts(raw_keys, environment)
1039
1040
  keys = final_grain.components
1040
1041
  return new_lineage, final_grain, keys
@@ -2244,6 +2245,11 @@ class CustomType(BaseModel):
2244
2245
  name: str
2245
2246
  type: DataType
2246
2247
 
2248
+ def with_namespace(self, namespace: str) -> "CustomType":
2249
+ return CustomType.model_construct(
2250
+ name=address_with_namespace(self.name, namespace), type=self.type
2251
+ )
2252
+
2247
2253
 
2248
2254
  Expr = (
2249
2255
  MagicConstants
@@ -2284,6 +2290,7 @@ FuncArgs = (
2284
2290
  | date
2285
2291
  | datetime
2286
2292
  | MapWrapper[Any, Any]
2293
+ | TraitDataType
2287
2294
  | DataType
2288
2295
  | ListType
2289
2296
  | MapType
@@ -77,6 +77,7 @@ from trilogy.core.models.core import (
77
77
  MapWrapper,
78
78
  NumericType,
79
79
  StructType,
80
+ TraitDataType,
80
81
  TupleWrapper,
81
82
  arg_to_datatype,
82
83
  )
@@ -1066,7 +1067,9 @@ class BuildFunction(DataTyped, BuildConceptArgs, BaseModel):
1066
1067
  # class BuildFunction(Function):
1067
1068
  operator: FunctionType
1068
1069
  arg_count: int = Field(default=1)
1069
- output_datatype: DataType | ListType | StructType | MapType | NumericType
1070
+ output_datatype: (
1071
+ DataType | ListType | StructType | MapType | NumericType | TraitDataType
1072
+ )
1070
1073
  output_purpose: Purpose
1071
1074
  valid_inputs: Optional[
1072
1075
  Union[
@@ -1082,6 +1085,7 @@ class BuildFunction(DataTyped, BuildConceptArgs, BaseModel):
1082
1085
  date,
1083
1086
  datetime,
1084
1087
  MapWrapper[Any, Any],
1088
+ TraitDataType,
1085
1089
  DataType,
1086
1090
  ListType,
1087
1091
  MapType,
@@ -1873,6 +1877,10 @@ class Factory:
1873
1877
  new.gen_concept_list_caches()
1874
1878
  return new
1875
1879
 
1880
+ @build.register
1881
+ def _(self, base: TraitDataType):
1882
+ return base
1883
+
1876
1884
  @build.register
1877
1885
  def _(self, base: Datasource):
1878
1886
  local_cache: dict[str, BuildConcept] = {}
@@ -111,6 +111,9 @@ class TraitDataType(BaseModel):
111
111
  def __hash__(self):
112
112
  return hash(self.type)
113
113
 
114
+ def __str__(self) -> str:
115
+ return f"Trait<{self.type}, {self.traits}>"
116
+
114
117
  def __eq__(self, other):
115
118
  if isinstance(other, DataType):
116
119
  return self.type == other
@@ -382,6 +385,8 @@ def arg_to_datatype(arg) -> CONCRETE_TYPES:
382
385
  return DataType.FLOAT
383
386
  elif isinstance(arg, NumericType):
384
387
  return arg
388
+ elif isinstance(arg, TraitDataType):
389
+ return arg
385
390
  elif isinstance(arg, ListWrapper):
386
391
  return ListType(type=arg.type)
387
392
  elif isinstance(arg, DataTyped):
@@ -442,6 +442,13 @@ class Environment(BaseModel):
442
442
  self.functions[address_with_namespace(key, alias)] = (
443
443
  function.with_namespace(alias)
444
444
  )
445
+ for key, type in source.data_types.items():
446
+ if same_namespace:
447
+ self.data_types[key] = type
448
+ else:
449
+ self.data_types[address_with_namespace(key, alias)] = (
450
+ type.with_namespace(alias)
451
+ )
445
452
  return self
446
453
 
447
454
  def add_file_import(
@@ -38,6 +38,7 @@ from trilogy.core.models.core import (
38
38
  MapType,
39
39
  MapWrapper,
40
40
  NumericType,
41
+ TraitDataType,
41
42
  TupleWrapper,
42
43
  )
43
44
  from trilogy.core.models.execute import (
@@ -441,6 +442,7 @@ def is_scalar_condition(
441
442
  | BuildCaseWhen
442
443
  | BuildCaseElse
443
444
  | MagicConstants
445
+ | TraitDataType
444
446
  | DataType
445
447
  | MapWrapper[Any, Any]
446
448
  | ListType
@@ -36,6 +36,7 @@ from trilogy.core.models.core import (
36
36
  MapWrapper,
37
37
  NumericType,
38
38
  StructType,
39
+ TraitDataType,
39
40
  TupleWrapper,
40
41
  )
41
42
  from trilogy.core.models.datasource import Datasource, RawColumnExpr
@@ -510,6 +511,7 @@ class BaseDialect:
510
511
  date,
511
512
  datetime,
512
513
  DataType,
514
+ TraitDataType,
513
515
  MagicConstants,
514
516
  MapWrapper[Any, Any],
515
517
  MapType,
@@ -677,6 +679,8 @@ class BaseDialect:
677
679
  return self.FUNCTION_MAP[FunctionType.DATE_LITERAL](e)
678
680
  elif isinstance(e, datetime):
679
681
  return self.FUNCTION_MAP[FunctionType.DATETIME_LITERAL](e)
682
+ elif isinstance(e, TraitDataType):
683
+ return self.DATATYPE_MAP.get(e.type, e.type.value)
680
684
  else:
681
685
  raise ValueError(f"Unable to render type {type(e)} {e}")
682
686
 
@@ -443,8 +443,9 @@ class ParseToObjects(Transformer):
443
443
  def map_type(self, args) -> MapType:
444
444
  return MapType(key_type=args[0], value_type=args[1])
445
445
 
446
+ @v_args(meta=True)
446
447
  def data_type(
447
- self, args
448
+ self, meta: Meta, args
448
449
  ) -> DataType | TraitDataType | ListType | StructType | MapType | NumericType:
449
450
  resolved = args[0]
450
451
  traits = args[2:]
@@ -458,7 +459,13 @@ class ParseToObjects(Transformer):
458
459
  return resolved
459
460
  base = DataType(args[0].lower())
460
461
  if traits:
462
+ for trait in traits:
463
+ if trait not in self.environment.data_types:
464
+ raise ParseError(
465
+ f"Invalid type trait {trait} for {base}, line {meta.line}"
466
+ )
461
467
  return TraitDataType(type=base, traits=traits)
468
+
462
469
  return base
463
470
 
464
471
  def array_comparison(self, args) -> ComparisonOperator:
@@ -1238,8 +1245,9 @@ class ParseToObjects(Transformer):
1238
1245
  def type_declaration(self, meta: Meta, args) -> TypeDeclaration:
1239
1246
  key = args[0]
1240
1247
  datatype = args[1]
1241
- self.environment.data_types[key] = datatype
1242
- return TypeDeclaration(type=CustomType(name=key, type=datatype))
1248
+ new = CustomType(name=key, type=datatype)
1249
+ self.environment.data_types[key] = new
1250
+ return TypeDeclaration(type=new)
1243
1251
 
1244
1252
  def int_lit(self, args):
1245
1253
  return int("".join(args))
File without changes
File without changes
File without changes
File without changes