pytrilogy 0.3.149__cp313-cp313-win_amd64.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 (207) hide show
  1. LICENSE.md +19 -0
  2. _preql_import_resolver/__init__.py +5 -0
  3. _preql_import_resolver/_preql_import_resolver.cp313-win_amd64.pyd +0 -0
  4. pytrilogy-0.3.149.dist-info/METADATA +555 -0
  5. pytrilogy-0.3.149.dist-info/RECORD +207 -0
  6. pytrilogy-0.3.149.dist-info/WHEEL +4 -0
  7. pytrilogy-0.3.149.dist-info/entry_points.txt +2 -0
  8. pytrilogy-0.3.149.dist-info/licenses/LICENSE.md +19 -0
  9. trilogy/__init__.py +27 -0
  10. trilogy/ai/README.md +10 -0
  11. trilogy/ai/__init__.py +19 -0
  12. trilogy/ai/constants.py +92 -0
  13. trilogy/ai/conversation.py +107 -0
  14. trilogy/ai/enums.py +7 -0
  15. trilogy/ai/execute.py +50 -0
  16. trilogy/ai/models.py +34 -0
  17. trilogy/ai/prompts.py +100 -0
  18. trilogy/ai/providers/__init__.py +0 -0
  19. trilogy/ai/providers/anthropic.py +106 -0
  20. trilogy/ai/providers/base.py +24 -0
  21. trilogy/ai/providers/google.py +146 -0
  22. trilogy/ai/providers/openai.py +89 -0
  23. trilogy/ai/providers/utils.py +68 -0
  24. trilogy/authoring/README.md +3 -0
  25. trilogy/authoring/__init__.py +148 -0
  26. trilogy/constants.py +119 -0
  27. trilogy/core/README.md +52 -0
  28. trilogy/core/__init__.py +0 -0
  29. trilogy/core/constants.py +6 -0
  30. trilogy/core/enums.py +454 -0
  31. trilogy/core/env_processor.py +239 -0
  32. trilogy/core/environment_helpers.py +320 -0
  33. trilogy/core/ergonomics.py +193 -0
  34. trilogy/core/exceptions.py +123 -0
  35. trilogy/core/functions.py +1240 -0
  36. trilogy/core/graph_models.py +142 -0
  37. trilogy/core/internal.py +85 -0
  38. trilogy/core/models/__init__.py +0 -0
  39. trilogy/core/models/author.py +2670 -0
  40. trilogy/core/models/build.py +2603 -0
  41. trilogy/core/models/build_environment.py +165 -0
  42. trilogy/core/models/core.py +506 -0
  43. trilogy/core/models/datasource.py +436 -0
  44. trilogy/core/models/environment.py +756 -0
  45. trilogy/core/models/execute.py +1213 -0
  46. trilogy/core/optimization.py +251 -0
  47. trilogy/core/optimizations/__init__.py +12 -0
  48. trilogy/core/optimizations/base_optimization.py +17 -0
  49. trilogy/core/optimizations/hide_unused_concept.py +47 -0
  50. trilogy/core/optimizations/inline_datasource.py +102 -0
  51. trilogy/core/optimizations/predicate_pushdown.py +245 -0
  52. trilogy/core/processing/README.md +94 -0
  53. trilogy/core/processing/READMEv2.md +121 -0
  54. trilogy/core/processing/VIRTUAL_UNNEST.md +30 -0
  55. trilogy/core/processing/__init__.py +0 -0
  56. trilogy/core/processing/concept_strategies_v3.py +508 -0
  57. trilogy/core/processing/constants.py +15 -0
  58. trilogy/core/processing/discovery_node_factory.py +451 -0
  59. trilogy/core/processing/discovery_utility.py +548 -0
  60. trilogy/core/processing/discovery_validation.py +167 -0
  61. trilogy/core/processing/graph_utils.py +43 -0
  62. trilogy/core/processing/node_generators/README.md +9 -0
  63. trilogy/core/processing/node_generators/__init__.py +31 -0
  64. trilogy/core/processing/node_generators/basic_node.py +160 -0
  65. trilogy/core/processing/node_generators/common.py +270 -0
  66. trilogy/core/processing/node_generators/constant_node.py +38 -0
  67. trilogy/core/processing/node_generators/filter_node.py +315 -0
  68. trilogy/core/processing/node_generators/group_node.py +213 -0
  69. trilogy/core/processing/node_generators/group_to_node.py +117 -0
  70. trilogy/core/processing/node_generators/multiselect_node.py +207 -0
  71. trilogy/core/processing/node_generators/node_merge_node.py +695 -0
  72. trilogy/core/processing/node_generators/recursive_node.py +88 -0
  73. trilogy/core/processing/node_generators/rowset_node.py +165 -0
  74. trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
  75. trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +261 -0
  76. trilogy/core/processing/node_generators/select_merge_node.py +846 -0
  77. trilogy/core/processing/node_generators/select_node.py +95 -0
  78. trilogy/core/processing/node_generators/synonym_node.py +98 -0
  79. trilogy/core/processing/node_generators/union_node.py +91 -0
  80. trilogy/core/processing/node_generators/unnest_node.py +182 -0
  81. trilogy/core/processing/node_generators/window_node.py +201 -0
  82. trilogy/core/processing/nodes/README.md +28 -0
  83. trilogy/core/processing/nodes/__init__.py +179 -0
  84. trilogy/core/processing/nodes/base_node.py +522 -0
  85. trilogy/core/processing/nodes/filter_node.py +75 -0
  86. trilogy/core/processing/nodes/group_node.py +194 -0
  87. trilogy/core/processing/nodes/merge_node.py +420 -0
  88. trilogy/core/processing/nodes/recursive_node.py +46 -0
  89. trilogy/core/processing/nodes/select_node_v2.py +242 -0
  90. trilogy/core/processing/nodes/union_node.py +53 -0
  91. trilogy/core/processing/nodes/unnest_node.py +62 -0
  92. trilogy/core/processing/nodes/window_node.py +56 -0
  93. trilogy/core/processing/utility.py +823 -0
  94. trilogy/core/query_processor.py +604 -0
  95. trilogy/core/statements/README.md +35 -0
  96. trilogy/core/statements/__init__.py +0 -0
  97. trilogy/core/statements/author.py +536 -0
  98. trilogy/core/statements/build.py +0 -0
  99. trilogy/core/statements/common.py +20 -0
  100. trilogy/core/statements/execute.py +155 -0
  101. trilogy/core/table_processor.py +66 -0
  102. trilogy/core/utility.py +8 -0
  103. trilogy/core/validation/README.md +46 -0
  104. trilogy/core/validation/__init__.py +0 -0
  105. trilogy/core/validation/common.py +161 -0
  106. trilogy/core/validation/concept.py +146 -0
  107. trilogy/core/validation/datasource.py +227 -0
  108. trilogy/core/validation/environment.py +73 -0
  109. trilogy/core/validation/fix.py +256 -0
  110. trilogy/dialect/__init__.py +32 -0
  111. trilogy/dialect/base.py +1432 -0
  112. trilogy/dialect/bigquery.py +314 -0
  113. trilogy/dialect/common.py +147 -0
  114. trilogy/dialect/config.py +159 -0
  115. trilogy/dialect/dataframe.py +50 -0
  116. trilogy/dialect/duckdb.py +397 -0
  117. trilogy/dialect/enums.py +151 -0
  118. trilogy/dialect/metadata.py +173 -0
  119. trilogy/dialect/mock.py +190 -0
  120. trilogy/dialect/postgres.py +117 -0
  121. trilogy/dialect/presto.py +110 -0
  122. trilogy/dialect/results.py +89 -0
  123. trilogy/dialect/snowflake.py +129 -0
  124. trilogy/dialect/sql_server.py +137 -0
  125. trilogy/engine.py +48 -0
  126. trilogy/execution/__init__.py +17 -0
  127. trilogy/execution/config.py +119 -0
  128. trilogy/execution/state/__init__.py +0 -0
  129. trilogy/execution/state/exceptions.py +26 -0
  130. trilogy/execution/state/file_state_store.py +0 -0
  131. trilogy/execution/state/sqllite_state_store.py +0 -0
  132. trilogy/execution/state/state_store.py +406 -0
  133. trilogy/executor.py +692 -0
  134. trilogy/hooks/__init__.py +4 -0
  135. trilogy/hooks/base_hook.py +40 -0
  136. trilogy/hooks/graph_hook.py +135 -0
  137. trilogy/hooks/query_debugger.py +166 -0
  138. trilogy/metadata/__init__.py +0 -0
  139. trilogy/parser.py +10 -0
  140. trilogy/parsing/README.md +21 -0
  141. trilogy/parsing/__init__.py +0 -0
  142. trilogy/parsing/common.py +1069 -0
  143. trilogy/parsing/config.py +5 -0
  144. trilogy/parsing/exceptions.py +8 -0
  145. trilogy/parsing/helpers.py +1 -0
  146. trilogy/parsing/parse_engine.py +2876 -0
  147. trilogy/parsing/render.py +775 -0
  148. trilogy/parsing/trilogy.lark +546 -0
  149. trilogy/py.typed +0 -0
  150. trilogy/render.py +45 -0
  151. trilogy/scripts/README.md +9 -0
  152. trilogy/scripts/__init__.py +0 -0
  153. trilogy/scripts/agent.py +41 -0
  154. trilogy/scripts/agent_info.py +306 -0
  155. trilogy/scripts/common.py +432 -0
  156. trilogy/scripts/dependency/Cargo.lock +617 -0
  157. trilogy/scripts/dependency/Cargo.toml +39 -0
  158. trilogy/scripts/dependency/README.md +131 -0
  159. trilogy/scripts/dependency/build.sh +25 -0
  160. trilogy/scripts/dependency/src/directory_resolver.rs +387 -0
  161. trilogy/scripts/dependency/src/lib.rs +16 -0
  162. trilogy/scripts/dependency/src/main.rs +770 -0
  163. trilogy/scripts/dependency/src/parser.rs +435 -0
  164. trilogy/scripts/dependency/src/preql.pest +208 -0
  165. trilogy/scripts/dependency/src/python_bindings.rs +311 -0
  166. trilogy/scripts/dependency/src/resolver.rs +716 -0
  167. trilogy/scripts/dependency/tests/base.preql +3 -0
  168. trilogy/scripts/dependency/tests/cli_integration.rs +377 -0
  169. trilogy/scripts/dependency/tests/customer.preql +6 -0
  170. trilogy/scripts/dependency/tests/main.preql +9 -0
  171. trilogy/scripts/dependency/tests/orders.preql +7 -0
  172. trilogy/scripts/dependency/tests/test_data/base.preql +9 -0
  173. trilogy/scripts/dependency/tests/test_data/consumer.preql +1 -0
  174. trilogy/scripts/dependency.py +323 -0
  175. trilogy/scripts/display.py +555 -0
  176. trilogy/scripts/environment.py +59 -0
  177. trilogy/scripts/fmt.py +32 -0
  178. trilogy/scripts/ingest.py +487 -0
  179. trilogy/scripts/ingest_helpers/__init__.py +1 -0
  180. trilogy/scripts/ingest_helpers/foreign_keys.py +123 -0
  181. trilogy/scripts/ingest_helpers/formatting.py +93 -0
  182. trilogy/scripts/ingest_helpers/typing.py +161 -0
  183. trilogy/scripts/init.py +105 -0
  184. trilogy/scripts/parallel_execution.py +762 -0
  185. trilogy/scripts/plan.py +189 -0
  186. trilogy/scripts/refresh.py +161 -0
  187. trilogy/scripts/run.py +79 -0
  188. trilogy/scripts/serve.py +202 -0
  189. trilogy/scripts/serve_helpers/__init__.py +41 -0
  190. trilogy/scripts/serve_helpers/file_discovery.py +142 -0
  191. trilogy/scripts/serve_helpers/index_generation.py +206 -0
  192. trilogy/scripts/serve_helpers/models.py +38 -0
  193. trilogy/scripts/single_execution.py +131 -0
  194. trilogy/scripts/testing.py +143 -0
  195. trilogy/scripts/trilogy.py +75 -0
  196. trilogy/std/__init__.py +0 -0
  197. trilogy/std/color.preql +3 -0
  198. trilogy/std/date.preql +13 -0
  199. trilogy/std/display.preql +18 -0
  200. trilogy/std/geography.preql +22 -0
  201. trilogy/std/metric.preql +15 -0
  202. trilogy/std/money.preql +67 -0
  203. trilogy/std/net.preql +14 -0
  204. trilogy/std/ranking.preql +7 -0
  205. trilogy/std/report.preql +5 -0
  206. trilogy/std/semantic.preql +6 -0
  207. trilogy/utility.py +34 -0
