pytrilogy 0.0.3.100__py3-none-any.whl → 0.0.3.101__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 pytrilogy might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytrilogy
3
- Version: 0.0.3.100
3
+ Version: 0.0.3.101
4
4
  Summary: Declarative, typed query language that compiles to SQL.
5
5
  Home-page:
6
6
  Author:
@@ -1,5 +1,5 @@
1
- pytrilogy-0.0.3.100.dist-info/licenses/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
2
- trilogy/__init__.py,sha256=g9zY8214LmrIQyjxs_q4DVvbSXccQFQwFe0o0_PZcD8,304
1
+ pytrilogy-0.0.3.101.dist-info/licenses/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
2
+ trilogy/__init__.py,sha256=NMiEE_jE99ZiREk8IPjfT2M-jxAwtmd2vyCWVD3kT28,304
3
3
  trilogy/constants.py,sha256=ohmro6so7PPNp2ruWQKVc0ijjXYPOyRrxB9LI8dr3TU,1746
4
4
  trilogy/engine.py,sha256=3MiADf5MKcmxqiHBuRqiYdsXiLj7oitDfVvXvHrfjkA,2178
5
5
  trilogy/executor.py,sha256=KgCAQhHPT-j0rPkBbALX0f84W9-Q-bkjHayGuavg99w,16490
@@ -14,8 +14,8 @@ trilogy/core/enums.py,sha256=H8I2Dz4POHZ4ixYCGzNs4c3KDqxLQklGLVfmje1DSMo,8877
14
14
  trilogy/core/env_processor.py,sha256=H-rr2ALj31l5oh3FqeI47Qju6OOfiXBacXNJGNZ92zQ,4521
15
15
  trilogy/core/environment_helpers.py,sha256=TRlqVctqIRBxzfjRBmpQsAVoiCcsEKBhG1B6PUE0l1M,12743
16
16
  trilogy/core/ergonomics.py,sha256=e-7gE29vPLFdg0_A1smQ7eOrUwKl5VYdxRSTddHweRA,1631
17
- trilogy/core/exceptions.py,sha256=fI16oTNCVMMAJFSn2AFzZVapzsF5M9WbdN5e5UixwXc,2807
18
- trilogy/core/functions.py,sha256=oY-F0hsA9vp1ZipGTyx4QVtz_x83Ekk-lkHv6mMkHVQ,33095
17
+ trilogy/core/exceptions.py,sha256=axkVXYJYQXCCwMHwlyDA232g4tCOwdCZUt7eHeUMDMg,2829
18
+ trilogy/core/functions.py,sha256=sdV6Z3NUVfwL1d18eNcaAXllVNqzLez23McsJ6xIp7M,33182
19
19
  trilogy/core/graph_models.py,sha256=4EWFTHGfYd72zvS2HYoV6hm7nMC_VEd7vWr6txY-ig0,3400
20
20
  trilogy/core/internal.py,sha256=r9QagDB2GvpqlyD_I7VrsfbVfIk5mnok2znEbv72Aa4,2681
21
21
  trilogy/core/optimization.py,sha256=ojpn-p79lr03SSVQbbw74iPCyoYpDYBmj1dbZ3oXCjI,8860
@@ -25,7 +25,7 @@ trilogy/core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
25
25
  trilogy/core/models/author.py,sha256=ZSKEJ6Vg4otpI_m7_JuGyrFM8dZV1HaxBwprvDSwUzo,81149
26
26
  trilogy/core/models/build.py,sha256=ZwJJGyp4rVsISvL8Er_AxQdVJrafYc4fesSj4MNgoxU,70615
27
27
  trilogy/core/models/build_environment.py,sha256=mpx7MKGc60fnZLVdeLi2YSREy7eQbQYycCrP4zF-rHU,5258
28
- trilogy/core/models/core.py,sha256=EofJ8-kltNr_7oFhyCPqauVX1bSJzJI5xOp0eMP_vlA,12892
28
+ trilogy/core/models/core.py,sha256=iT9WdZoiXeglmUHWn6bZyXCTBpkApTGPKtNm_Mhbu_g,12987
29
29
  trilogy/core/models/datasource.py,sha256=wogTevZ-9CyUW2a8gjzqMCieircxi-J5lkI7EOAZnck,9596
30
30
  trilogy/core/models/environment.py,sha256=hwTIRnJgaHUdCYof7U5A9NPitGZ2s9yxqiW5O2SaJ9Y,28759
31
31
  trilogy/core/models/execute.py,sha256=lsNzNjS3nZvoW5CHjYwxDTwBe502NZyytpK1eq8CwW4,42357
