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.
- LICENSE.md +19 -0
- _preql_import_resolver/__init__.py +5 -0
- _preql_import_resolver/_preql_import_resolver.cp313-win_amd64.pyd +0 -0
- pytrilogy-0.3.149.dist-info/METADATA +555 -0
- pytrilogy-0.3.149.dist-info/RECORD +207 -0
- pytrilogy-0.3.149.dist-info/WHEEL +4 -0
- pytrilogy-0.3.149.dist-info/entry_points.txt +2 -0
- pytrilogy-0.3.149.dist-info/licenses/LICENSE.md +19 -0
- trilogy/__init__.py +27 -0
- trilogy/ai/README.md +10 -0
- trilogy/ai/__init__.py +19 -0
- trilogy/ai/constants.py +92 -0
- trilogy/ai/conversation.py +107 -0
- trilogy/ai/enums.py +7 -0
- trilogy/ai/execute.py +50 -0
- trilogy/ai/models.py +34 -0
- trilogy/ai/prompts.py +100 -0
- trilogy/ai/providers/__init__.py +0 -0
- trilogy/ai/providers/anthropic.py +106 -0
- trilogy/ai/providers/base.py +24 -0
- trilogy/ai/providers/google.py +146 -0
- trilogy/ai/providers/openai.py +89 -0
- trilogy/ai/providers/utils.py +68 -0
- trilogy/authoring/README.md +3 -0
- trilogy/authoring/__init__.py +148 -0
- trilogy/constants.py +119 -0
- trilogy/core/README.md +52 -0
- trilogy/core/__init__.py +0 -0
- trilogy/core/constants.py +6 -0
- trilogy/core/enums.py +454 -0
- trilogy/core/env_processor.py +239 -0
- trilogy/core/environment_helpers.py +320 -0
- trilogy/core/ergonomics.py +193 -0
- trilogy/core/exceptions.py +123 -0
- trilogy/core/functions.py +1240 -0
- trilogy/core/graph_models.py +142 -0
- trilogy/core/internal.py +85 -0
- trilogy/core/models/__init__.py +0 -0
- trilogy/core/models/author.py +2670 -0
- trilogy/core/models/build.py +2603 -0
- trilogy/core/models/build_environment.py +165 -0
- trilogy/core/models/core.py +506 -0
- trilogy/core/models/datasource.py +436 -0
- trilogy/core/models/environment.py +756 -0
- trilogy/core/models/execute.py +1213 -0
- trilogy/core/optimization.py +251 -0
- trilogy/core/optimizations/__init__.py +12 -0
- trilogy/core/optimizations/base_optimization.py +17 -0
- trilogy/core/optimizations/hide_unused_concept.py +47 -0
- trilogy/core/optimizations/inline_datasource.py +102 -0
- trilogy/core/optimizations/predicate_pushdown.py +245 -0
- trilogy/core/processing/README.md +94 -0
- trilogy/core/processing/READMEv2.md +121 -0
- trilogy/core/processing/VIRTUAL_UNNEST.md +30 -0
- trilogy/core/processing/__init__.py +0 -0
- trilogy/core/processing/concept_strategies_v3.py +508 -0
- trilogy/core/processing/constants.py +15 -0
- trilogy/core/processing/discovery_node_factory.py +451 -0
- trilogy/core/processing/discovery_utility.py +548 -0
- trilogy/core/processing/discovery_validation.py +167 -0
- trilogy/core/processing/graph_utils.py +43 -0
- trilogy/core/processing/node_generators/README.md +9 -0
- trilogy/core/processing/node_generators/__init__.py +31 -0
- trilogy/core/processing/node_generators/basic_node.py +160 -0
- trilogy/core/processing/node_generators/common.py +270 -0
- trilogy/core/processing/node_generators/constant_node.py +38 -0
- trilogy/core/processing/node_generators/filter_node.py +315 -0
- trilogy/core/processing/node_generators/group_node.py +213 -0
- trilogy/core/processing/node_generators/group_to_node.py +117 -0
- trilogy/core/processing/node_generators/multiselect_node.py +207 -0
- trilogy/core/processing/node_generators/node_merge_node.py +695 -0
- trilogy/core/processing/node_generators/recursive_node.py +88 -0
- trilogy/core/processing/node_generators/rowset_node.py +165 -0
- trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
- trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +261 -0
- trilogy/core/processing/node_generators/select_merge_node.py +846 -0
- trilogy/core/processing/node_generators/select_node.py +95 -0
- trilogy/core/processing/node_generators/synonym_node.py +98 -0
- trilogy/core/processing/node_generators/union_node.py +91 -0
- trilogy/core/processing/node_generators/unnest_node.py +182 -0
- trilogy/core/processing/node_generators/window_node.py +201 -0
- trilogy/core/processing/nodes/README.md +28 -0
- trilogy/core/processing/nodes/__init__.py +179 -0
- trilogy/core/processing/nodes/base_node.py +522 -0
- trilogy/core/processing/nodes/filter_node.py +75 -0
- trilogy/core/processing/nodes/group_node.py +194 -0
- trilogy/core/processing/nodes/merge_node.py +420 -0
- trilogy/core/processing/nodes/recursive_node.py +46 -0
- trilogy/core/processing/nodes/select_node_v2.py +242 -0
- trilogy/core/processing/nodes/union_node.py +53 -0
- trilogy/core/processing/nodes/unnest_node.py +62 -0
- trilogy/core/processing/nodes/window_node.py +56 -0
- trilogy/core/processing/utility.py +823 -0
- trilogy/core/query_processor.py +604 -0
- trilogy/core/statements/README.md +35 -0
- trilogy/core/statements/__init__.py +0 -0
- trilogy/core/statements/author.py +536 -0
- trilogy/core/statements/build.py +0 -0
- trilogy/core/statements/common.py +20 -0
- trilogy/core/statements/execute.py +155 -0
- trilogy/core/table_processor.py +66 -0
- trilogy/core/utility.py +8 -0
- trilogy/core/validation/README.md +46 -0
- trilogy/core/validation/__init__.py +0 -0
- trilogy/core/validation/common.py +161 -0
- trilogy/core/validation/concept.py +146 -0
- trilogy/core/validation/datasource.py +227 -0
- trilogy/core/validation/environment.py +73 -0
- trilogy/core/validation/fix.py +256 -0
- trilogy/dialect/__init__.py +32 -0
- trilogy/dialect/base.py +1432 -0
- trilogy/dialect/bigquery.py +314 -0
- trilogy/dialect/common.py +147 -0
- trilogy/dialect/config.py +159 -0
- trilogy/dialect/dataframe.py +50 -0
- trilogy/dialect/duckdb.py +397 -0
- trilogy/dialect/enums.py +151 -0
- trilogy/dialect/metadata.py +173 -0
- trilogy/dialect/mock.py +190 -0
- trilogy/dialect/postgres.py +117 -0
- trilogy/dialect/presto.py +110 -0
- trilogy/dialect/results.py +89 -0
- trilogy/dialect/snowflake.py +129 -0
- trilogy/dialect/sql_server.py +137 -0
- trilogy/engine.py +48 -0
- trilogy/execution/__init__.py +17 -0
- trilogy/execution/config.py +119 -0
- trilogy/execution/state/__init__.py +0 -0
- trilogy/execution/state/exceptions.py +26 -0
- trilogy/execution/state/file_state_store.py +0 -0
- trilogy/execution/state/sqllite_state_store.py +0 -0
- trilogy/execution/state/state_store.py +406 -0
- trilogy/executor.py +692 -0
- trilogy/hooks/__init__.py +4 -0
- trilogy/hooks/base_hook.py +40 -0
- trilogy/hooks/graph_hook.py +135 -0
- trilogy/hooks/query_debugger.py +166 -0
- trilogy/metadata/__init__.py +0 -0
- trilogy/parser.py +10 -0
- trilogy/parsing/README.md +21 -0
- trilogy/parsing/__init__.py +0 -0
- trilogy/parsing/common.py +1069 -0
- trilogy/parsing/config.py +5 -0
- trilogy/parsing/exceptions.py +8 -0
- trilogy/parsing/helpers.py +1 -0
- trilogy/parsing/parse_engine.py +2876 -0
- trilogy/parsing/render.py +775 -0
- trilogy/parsing/trilogy.lark +546 -0
- trilogy/py.typed +0 -0
- trilogy/render.py +45 -0
- trilogy/scripts/README.md +9 -0
- trilogy/scripts/__init__.py +0 -0
- trilogy/scripts/agent.py +41 -0
- trilogy/scripts/agent_info.py +306 -0
- trilogy/scripts/common.py +432 -0
- trilogy/scripts/dependency/Cargo.lock +617 -0
- trilogy/scripts/dependency/Cargo.toml +39 -0
- trilogy/scripts/dependency/README.md +131 -0
- trilogy/scripts/dependency/build.sh +25 -0
- trilogy/scripts/dependency/src/directory_resolver.rs +387 -0
- trilogy/scripts/dependency/src/lib.rs +16 -0
- trilogy/scripts/dependency/src/main.rs +770 -0
- trilogy/scripts/dependency/src/parser.rs +435 -0
- trilogy/scripts/dependency/src/preql.pest +208 -0
- trilogy/scripts/dependency/src/python_bindings.rs +311 -0
- trilogy/scripts/dependency/src/resolver.rs +716 -0
- trilogy/scripts/dependency/tests/base.preql +3 -0
- trilogy/scripts/dependency/tests/cli_integration.rs +377 -0
- trilogy/scripts/dependency/tests/customer.preql +6 -0
- trilogy/scripts/dependency/tests/main.preql +9 -0
- trilogy/scripts/dependency/tests/orders.preql +7 -0
- trilogy/scripts/dependency/tests/test_data/base.preql +9 -0
- trilogy/scripts/dependency/tests/test_data/consumer.preql +1 -0
- trilogy/scripts/dependency.py +323 -0
- trilogy/scripts/display.py +555 -0
- trilogy/scripts/environment.py +59 -0
- trilogy/scripts/fmt.py +32 -0
- trilogy/scripts/ingest.py +487 -0
- trilogy/scripts/ingest_helpers/__init__.py +1 -0
- trilogy/scripts/ingest_helpers/foreign_keys.py +123 -0
- trilogy/scripts/ingest_helpers/formatting.py +93 -0
- trilogy/scripts/ingest_helpers/typing.py +161 -0
- trilogy/scripts/init.py +105 -0
- trilogy/scripts/parallel_execution.py +762 -0
- trilogy/scripts/plan.py +189 -0
- trilogy/scripts/refresh.py +161 -0
- trilogy/scripts/run.py +79 -0
- trilogy/scripts/serve.py +202 -0
- trilogy/scripts/serve_helpers/__init__.py +41 -0
- trilogy/scripts/serve_helpers/file_discovery.py +142 -0
- trilogy/scripts/serve_helpers/index_generation.py +206 -0
- trilogy/scripts/serve_helpers/models.py +38 -0
- trilogy/scripts/single_execution.py +131 -0
- trilogy/scripts/testing.py +143 -0
- trilogy/scripts/trilogy.py +75 -0
- trilogy/std/__init__.py +0 -0
- trilogy/std/color.preql +3 -0
- trilogy/std/date.preql +13 -0
- trilogy/std/display.preql +18 -0
- trilogy/std/geography.preql +22 -0
- trilogy/std/metric.preql +15 -0
- trilogy/std/money.preql +67 -0
- trilogy/std/net.preql +14 -0
- trilogy/std/ranking.preql +7 -0
- trilogy/std/report.preql +5 -0
- trilogy/std/semantic.preql +6 -0
- trilogy/utility.py +34 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from click import group, option, pass_context
|
|
2
|
+
|
|
3
|
+
from trilogy.scripts.agent import agent
|
|
4
|
+
from trilogy.scripts.agent_info import agent_info
|
|
5
|
+
from trilogy.scripts.display import set_rich_mode, show_debug_mode
|
|
6
|
+
from trilogy.scripts.fmt import fmt
|
|
7
|
+
from trilogy.scripts.ingest import ingest
|
|
8
|
+
from trilogy.scripts.init import init
|
|
9
|
+
from trilogy.scripts.plan import plan
|
|
10
|
+
from trilogy.scripts.refresh import refresh
|
|
11
|
+
from trilogy.scripts.run import run
|
|
12
|
+
from trilogy.scripts.serve import serve
|
|
13
|
+
from trilogy.scripts.testing import integration, unit
|
|
14
|
+
|
|
15
|
+
set_rich_mode = set_rich_mode
|
|
16
|
+
|
|
17
|
+
# Default parallelism level
|
|
18
|
+
DEFAULT_PARALLELISM = 2
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
AGENT_NOTICE = """
|
|
22
|
+
NOTE FOR AI AGENTS (Claude, GPT, etc.): For comprehensive usage documentation,
|
|
23
|
+
run 'trilogy agent-info' to get a detailed AGENTS.md-style guide with all
|
|
24
|
+
commands, options, and usage examples.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@group(epilog=AGENT_NOTICE)
|
|
29
|
+
@option("--debug", default=False, help="Enable debug mode")
|
|
30
|
+
@pass_context
|
|
31
|
+
def cli(ctx, debug: bool):
|
|
32
|
+
"""Trilogy CLI - A beautiful data productivity tool."""
|
|
33
|
+
ctx.ensure_object(dict)
|
|
34
|
+
ctx.obj["DEBUG"] = debug
|
|
35
|
+
|
|
36
|
+
if debug:
|
|
37
|
+
show_debug_mode()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# Add commands to the group
|
|
41
|
+
cli.command("init")(init)
|
|
42
|
+
cli.command("ingest", context_settings=dict(ignore_unknown_options=True))(ingest)
|
|
43
|
+
cli.command("fmt", context_settings=dict(ignore_unknown_options=True))(fmt)
|
|
44
|
+
cli.command(
|
|
45
|
+
"unit",
|
|
46
|
+
context_settings=dict(
|
|
47
|
+
ignore_unknown_options=True,
|
|
48
|
+
),
|
|
49
|
+
)(unit)
|
|
50
|
+
cli.command(
|
|
51
|
+
"integration",
|
|
52
|
+
context_settings=dict(
|
|
53
|
+
ignore_unknown_options=True,
|
|
54
|
+
),
|
|
55
|
+
)(integration)
|
|
56
|
+
cli.command(
|
|
57
|
+
"run",
|
|
58
|
+
context_settings=dict(
|
|
59
|
+
ignore_unknown_options=True,
|
|
60
|
+
),
|
|
61
|
+
)(run)
|
|
62
|
+
cli.command("agent")(agent)
|
|
63
|
+
cli.command("agent-info")(agent_info)
|
|
64
|
+
cli.command("plan")(plan)
|
|
65
|
+
cli.command(
|
|
66
|
+
"refresh",
|
|
67
|
+
context_settings=dict(
|
|
68
|
+
ignore_unknown_options=True,
|
|
69
|
+
),
|
|
70
|
+
)(refresh)
|
|
71
|
+
cli.command("serve")(serve)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
if __name__ == "__main__":
|
|
75
|
+
cli()
|
trilogy/std/__init__.py
ADDED
|
File without changes
|
trilogy/std/color.preql
ADDED
trilogy/std/date.preql
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
type percent float; # Percentage value
|
|
4
|
+
|
|
5
|
+
def calc_percent(a, b, digits=-1) ->
|
|
6
|
+
case
|
|
7
|
+
when digits =-1 then
|
|
8
|
+
case
|
|
9
|
+
when b = 0 then 0.0::numeric
|
|
10
|
+
else (a/b)::numeric
|
|
11
|
+
end
|
|
12
|
+
else round((
|
|
13
|
+
case
|
|
14
|
+
when b = 0 then 0.0::float
|
|
15
|
+
else (a/b)::float
|
|
16
|
+
end
|
|
17
|
+
)::numeric, digits)
|
|
18
|
+
end::numeric::percent;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
## us types
|
|
4
|
+
type us_state_short string; # US state abbreviation - ex MA, CA, NY
|
|
5
|
+
type us_state string; # US state name - ex Massachusetts, California, New York
|
|
6
|
+
|
|
7
|
+
type us_zip_code string; # US ZIP code
|
|
8
|
+
|
|
9
|
+
## generic types
|
|
10
|
+
type latitude float; # Latitude in degrees
|
|
11
|
+
type longitude float; # Longitude in degrees
|
|
12
|
+
type lat_long string; # Latitude and longitude in degrees, as a coordinate pair
|
|
13
|
+
|
|
14
|
+
type city string; # City name
|
|
15
|
+
type country string; # Full Country Name
|
|
16
|
+
type country_code string; # ISO-3166 Country code - ex US, CA, GB
|
|
17
|
+
type timezone string; # Timezone name
|
|
18
|
+
type region string; # Region name
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## special formats
|
|
22
|
+
type geojson string; # GeoJSON format for geographic data
|
trilogy/std/metric.preql
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Length and distance units
|
|
2
|
+
type m numeric; # meters
|
|
3
|
+
type km numeric; # kilometers
|
|
4
|
+
type cm numeric; # centimeters
|
|
5
|
+
type mm numeric; # millimeters
|
|
6
|
+
|
|
7
|
+
# Mass units
|
|
8
|
+
type kg numeric; # kilograms
|
|
9
|
+
type g numeric; # grams
|
|
10
|
+
type tonne numeric; # metric tons (1000 kg)
|
|
11
|
+
|
|
12
|
+
# Force units
|
|
13
|
+
type n numeric; # newtons
|
|
14
|
+
type kn numeric; # kilonewtons (1000 N)
|
|
15
|
+
type mn numeric; # meganewtons (1,000,000 N)
|
trilogy/std/money.preql
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# generic currency types
|
|
2
|
+
|
|
3
|
+
# Major global currencies
|
|
4
|
+
type usd numeric; # US Dollar
|
|
5
|
+
type eur numeric; # Euro
|
|
6
|
+
type gbp numeric; # British Pound Sterling
|
|
7
|
+
type jpy numeric; # Japanese Yen
|
|
8
|
+
type chf numeric; # Swiss Franc
|
|
9
|
+
type cad numeric; # Canadian Dollar
|
|
10
|
+
type aud numeric; # Australian Dollar
|
|
11
|
+
type nzd numeric; # New Zealand Dollar
|
|
12
|
+
|
|
13
|
+
# Asian currencies
|
|
14
|
+
type cny numeric; # Chinese Yuan
|
|
15
|
+
type hkd numeric; # Hong Kong Dollar
|
|
16
|
+
type sgd numeric; # Singapore Dollar
|
|
17
|
+
type krw numeric; # South Korean Won
|
|
18
|
+
type inr numeric; # Indian Rupee
|
|
19
|
+
type thb numeric; # Thai Baht
|
|
20
|
+
type php numeric; # Philippine Peso
|
|
21
|
+
type myr numeric; # Malaysian Ringgit
|
|
22
|
+
type idr numeric; # Indonesian Rupiah
|
|
23
|
+
type vnd numeric; # Vietnamese Dong
|
|
24
|
+
|
|
25
|
+
# European currencies (non-Euro)
|
|
26
|
+
type sek numeric; # Swedish Krona
|
|
27
|
+
type nok numeric; # Norwegian Krone
|
|
28
|
+
type dkk numeric; # Danish Krone
|
|
29
|
+
type pln numeric; # Polish Zloty
|
|
30
|
+
type czk numeric; # Czech Koruna
|
|
31
|
+
type huf numeric; # Hungarian Forint
|
|
32
|
+
type ron numeric; # Romanian Leu
|
|
33
|
+
type bgn numeric; # Bulgarian Lev
|
|
34
|
+
type rub numeric; # Russian Ruble
|
|
35
|
+
|
|
36
|
+
# Middle Eastern currencies
|
|
37
|
+
type aed numeric; # UAE Dirham
|
|
38
|
+
type sar numeric; # Saudi Riyal
|
|
39
|
+
type qar numeric; # Qatari Riyal
|
|
40
|
+
type kwd numeric; # Kuwaiti Dinar
|
|
41
|
+
type bhd numeric; # Bahraini Dinar
|
|
42
|
+
type omr numeric; # Omani Rial
|
|
43
|
+
type jod numeric; # Jordanian Dinar
|
|
44
|
+
type ils numeric; # Israeli Shekel
|
|
45
|
+
type try numeric; # Turkish Lira
|
|
46
|
+
|
|
47
|
+
# African currencies
|
|
48
|
+
type zar numeric; # South African Rand
|
|
49
|
+
type egp numeric; # Egyptian Pound
|
|
50
|
+
type ngn numeric; # Nigerian Naira
|
|
51
|
+
type mad numeric; # Moroccan Dirham
|
|
52
|
+
type kes numeric; # Kenyan Shilling
|
|
53
|
+
type ghs numeric; # Ghanaian Cedi
|
|
54
|
+
|
|
55
|
+
# Latin American currencies
|
|
56
|
+
type mxn numeric; # Mexican Peso
|
|
57
|
+
type brl numeric; # Brazilian Real
|
|
58
|
+
type ars numeric; # Argentine Peso
|
|
59
|
+
type cop numeric; # Colombian Peso
|
|
60
|
+
type pen numeric; # Peruvian Sol
|
|
61
|
+
type clp numeric; # Chilean Peso
|
|
62
|
+
type uyu numeric; # Uruguayan Peso
|
|
63
|
+
|
|
64
|
+
# Other notable currencies
|
|
65
|
+
type isk numeric; # Icelandic Krona
|
|
66
|
+
type xof numeric; # West African CFA Franc
|
|
67
|
+
type xaf numeric; # Central African CFA Franc
|
trilogy/std/net.preql
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
## network types
|
|
3
|
+
type url string; # URL string
|
|
4
|
+
type url_image string; # URL of an image
|
|
5
|
+
type domain string; # Domain name
|
|
6
|
+
type ip_net_mask string; # IP network mask
|
|
7
|
+
type ipv6_address string; # IPv6 address
|
|
8
|
+
type ipv4_address string; # IPv4 address
|
|
9
|
+
|
|
10
|
+
## communication types
|
|
11
|
+
type email_address string; # Email address, including @
|
|
12
|
+
|
|
13
|
+
## shared types
|
|
14
|
+
type suffix string; # A file suffix or extension, like .txt, .jpg, etc.
|
trilogy/std/report.preql
ADDED
trilogy/utility.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
from typing import Callable, List, TypeVar, Union
|
|
3
|
+
|
|
4
|
+
from trilogy.constants import DEFAULT_NAMESPACE
|
|
5
|
+
|
|
6
|
+
INT_HASH_SIZE = 16
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def string_to_hash(input: str) -> int:
|
|
10
|
+
return (
|
|
11
|
+
int(hashlib.sha256(input.encode("utf-8")).hexdigest(), 16) % 10**INT_HASH_SIZE
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
UniqueArg = TypeVar("UniqueArg")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def unique(inputs: List[UniqueArg], property: Union[str, Callable]) -> List[UniqueArg]:
|
|
19
|
+
final = []
|
|
20
|
+
dedupe = set()
|
|
21
|
+
if isinstance(property, str):
|
|
22
|
+
|
|
23
|
+
def getter(x):
|
|
24
|
+
return getattr(x, property, DEFAULT_NAMESPACE)
|
|
25
|
+
|
|
26
|
+
else:
|
|
27
|
+
getter = property
|
|
28
|
+
for input in inputs:
|
|
29
|
+
key = getter(input)
|
|
30
|
+
if key in dedupe:
|
|
31
|
+
continue
|
|
32
|
+
dedupe.add(key)
|
|
33
|
+
final.append(input)
|
|
34
|
+
return final
|