@@ -0,0 +1,161 @@
1
+ import re
2
+ from typing import Any
3
+
4
+ from trilogy.authoring import (
5
+ DataType,
6
+ )
7
+
8
+ # Rich type detection mappings
9
+ RICH_TYPE_PATTERNS: dict[str, dict[str, Any]] = {
10
+ "geography": {
11
+ "latitude": {
12
+ "patterns": [r"(?:^|_)lat(?:$|_)", r"(?:^|_)latitude(?:$|_)"],
13
+ "import": "std.geography",
14
+ "type_name": "latitude",
15
+ "base_type": DataType.FLOAT,
16
+ },
17
+ "longitude": {
18
+ "patterns": [
19
+ r"(?:^|_)lon(?:$|_)",
20
+ r"(?:^|_)lng(?:$|_)",
21
+ r"(?:^|_)long(?:$|_)",
22
+ r"(?:^|_)longitude(?:$|_)",
23
+ ],
24
+ "import": "std.geography",
25
+ "type_name": "longitude",
26
+ "base_type": DataType.FLOAT,
27
+ },
28
+ "city": {
29
+ "patterns": [r"(?:^|_)city(?:$|_)"],
30
+ "import": "std.geography",
31
+ "type_name": "city",
32
+ "base_type": DataType.STRING,
33
+ },
34
+ "country": {
35
+ "patterns": [r"(?:^|_)country(?:$|_)"],
36
+ "import": "std.geography",
37
+ "type_name": "country",
38
+ "base_type": DataType.STRING,
39
+ },
40
+ "country_code": {
41
+ "patterns": [r"country_code", r"countrycode"],
42
+ "import": "std.geography",
43
+ "type_name": "country_code",
44
+ "base_type": DataType.STRING,
45
+ },
46
+ "us_state": {
47
+ "patterns": [r"(?:^|_)state(?:$|_)", r"us_state"],
48
+ "import": "std.geography",
49
+ "type_name": "us_state",
50
+ "base_type": DataType.STRING,
51
+ },
52
+ "us_zip_code": {
53
+ "patterns": [r"(?:^|_)zip(?:$|_)", r"zipcode", r"zip_code", r"postal_code"],
54
+ "import": "std.geography",
55
+ "type_name": "us_zip_code",
56
+ "base_type": DataType.STRING,
57
+ },
58
+ },
59
+ "net": {
60
+ "email_address": {
61
+ "patterns": [r"(?:^|_)email(?:$|_)", r"email_address"],
62
+ "import": "std.net",
63
+ "type_name": "email_address",
64
+ "base_type": DataType.STRING,
65
+ },
66
+ "url": {
67
+ "patterns": [r"(?:^|_)url(?:$|_)", r"(?:^|_)website(?:$|_)"],
68
+ "import": "std.net",
69
+ "type_name": "url",
70
+ "base_type": DataType.STRING,
71
+ },
72
+ "ipv4_address": {
73
+ "patterns": [r"(?:^|_)ip(?:$|_)", r"(?:^|_)ipv4(?:$|_)", r"ip_address"],
74
+ "import": "std.net",
75
+ "type_name": "ipv4_address",
76
+ "base_type": DataType.STRING,
77
+ },
78
+ },
79
+ }
80
+
81
+
82
+ def detect_rich_type(
83
+ column_name: str, base_datatype: DataType
84
+ ) -> tuple[str, str] | tuple[None, None]:
85
+ """Detect if a column name matches a rich type pattern.
86
+
87
+ Returns: (import_path, type_name) or (None, None) if no match
88
+
89
+ Note: When multiple patterns match, the one with the longest matched
90
+ string is preferred to ensure more specific matches win.
91
+ """
92
+ column_lower = column_name.lower()
93
+
94
+ # Collect all matches and sort by matched string length (longest first) to prefer more specific matches
95
+ matches = []
96
+
97
+ for _, types in RICH_TYPE_PATTERNS.items():
98
+ for _, config in types.items():
99
+ # Only consider if base types match
100
+ if config["base_type"] != base_datatype:
101
+ continue
102
+
103
+ # Check if any pattern matches
104
+ for pattern in config["patterns"]:
105
+ match = re.search(pattern, column_lower)
106
+ if match:
107
+ # Store match with the length of the matched string for sorting
108
+ matched_length = len(match.group())
109
+ matches.append(
110
+ (matched_length, config["import"], config["type_name"])
111
+ )
112
+ break # Only need one match per type
113
+
114
+ # Return the most specific match (longest matched string)
115
+ if matches:
116
+ matches.sort(reverse=True) # Sort by matched string length descending
117
+ return str(matches[0][1]), str(matches[0][2])
118
+
119
+ return None, None
120
+
121
+
122
+ def infer_datatype_from_sql_type(sql_type: str) -> DataType:
123
+ """Infer Trilogy datatype from SQL type string."""
124
+ sql_type_lower = sql_type.lower()
125
+
126
+ # Integer types
127
+ if any(
128
+ t in sql_type_lower
129
+ for t in ["int", "integer", "smallint", "tinyint", "mediumint"]
130
+ ):
131
+ return DataType.INTEGER
132
+ if any(t in sql_type_lower for t in ["bigint", "long", "int64"]):
133
+ return DataType.BIGINT
134
+
135
+ # Numeric/decimal types
136
+ if any(t in sql_type_lower for t in ["numeric", "decimal", "money"]):
137
+ return DataType.NUMERIC
138
+ if any(t in sql_type_lower for t in ["float", "double", "real", "float64"]):
139
+ return DataType.FLOAT
140
+
141
+ # String types
142
+ if any(
143
+ t in sql_type_lower
144
+ for t in ["char", "varchar", "text", "string", "clob", "nchar", "nvarchar"]
145
+ ):
146
+ return DataType.STRING
147
+
148
+ # Boolean
149
+ if any(t in sql_type_lower for t in ["bool", "boolean", "bit"]):
150
+ return DataType.BOOL
151
+
152
+ # Date/Time types
153
+ if "timestamp" in sql_type_lower:
154
+ return DataType.TIMESTAMP
155
+ if "datetime" in sql_type_lower:
156
+ return DataType.DATETIME
157
+ if "date" in sql_type_lower:
158
+ return DataType.DATE
159
+
160
+ # Default to string for unknown types
161
+ return DataType.STRING
@@ -0,0 +1,105 @@
1
+ """Init command for Trilogy CLI - creates a new default workspace."""
2
+
3
+ from pathlib import Path
4
+
5
+ from click import argument, pass_context
6
+
7
+ from trilogy.scripts.display import print_error, print_info, print_success
8
+
9
+ # Default hello world script content
10
+ HELLO_WORLD_SCRIPT = """# Welcome to Trilogy!
11
+ # This is a simple example script to get you started.
12
+
13
+ # Define a simple concept
14
+ key user_id int;
15
+
16
+ # Create a sample datasource
17
+ datasource users (
18
+ user_id
19
+ )
20
+ grain (user_id)
21
+ query '''
22
+ SELECT 1 as user_id
23
+ UNION ALL
24
+ SELECT 2 as user_id
25
+ UNION ALL
26
+ SELECT 3 as user_id
27
+ ''';
28
+
29
+ # Query the data
30
+ SELECT
31
+ user_id
32
+ ;
33
+ """
34
+
35
+ # Default trilogy.toml content
36
+ DEFAULT_CONFIG = """# Trilogy Configuration File
37
+ # Learn more at: https://github.com/trilmhmogy-data/pytrilogy
38
+
39
+ [engine]
40
+ # Default dialect for execution
41
+ # dialect = "duck_db"
42
+
43
+ # Max parallelism for multi-script execution
44
+ # parallelism = 3
45
+
46
+
47
+ [setup]
48
+ # Startup scripts to run before execution
49
+ # trilogy = []
50
+ # sql = []
51
+ """
52
+
53
+
54
+ @argument("path", type=str, required=False, default=".")
55
+ @pass_context
56
+ def init(ctx, path: str):
57
+ """Create a new default Trilogy workspace.
58
+
59
+ Initializes a new workspace with default configuration and structure:
60
+ - trilogy.toml: Configuration file
61
+ - raw/: Directory for raw data models
62
+ - derived/: Directory for derived data models
63
+ - jobs/: Directory for job scripts
64
+ - hello_world.preql: Example script
65
+
66
+ Args:
67
+ path: Path where the workspace should be created (default: current directory)
68
+ """
69
+ workspace_path = Path(path).resolve()
70
+
71
+ print_info(f"Initializing Trilogy workspace at: {workspace_path}")
72
+
73
+ # Check if path already has trilogy files
74
+ if (workspace_path / "trilogy.toml").exists():
75
+ print_error(
76
+ f"Workspace already initialized at {workspace_path} (trilogy.toml exists)"
77
+ )
78
+ raise SystemExit(1)
79
+
80
+ # Create base directory if it doesn't exist
81
+ workspace_path.mkdir(parents=True, exist_ok=True)
82
+
83
+ # Create subdirectories
84
+ subdirs = ["raw", "derived", "jobs"]
85
+ for subdir in subdirs:
86
+ subdir_path = workspace_path / subdir
87
+ subdir_path.mkdir(exist_ok=True)
88
+ print_info(f"Created directory: {subdir}/")
89
+
90
+ # Create trilogy.toml
91
+ config_path = workspace_path / "trilogy.toml"
92
+ config_path.write_text(DEFAULT_CONFIG)
93
+ print_info("Created configuration: trilogy.toml")
94
+
95
+ # Create hello_world.preql
96
+ hello_world_path = workspace_path / "hello_world.preql"
97
+ hello_world_path.write_text(HELLO_WORLD_SCRIPT)
98
+ print_info("Created example script: hello_world.preql")
99
+
100
+ print_success(
101
+ f"\nWorkspace initialized successfully!\n\n"
102
+ f"Get started with:\n"
103
+ f" cd {workspace_path.name if path != '.' else workspace_path}\n"
104
+ f" trilogy unit hello_world.preql\n"
105
+ )