@@ -45,10 +45,10 @@ trilogy/core/processing/node_generators/basic_node.py,sha256=0Uhnf07056SBbRkt-wY
45
45
  trilogy/core/processing/node_generators/common.py,sha256=PdysdroW9DUADP7f5Wv_GKPUyCTROZV1g3L45fawxi8,9443
46
46
  trilogy/core/processing/node_generators/constant_node.py,sha256=LfpDq2WrBRZ3tGsLxw77LuigKfhbteWWh9L8BGdMGwk,1146
47
47
  trilogy/core/processing/node_generators/filter_node.py,sha256=ArBsQJl-4fWBJWCE28CRQ7UT7ErnFfbcseoQQZrBodY,11220
48
- trilogy/core/processing/node_generators/group_node.py,sha256=pq8aqKe4hCtkzFtpHvE15BJoYvpveoe50_2IM1pqjIQ,6732
48
+ trilogy/core/processing/node_generators/group_node.py,sha256=yqOWl5TCV4PrdJua4OJkPUIHkljaLoSW2Y8eRAmVddQ,6733
49
49
  trilogy/core/processing/node_generators/group_to_node.py,sha256=jKcNCDOY6fNblrdZwaRU0sbUSr9H0moQbAxrGgX6iGA,3832
50
50
  trilogy/core/processing/node_generators/multiselect_node.py,sha256=GWV5yLmKTe1yyPhN60RG1Rnrn4ktfn9lYYXi_FVU4UI,7061
51
- trilogy/core/processing/node_generators/node_merge_node.py,sha256=531ptEAZIczc7PR-kfuNe_KBaDToyIMUMKq4bkoZkgw,23561
51
+ trilogy/core/processing/node_generators/node_merge_node.py,sha256=1joMV7XpQ9Gpe-d5y7JUMBHIqakV5wFJi3Mtvs4UcL4,23415
52
52
  trilogy/core/processing/node_generators/recursive_node.py,sha256=l5zdh0dURKwmAy8kK4OpMtZfyUEQRk6N-PwSWIyBpSM,2468
53
53
  trilogy/core/processing/node_generators/rowset_node.py,sha256=5L5u6xz1In8EaHQdcYgR2si-tz9WB9YLXURo4AkUT9A,6630
54
54
  trilogy/core/processing/node_generators/select_merge_node.py,sha256=KQvGoNT5ZBWQ_caEomRTtG1PKZC7OPT4PKfY0QmwMGE,22270
@@ -77,11 +77,11 @@ trilogy/core/statements/execute.py,sha256=kiwJcVeMa4wZR-xLfM2oYOJ9DeyJkP8An38WFy
77
77
  trilogy/core/validation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
78
  trilogy/core/validation/common.py,sha256=Sd-towAX1uSDe3dK51FcVtIwVrMhayEwdHqhzeJHro0,4776
79
79
  trilogy/core/validation/concept.py,sha256=PM2BxBxLvuBScSWZMPsDZVcOblDil5pNT0pHLcLhdPA,5242
80
- trilogy/core/validation/datasource.py,sha256=d9AQNcukIRgN2spItPsXFiNtlZva-lDnfei3i06yQCE,6489
80
+ trilogy/core/validation/datasource.py,sha256=nJeEFyb6iMBwlEVdYVy1vLzAbdRZwOsUjGxgWKgY8oM,7636
81
81
  trilogy/core/validation/environment.py,sha256=ymvhQyt7jLK641JAAIQkqjQaAmr9C5022ILzYvDgPP0,2835
82
82
  trilogy/core/validation/fix.py,sha256=Z818UFNLxndMTLiyhB3doLxIfnOZ-16QGvVFWuD7UsA,3750
83
83
  trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
84
- trilogy/dialect/base.py,sha256=0QVHv4F0t3_gRQrZ0woFoUNKu7vaXGo-BG1l47CZUKc,49698
84
+ trilogy/dialect/base.py,sha256=d2gXfa5Jh3uyN9H9MxG53JT-xQQgntq2X7EprobJYUc,49698
85
85
  trilogy/dialect/bigquery.py,sha256=XS3hpybeowgfrOrkycAigAF3NX2YUzTzfgE6f__2fT4,4316
86
86
  trilogy/dialect/common.py,sha256=_MarnMWRBn3VcNt3k5VUdFrwH6oHzGdNQquSpHNLq4o,5644
87
87
  trilogy/dialect/config.py,sha256=olnyeVU5W5T6b9-dMeNAnvxuPlyc2uefb7FRME094Ec,3834
@@ -104,8 +104,8 @@ trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
104
104
  trilogy/parsing/exceptions.py,sha256=Xwwsv2C9kSNv2q-HrrKC1f60JNHShXcCMzstTSEbiCw,154
105
105
  trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
106
106
  trilogy/parsing/parse_engine.py,sha256=2k1TvnBYE_CW5zCmNfVbf1aWBuMDm5Wz4QfKKgGnE5k,81824
107
- trilogy/parsing/render.py,sha256=tqB3GlGk3bX6AbkJjvADad2QH6n63nw1kgrpjzLX2tI,20520
108
- trilogy/parsing/trilogy.lark,sha256=rM4WleeyGhoRgU-FOGcaeHOzZcYVxN4f13e_3B4OeLQ,16389
107
+ trilogy/parsing/render.py,sha256=E8-R0zO40QoeTeVX9OYdi5e9YgRYtuRrezDRj7VOgds,20614
108
+ trilogy/parsing/trilogy.lark,sha256=2-jguxgJQnNLbODjTijqrXXzFZ_UlivTdiYhec2YWuc,16451
109
109
  trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
110
110
  trilogy/scripts/trilogy.py,sha256=1L0XrH4mVHRt1C9T1HnaDv2_kYEfbWTb5_-cBBke79w,3774
111
111
  trilogy/std/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -117,8 +117,8 @@ trilogy/std/money.preql,sha256=XWwvAV3WxBsHX9zfptoYRnBigcfYwrYtBHXTME0xJuQ,2082
117
117
  trilogy/std/net.preql,sha256=WZCuvH87_rZntZiuGJMmBDMVKkdhTtxeHOkrXNwJ1EE,416
118
118
  trilogy/std/ranking.preql,sha256=LDoZrYyz4g3xsII9XwXfmstZD-_92i1Eox1UqkBIfi8,83
119
119
  trilogy/std/report.preql,sha256=LbV-XlHdfw0jgnQ8pV7acG95xrd1-p65fVpiIc-S7W4,202
120
- pytrilogy-0.0.3.100.dist-info/METADATA,sha256=T9p4b_yjL4_HtEwChltpxh5mlP8pCoRQPn28Ucu_1gI,11811
121
- pytrilogy-0.0.3.100.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
122
- pytrilogy-0.0.3.100.dist-info/entry_points.txt,sha256=ewBPU2vLnVexZVnB-NrVj-p3E-4vukg83Zk8A55Wp2w,56
123
- pytrilogy-0.0.3.100.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
124
- pytrilogy-0.0.3.100.dist-info/RECORD,,
120
+ pytrilogy-0.0.3.101.dist-info/METADATA,sha256=dkvyYmeCXSZl2uHkPpoy-R7HdKb2w7pLGFrDu1tRGEU,11811
121
+ pytrilogy-0.0.3.101.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
122
+ pytrilogy-0.0.3.101.dist-info/entry_points.txt,sha256=ewBPU2vLnVexZVnB-NrVj-p3E-4vukg83Zk8A55Wp2w,56
123
+ pytrilogy-0.0.3.101.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
124
+ pytrilogy-0.0.3.101.dist-info/RECORD,,
trilogy/__init__.py CHANGED
@@ -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.100"
7
+ __version__ = "0.0.3.101"
8
8
 
9
9
  __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
@@ -69,7 +69,7 @@ class DatasourceColumnBindingData:
69
69
  actual_modifiers: List[Modifier]
70
70
 
71
71
  def format_failure(self):
72
- return f"Concept {self.address} value '{self.value}' with type {self.value_modifiers} does not conform to expected type {str(self.actual_type)} with modifiers {self.actual_modifiers}"
72
+ return f"Concept {self.address} value '{self.value}' with type {self.value_type} and {self.value_modifiers} does not conform to expected type {str(self.actual_type)} with modifiers {self.actual_modifiers}"
73
73
 
74
74
  def is_modifier_issue(self) -> bool:
75
75
  return len(self.value_modifiers) > 0 and any(
trilogy/core/functions.py CHANGED
@@ -18,6 +18,7 @@ from trilogy.core.models.author import (
18
18
  AggregateWrapper,
19
19
  Concept,
20
20
  ConceptRef,
21
+ Conditional,
21
22
  Function,
22
23
  Parenthetical,
23
24
  UndefinedConcept,
@@ -129,8 +130,8 @@ def validate_case_output(
129
130
  def create_struct_output(
130
131
  args: list[Any],
131
132
  ) -> StructType:
132
- zipped = dict(zip(args[::2], args[1::2]))
133
- types = [arg_to_datatype(x) for x in args[1::2]]
133
+ zipped = dict(zip(args[1::2], args[::2]))
134
+ types = [arg_to_datatype(x) for x in args[::2]]
134
135
  return StructType(fields=types, fields_map=zipped)
135
136
 
136
137
 
@@ -997,6 +998,8 @@ def argument_to_purpose(arg) -> Purpose:
997
998
  return argument_to_purpose(arg.content)
998
999
  elif isinstance(arg, WindowItem):
999
1000
  return Purpose.PROPERTY
1001
+ elif isinstance(arg, Conditional):
1002
+ return Purpose.PROPERTY
1000
1003
  elif isinstance(arg, Concept):
1001
1004
  base = arg.purpose
1002
1005
  if (
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from abc import ABC
4
4
  from collections import UserDict, UserList
5
5
  from datetime import date, datetime
6
+ from decimal import Decimal
6
7
  from enum import Enum
7
8
  from typing import (
8
9
  Any,
@@ -448,6 +449,8 @@ def arg_to_datatype(arg) -> CONCRETE_TYPES:
448
449
  return DataType.STRING
449
450
  elif isinstance(arg, float):
450
451
  return DataType.FLOAT
452
+ elif isinstance(arg, Decimal):
453
+ return DataType.NUMERIC
451
454
  elif isinstance(arg, DataType):
452
455
  return arg
453
456
  elif isinstance(arg, NumericType):
@@ -28,6 +28,7 @@ def get_aggregate_grain(
28
28
  parent_concepts: List[BuildConcept] = unique(
29
29
  resolve_function_parent_concepts(concept, environment=environment), "address"
30
30
  )
31
+
31
32
  if (
32
33
  concept.grain
33
34
  and len(concept.grain.components) > 0
@@ -164,9 +164,6 @@ def reinject_common_join_keys_v2(
164
164
  reduced = BuildGrain.from_concepts(concrete_concepts).components
165
165
  existing_addresses = set()
166
166
  for concrete in concrete_concepts:
167
- logger.debug(
168
- f"looking at column {concrete.address} with pseudonyms {concrete.pseudonyms}"
169
- )
170
167
  cnode = concept_to_node(concrete.with_default_grain())
171
168
  if cnode in final.nodes:
172
169
  existing_addresses.add(concrete.address)
@@ -36,31 +36,51 @@ def type_check(
36
36
  ) -> bool:
37
37
  if input is None and nullable:
38
38
  return True
39
+
39
40
  target_type = expected_type
40
41
  while isinstance(target_type, TraitDataType):
41
42
  return type_check(input, target_type.data_type, nullable)
43
+
42
44
  if target_type == DataType.STRING:
43
45
  return isinstance(input, str)
44
46
  if target_type == DataType.INTEGER:
45
47
  return isinstance(input, int)
48
+ if target_type == DataType.BIGINT:
49
+ return isinstance(input, int) # or check for larger int if needed
46
50
  if target_type == DataType.FLOAT or isinstance(target_type, NumericType):
47
51
  return (
48
52
  isinstance(input, float)
49
53
  or isinstance(input, int)
50
54
  or isinstance(input, Decimal)
51
55
  )
56
+ if target_type == DataType.NUMBER:
57
+ return isinstance(input, (int, float, Decimal))
58
+ if target_type == DataType.NUMERIC:
59
+ return isinstance(input, (int, float, Decimal))
52
60
  if target_type == DataType.BOOL:
53
61
  return isinstance(input, bool)
54
62
  if target_type == DataType.DATE:
55
- return isinstance(input, date)
63
+ return isinstance(input, date) and not isinstance(input, datetime)
56
64
  if target_type == DataType.DATETIME:
57
65
  return isinstance(input, datetime)
66
+ if target_type == DataType.TIMESTAMP:
67
+ return isinstance(input, datetime) # or timestamp type if you have one
68
+ if target_type == DataType.UNIX_SECONDS:
69
+ return isinstance(input, (int, float)) # Unix timestamps are numeric
70
+ if target_type == DataType.DATE_PART:
71
+ return isinstance(
72
+ input, str
73
+ ) # assuming date parts are strings like "year", "month"
58
74
  if target_type == DataType.ARRAY or isinstance(target_type, ArrayType):
59
75
  return isinstance(input, list)
60
76
  if target_type == DataType.MAP or isinstance(target_type, MapType):
61
77
  return isinstance(input, dict)
62
78
  if target_type == DataType.STRUCT or isinstance(target_type, StructType):
63
79
  return isinstance(input, dict)
80
+ if target_type == DataType.NULL:
81
+ return input is None
82
+ if target_type == DataType.UNKNOWN:
83
+ return True
64
84
  return False
65
85
 
66
86
 
@@ -125,15 +145,19 @@ def validate_datasource(
125
145
  rval = row[actual_address]
126
146
  passed = type_check(rval, col.concept.datatype, col.is_nullable)
127
147
  if not passed:
148
+ value_type = (
149
+ arg_to_datatype(rval) if rval is not None else col.concept.datatype
150
+ )
151
+ traits = None
152
+ if isinstance(col.concept.datatype, TraitDataType):
153
+ traits = col.concept.datatype.traits
154
+ if traits and not isinstance(value_type, TraitDataType):
155
+ value_type = TraitDataType(type=value_type, traits=traits)
128
156
  failures.append(
129
157
  DatasourceColumnBindingData(
130
158
  address=col.concept.address,
131
159
  value=rval,
132
- value_type=(
133
- arg_to_datatype(rval)
134
- if rval is not None
135
- else col.concept.datatype
136
- ),
160
+ value_type=value_type,
137
161
  value_modifiers=[Modifier.NULLABLE] if rval is None else [],
138
162
  actual_type=col.concept.datatype,
139
163
  actual_modifiers=col.concept.modifiers,
trilogy/dialect/base.py CHANGED
@@ -163,7 +163,7 @@ def render_case(args):
163
163
 
164
164
 
165
165
  def struct_arg(args):
166
- return [f"{x[0]}: {x[1]}" for x in zip(args[::2], args[1::2])]
166
+ return [f"{x[1]}: {x[0]}" for x in zip(args[::2], args[1::2])]
167
167
 
168
168
 
169
169
  FUNCTION_MAP = {
trilogy/parsing/render.py CHANGED
@@ -349,7 +349,8 @@ class Renderer:
349
349
  else:
350
350
  output = f"{concept.purpose.value} {namespace}{concept.name} <- {self.to_string(concept.lineage)};"
351
351
  if base_description:
352
- output += f" #{base_description}"
352
+ lines = "\n#".join(base_description.split("\n"))
353
+ output += f" #{lines}"
353
354
  return output
354
355
 
355
356
  @to_string.register
@@ -439,7 +440,7 @@ class Renderer:
439
440
 
440
441
  @to_string.register
441
442
  def _(self, arg: "Conditional"):
442
- return f"({self.to_string(arg.left)} {arg.operator.value} {self.to_string(arg.right)})"
443
+ return f"{self.to_string(arg.left)} {arg.operator.value} {self.to_string(arg.right)}"
443
444
 
444
445
  @to_string.register
445
446
  def _(self, arg: "SubselectComparison"):
@@ -451,7 +452,8 @@ class Renderer:
451
452
 
452
453
  @to_string.register
453
454
  def _(self, arg: "Comment"):
454
- return f"{arg.text}"
455
+ lines = "\n#".join(arg.text.split("\n"))
456
+ return f"{lines}"
455
457
 
456
458
  @to_string.register
457
459
  def _(self, arg: "WindowItem"):
@@ -134,10 +134,12 @@
134
134
  metadata: "metadata" "(" IDENTIFIER "=" string_lit ")"
135
135
 
136
136
  limit: "LIMIT"i /[0-9]+/
137
+
138
+ _order_atom: expr ordering
137
139
 
138
- order_list: expr ordering ("," expr ordering)* ","?
140
+ order_list: _order_atom ("," _order_atom)* ","?
139
141
 
140
- over_list: concept_lit ("," concept_lit )* ","?
142
+ over_list: (concept_lit ",")* concept_lit ","?
141
143
 
142
144
  ORDERING_DIRECTION: /ASC|DESC/i
143
145
 
@@ -433,7 +435,8 @@
433
435
  map_lit: "{" (literal ":" literal ",")* literal ":" literal ","? "}"
434
436
 
435
437
  _STRUCT.1: "struct("i
436
- struct_lit: _STRUCT (IDENTIFIER "->" expr ",")* IDENTIFIER "->" expr ","? ")"
438
+ _BINDING.1: "->"
439
+ struct_lit: _STRUCT expr _BINDING IDENTIFIER ( "," expr _BINDING IDENTIFIER )* ","? ")"
437
440
 
438
441
  !bool_lit: "True"i | "False"i
439
442