pytrilogy 0.0.1.118__py3-none-any.whl → 0.0.2.2__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.
- {pytrilogy-0.0.1.118.dist-info → pytrilogy-0.0.2.2.dist-info}/METADATA +1 -1
- pytrilogy-0.0.2.2.dist-info/RECORD +82 -0
- {pytrilogy-0.0.1.118.dist-info → pytrilogy-0.0.2.2.dist-info}/WHEEL +1 -1
- trilogy/__init__.py +1 -1
- trilogy/constants.py +6 -0
- trilogy/core/enums.py +7 -2
- trilogy/core/env_processor.py +43 -19
- trilogy/core/functions.py +1 -0
- trilogy/core/models.py +674 -146
- trilogy/core/optimization.py +31 -28
- trilogy/core/optimizations/inline_constant.py +4 -1
- trilogy/core/optimizations/inline_datasource.py +25 -4
- trilogy/core/optimizations/predicate_pushdown.py +94 -54
- trilogy/core/processing/concept_strategies_v3.py +69 -39
- trilogy/core/processing/graph_utils.py +3 -3
- trilogy/core/processing/node_generators/__init__.py +0 -2
- trilogy/core/processing/node_generators/basic_node.py +30 -17
- trilogy/core/processing/node_generators/filter_node.py +3 -1
- trilogy/core/processing/node_generators/node_merge_node.py +345 -96
- trilogy/core/processing/node_generators/rowset_node.py +18 -16
- trilogy/core/processing/node_generators/select_node.py +45 -85
- trilogy/core/processing/nodes/__init__.py +2 -0
- trilogy/core/processing/nodes/base_node.py +22 -5
- trilogy/core/processing/nodes/filter_node.py +3 -0
- trilogy/core/processing/nodes/group_node.py +20 -2
- trilogy/core/processing/nodes/merge_node.py +32 -18
- trilogy/core/processing/nodes/select_node_v2.py +17 -3
- trilogy/core/processing/utility.py +100 -8
- trilogy/core/query_processor.py +77 -24
- trilogy/dialect/base.py +11 -46
- trilogy/dialect/bigquery.py +1 -1
- trilogy/dialect/common.py +11 -0
- trilogy/dialect/duckdb.py +1 -1
- trilogy/dialect/presto.py +1 -0
- trilogy/hooks/graph_hook.py +50 -5
- trilogy/hooks/query_debugger.py +1 -0
- trilogy/parsing/common.py +8 -5
- trilogy/parsing/parse_engine.py +52 -27
- trilogy/parsing/render.py +20 -9
- trilogy/parsing/trilogy.lark +13 -8
- pytrilogy-0.0.1.118.dist-info/RECORD +0 -83
- trilogy/core/processing/node_generators/concept_merge_node.py +0 -214
- {pytrilogy-0.0.1.118.dist-info → pytrilogy-0.0.2.2.dist-info}/LICENSE.md +0 -0
- {pytrilogy-0.0.1.118.dist-info → pytrilogy-0.0.2.2.dist-info}/entry_points.txt +0 -0
- {pytrilogy-0.0.1.118.dist-info → pytrilogy-0.0.2.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
trilogy/__init__.py,sha256=mSeU_j02wb5aKd5vDcHQJdZaoG1AB96bCjUn2tIVpwk,290
|
|
2
|
+
trilogy/compiler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
trilogy/constants.py,sha256=KIvi-cgU4R9urNgDdGiCsRkCrzjAfM4xGHhZb1SVy2w,881
|
|
4
|
+
trilogy/engine.py,sha256=R5ubIxYyrxRExz07aZCUfrTsoXCHQ8DKFTDsobXdWdA,1102
|
|
5
|
+
trilogy/executor.py,sha256=5cRbU4Rj7p1pNV76rfp1pz704Hx_0q8_O8HFURjgXxQ,11016
|
|
6
|
+
trilogy/parser.py,sha256=UtuqSiGiCjpMAYgo1bvNq-b7NSzCA5hzbUW31RXaMII,281
|
|
7
|
+
trilogy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
trilogy/utility.py,sha256=zM__8r29EsyDW7K9VOHz8yvZC2bXFzh7xKy3cL7GKsk,707
|
|
9
|
+
trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
trilogy/core/constants.py,sha256=LL8NLvxb3HRnAjvofyLRXqQJijLcYiXAQYQzGarVD-g,128
|
|
11
|
+
trilogy/core/enums.py,sha256=DWKPuShM_DbyAenjNFOAxcIH2l0QC9WgIwqZKPQqk_o,5850
|
|
12
|
+
trilogy/core/env_processor.py,sha256=Wpy-iiduBwHntTsQTYWBO1O0i3Ij9_VoL3d4IWDEoj4,2126
|
|
13
|
+
trilogy/core/environment_helpers.py,sha256=mzBDHhdF9ssZ_-LY8CcaM_ddfJavkpRYrFImUd3cjXI,5972
|
|
14
|
+
trilogy/core/ergonomics.py,sha256=w3gwXdgrxNHCuaRdyKg73t6F36tj-wIjQf47WZkHmJk,1465
|
|
15
|
+
trilogy/core/exceptions.py,sha256=NvV_4qLOgKXbpotgRf7c8BANDEvHxlqRPaA53IThQ2o,561
|
|
16
|
+
trilogy/core/functions.py,sha256=xISGHMiUR9hFyoZe2l3VLTMO6UEtyGHQcMuovzlVRqw,9492
|
|
17
|
+
trilogy/core/graph_models.py,sha256=oJUMSpmYhqXlavckHLpR07GJxuQ8dZ1VbB1fB0KaS8c,2036
|
|
18
|
+
trilogy/core/internal.py,sha256=jNGFHKENnbMiMCtAgsnLZYVSENDK4b5ALecXFZpTDzQ,1075
|
|
19
|
+
trilogy/core/models.py,sha256=4iwlTfHzzmbDhm9vt7zgExMqY1xKyQL-fVG5Nrm-YTU,134722
|
|
20
|
+
trilogy/core/optimization.py,sha256=iX8BCh2BIEPJ6cYlcn7piDKFfig47azphhyqkwkYJM4,4291
|
|
21
|
+
trilogy/core/query_processor.py,sha256=PROehLEOMOuKy1EAUeIgdfGq1LrJsX0N7Z2qDED6S30,17580
|
|
22
|
+
trilogy/core/optimizations/__init__.py,sha256=pxRzNzd2g8oRMy4f_ub5va6bNS2pd4hnyp9JBzTKc1E,300
|
|
23
|
+
trilogy/core/optimizations/base_optimization.py,sha256=tWWT-xnTbnEU-mNi_isMNbywm8B9WTRsNFwGpeh3rqE,468
|
|
24
|
+
trilogy/core/optimizations/inline_constant.py,sha256=kHNyc2UoaPVdYfVAPAFwnWuk4sJ_IF5faRtVcDOrBtw,1110
|
|
25
|
+
trilogy/core/optimizations/inline_datasource.py,sha256=KiwZ4fnRnSOVK8zzdwMAkafszo3fNn5LY8xgb0X1CbI,3194
|
|
26
|
+
trilogy/core/optimizations/predicate_pushdown.py,sha256=mduJn4zzKmLVNUja60ZlY6LlNp389OwjEbq2Rj8K6co,5389
|
|
27
|
+
trilogy/core/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
+
trilogy/core/processing/concept_strategies_v3.py,sha256=hmbck3a23N61HfMwC2z3lxA6Yms9TP7Lm3Aw7GiDcMA,23765
|
|
29
|
+
trilogy/core/processing/graph_utils.py,sha256=aq-kqk4Iado2HywDxWEejWc-7PGO6Oa-ZQLAM6XWPHw,1199
|
|
30
|
+
trilogy/core/processing/utility.py,sha256=hgfPfz5FlghN8edIVGTQ21eDUof5EMvnl3Vu64hjfqY,13289
|
|
31
|
+
trilogy/core/processing/node_generators/__init__.py,sha256=-mzYkRsaRNa_dfTckYkKVFSR8h8a3ihEiPJDU_tAmDo,672
|
|
32
|
+
trilogy/core/processing/node_generators/basic_node.py,sha256=uD6noJOgrtmhjb-1aa-vD8sQ97s9Tya6wbso7V_AdyE,2819
|
|
33
|
+
trilogy/core/processing/node_generators/common.py,sha256=liZDth7mvhkF_sUFXK7JitJsiaKD132w3ySLbF7l-nE,8956
|
|
34
|
+
trilogy/core/processing/node_generators/filter_node.py,sha256=5B7UCK84A9lGgJ7EjCiC7YGWWM1xPyQGHkBwZgYypFM,4585
|
|
35
|
+
trilogy/core/processing/node_generators/group_node.py,sha256=xWI1xNIXEOj6jlRGD9hcv2_vVNvY6lpzJl6pQ8HuFBE,2988
|
|
36
|
+
trilogy/core/processing/node_generators/group_to_node.py,sha256=BzPdYwzoo8gRMH7BDffTTXq4z-mjfCEzvfB5I-P0_nw,2941
|
|
37
|
+
trilogy/core/processing/node_generators/multiselect_node.py,sha256=vP84dnLQy6dtypi6mUbt9sMAcmmrTgQ1Oz4GI6X1IEo,6421
|
|
38
|
+
trilogy/core/processing/node_generators/node_merge_node.py,sha256=YivTVrTEUJuQbQAHFVB2lUD4mJYQ-kTVVpwY4oT9A-Y,14664
|
|
39
|
+
trilogy/core/processing/node_generators/rowset_node.py,sha256=2ROd2c1_o4h5sbnDdaiL1o9UiiwyYw-B6OKyfHYNe0A,6188
|
|
40
|
+
trilogy/core/processing/node_generators/select_node.py,sha256=XGcz74XsWv5POWhV2gGC_jbi7T9g7sY-VtP3sjlppFc,19057
|
|
41
|
+
trilogy/core/processing/node_generators/unnest_node.py,sha256=6CH66eGwpadNX7TzUhWZ8aqIisOtQeHINbLV6X3QBUk,1779
|
|
42
|
+
trilogy/core/processing/node_generators/window_node.py,sha256=9nXUXUgQrNczU1gaOqhOZPNzCUxw-lkxt0R7HORI6ss,2582
|
|
43
|
+
trilogy/core/processing/nodes/__init__.py,sha256=-8ONG7Nqa6sNLpst5wNNyMigyaHRfUKGdE3xce8E3mM,3998
|
|
44
|
+
trilogy/core/processing/nodes/base_node.py,sha256=q1G4FO3Q4OuboWL8EaJgJ4jcnnqM9QsothMIcF2ot1g,11161
|
|
45
|
+
trilogy/core/processing/nodes/filter_node.py,sha256=ImUHYj5G5eHbOtki-ZMR31Op38wKOjR1xu_ETiE_D6I,1932
|
|
46
|
+
trilogy/core/processing/nodes/group_node.py,sha256=5dqGlonXG5Ou7HRSsTStbM1KyxeDSZROz9qKTjOUMEc,5166
|
|
47
|
+
trilogy/core/processing/nodes/merge_node.py,sha256=W7ryL9rceylCQGNgcuGY-dSiNoIz8qrbpJXKzg_Niwo,14056
|
|
48
|
+
trilogy/core/processing/nodes/select_node_v2.py,sha256=COu-WPuyabGAc3HTkJB-_7eNzR4OgxIL4YDuZIRrST0,7179
|
|
49
|
+
trilogy/core/processing/nodes/unnest_node.py,sha256=JFtm90IVM-46aCYkTNIaJah6v9ApAfonjVhcVM1HmDE,1903
|
|
50
|
+
trilogy/core/processing/nodes/window_node.py,sha256=X7qxLUKd3tekjUUsmH_4vz5b-U89gMnGd04VBxuu2Ns,1280
|
|
51
|
+
trilogy/dialect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
52
|
+
trilogy/dialect/base.py,sha256=EZCP3xU8-B4xpU1pFFew4CGtkNWignbyPll6OTENFLg,29832
|
|
53
|
+
trilogy/dialect/bigquery.py,sha256=BAN2o0SOuLvzLYLV7Sc11woapS5L7Cc36aMBeaphW5k,2905
|
|
54
|
+
trilogy/dialect/common.py,sha256=5jdOHWIj3Xv8F8y5mnyWHLjxD_we2fncM-ZnNetJP7U,2781
|
|
55
|
+
trilogy/dialect/config.py,sha256=tLVEMctaTDhUgARKXUNfHUcIolGaALkQ0RavUvXAY4w,2994
|
|
56
|
+
trilogy/dialect/duckdb.py,sha256=JQPnR5F39iDQXfTccKhbq7xWYGzYc0dPpn5vo0Qd_Vk,3076
|
|
57
|
+
trilogy/dialect/enums.py,sha256=4NdpsydBpDn6jnh0JzFz5VvQEtnShErWtWHVyT6TNpw,3948
|
|
58
|
+
trilogy/dialect/postgres.py,sha256=r47xbCA7nfEYENofiVfLZ-SnReNfDmUmW4OSHVkkP4E,3206
|
|
59
|
+
trilogy/dialect/presto.py,sha256=ouSVNbs7e3eEc20emLfxKyRjdINSibPGUFL4X9OwboA,3163
|
|
60
|
+
trilogy/dialect/snowflake.py,sha256=N3HknYgN-fjD7BLX1Ucj-ss_ku2Ox8DgLsF3BIHutHo,2941
|
|
61
|
+
trilogy/dialect/sql_server.py,sha256=HX68vNTrcDaTnOxe6Zbx_PBgrO42e2VuThxO6CYQ2cY,3026
|
|
62
|
+
trilogy/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
63
|
+
trilogy/hooks/base_hook.py,sha256=Xkb-A2qCHozYjum0A36zOy5PwTVwrP3NLDF0U2GpgHo,1100
|
|
64
|
+
trilogy/hooks/graph_hook.py,sha256=onHvMQPwj_KOS3HOTpRFiy7QLLKAiycq2MzJ_Q0Oh5Y,2467
|
|
65
|
+
trilogy/hooks/query_debugger.py,sha256=NDChfkPmmW-KINa4TaQmDe_adGiwsKFdGLDSYpbodeU,4282
|
|
66
|
+
trilogy/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
67
|
+
trilogy/parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
|
+
trilogy/parsing/common.py,sha256=8MDRPccWymtVkHVQMzESjL5tOH79flWU5jo6Ys-C5UQ,5963
|
|
69
|
+
trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
|
|
70
|
+
trilogy/parsing/exceptions.py,sha256=92E5i2frv5hj9wxObJZsZqj5T6bglvPzvdvco_vW1Zk,38
|
|
71
|
+
trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
72
|
+
trilogy/parsing/parse_engine.py,sha256=rjTDs8AhJ6NjPCugfZCTdu7d_bUOSC9M8MAl9KmURNw,57763
|
|
73
|
+
trilogy/parsing/render.py,sha256=Gy_6wVYPwYLf35Iota08sbqveuWILtUhI8MYStcvtJM,12174
|
|
74
|
+
trilogy/parsing/trilogy.lark,sha256=Zn5UHqiNoVKa76r1af9KND0TNdsLIeHpyG3hJjUOOTQ,11000
|
|
75
|
+
trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
|
+
trilogy/scripts/trilogy.py,sha256=PHxvv6f2ODv0esyyhWxlARgra8dVhqQhYl0lTrSyVNo,3729
|
|
77
|
+
pytrilogy-0.0.2.2.dist-info/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
|
|
78
|
+
pytrilogy-0.0.2.2.dist-info/METADATA,sha256=rjwj8b_CWxQc82n5HJfPTBYlhtVKNUwIhAkWLusfA7g,7876
|
|
79
|
+
pytrilogy-0.0.2.2.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
|
|
80
|
+
pytrilogy-0.0.2.2.dist-info/entry_points.txt,sha256=0petKryjvvtEfTlbZC1AuMFumH_WQ9v8A19LvoS6G6c,54
|
|
81
|
+
pytrilogy-0.0.2.2.dist-info/top_level.txt,sha256=cAy__NW_eMAa_yT9UnUNlZLFfxcg6eimUAZ184cdNiE,8
|
|
82
|
+
pytrilogy-0.0.2.2.dist-info/RECORD,,
|
trilogy/__init__.py
CHANGED
trilogy/constants.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from logging import getLogger
|
|
2
2
|
from dataclasses import dataclass, field
|
|
3
3
|
from enum import Enum
|
|
4
|
+
import random
|
|
4
5
|
|
|
5
6
|
logger = getLogger("trilogy")
|
|
6
7
|
|
|
@@ -34,7 +35,12 @@ class Config:
|
|
|
34
35
|
validate_missing: bool = True
|
|
35
36
|
optimizations: Optimizations = field(default_factory=Optimizations)
|
|
36
37
|
|
|
38
|
+
def set_random_seed(self, seed: int):
|
|
39
|
+
random.seed(seed)
|
|
40
|
+
|
|
37
41
|
|
|
38
42
|
CONFIG = Config()
|
|
39
43
|
|
|
44
|
+
CONFIG.set_random_seed(42)
|
|
45
|
+
|
|
40
46
|
CONFIG.strict_mode = True
|
trilogy/core/enums.py
CHANGED
|
@@ -43,7 +43,6 @@ class PurposeLineage(Enum):
|
|
|
43
43
|
ROOT = "root"
|
|
44
44
|
ROWSET = "rowset"
|
|
45
45
|
MULTISELECT = "multiselect"
|
|
46
|
-
MERGE = "merge"
|
|
47
46
|
|
|
48
47
|
|
|
49
48
|
class Granularity(Enum):
|
|
@@ -263,7 +262,6 @@ class DatePart(Enum):
|
|
|
263
262
|
class SourceType(Enum):
|
|
264
263
|
FILTER = "filter"
|
|
265
264
|
SELECT = "select"
|
|
266
|
-
MERGE = "merge"
|
|
267
265
|
ABSTRACT = "abstract"
|
|
268
266
|
DIRECT_SELECT = "direct_select"
|
|
269
267
|
GROUP = "group"
|
|
@@ -271,8 +269,15 @@ class SourceType(Enum):
|
|
|
271
269
|
UNNEST = "unnest"
|
|
272
270
|
CONSTANT = "constant"
|
|
273
271
|
ROWSET = "rowset"
|
|
272
|
+
MERGE = "merge"
|
|
274
273
|
|
|
275
274
|
|
|
276
275
|
class ShowCategory(Enum):
|
|
277
276
|
MODELS = "models"
|
|
278
277
|
CONCEPTS = "concepts"
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class SelectFiltering(Enum):
|
|
281
|
+
NONE = "none"
|
|
282
|
+
EXPLICIT = "explicit" # the filtering contains only selected values
|
|
283
|
+
IMPLICIT = "implicit" # the filtering contains unselected values
|
trilogy/core/env_processor.py
CHANGED
|
@@ -3,37 +3,61 @@ from trilogy.core.graph_models import (
|
|
|
3
3
|
concept_to_node,
|
|
4
4
|
datasource_to_node,
|
|
5
5
|
)
|
|
6
|
-
from trilogy.core.models import Environment
|
|
7
|
-
from trilogy.core.enums import PurposeLineage
|
|
6
|
+
from trilogy.core.models import Environment, Concept, Datasource
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
def
|
|
11
|
-
|
|
9
|
+
def add_concept(concept: Concept, g: ReferenceGraph):
|
|
10
|
+
g.add_node(concept)
|
|
11
|
+
# if we have sources, recursively add them
|
|
12
|
+
node_name = concept_to_node(concept)
|
|
13
|
+
if concept.sources:
|
|
14
|
+
for source in concept.sources:
|
|
15
|
+
generic = source.with_default_grain()
|
|
16
|
+
g.add_edge(generic, node_name)
|
|
17
|
+
for _, pseudonym in concept.pseudonyms.items():
|
|
18
|
+
pseudonym = pseudonym.with_default_grain()
|
|
19
|
+
pseudonym_node = concept_to_node(pseudonym)
|
|
20
|
+
if pseudonym_node.split("@")[0] == node_name.split("@")[0]:
|
|
21
|
+
continue
|
|
22
|
+
g.add_edge(pseudonym_node, node_name, pseudonym=True)
|
|
23
|
+
g.add_edge(node_name, pseudonym_node, pseudonym=True)
|
|
24
|
+
add_concept(pseudonym, g)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def generate_adhoc_graph(
|
|
28
|
+
concepts: list[Concept],
|
|
29
|
+
datasources: list[Datasource],
|
|
30
|
+
restrict_to_listed: bool = False,
|
|
12
31
|
) -> ReferenceGraph:
|
|
13
32
|
g = ReferenceGraph()
|
|
14
33
|
|
|
15
34
|
# add all parsed concepts
|
|
16
|
-
for
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
node_name = concept_to_node(concept)
|
|
21
|
-
for source in concept.sources:
|
|
22
|
-
generic = source.with_default_grain()
|
|
23
|
-
g.add_edge(generic, node_name)
|
|
24
|
-
|
|
25
|
-
# link the concept to the generic source
|
|
26
|
-
if concept.derivation == PurposeLineage.MERGE:
|
|
27
|
-
g.add_edge(node_name, generic)
|
|
28
|
-
for _, dataset in environment.datasources.items():
|
|
35
|
+
for concept in concepts:
|
|
36
|
+
add_concept(concept, g)
|
|
37
|
+
|
|
38
|
+
for dataset in datasources:
|
|
29
39
|
node = datasource_to_node(dataset)
|
|
30
40
|
g.add_node(dataset, type="datasource", datasource=dataset)
|
|
31
41
|
for concept in dataset.concepts:
|
|
42
|
+
if restrict_to_listed:
|
|
43
|
+
if concept_to_node(concept) not in g.nodes:
|
|
44
|
+
continue
|
|
32
45
|
g.add_edge(node, concept)
|
|
33
46
|
g.add_edge(concept, node)
|
|
34
47
|
# if there is a key on a table at a different grain
|
|
35
48
|
# add an FK edge to the canonical source, if it exists
|
|
36
49
|
# for example, order ID on order product table
|
|
37
|
-
|
|
38
|
-
|
|
50
|
+
default = concept.with_default_grain()
|
|
51
|
+
if concept != default:
|
|
52
|
+
g.add_edge(concept, default)
|
|
53
|
+
g.add_edge(default, concept)
|
|
39
54
|
return g
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def generate_graph(
|
|
58
|
+
environment: Environment,
|
|
59
|
+
) -> ReferenceGraph:
|
|
60
|
+
|
|
61
|
+
return generate_adhoc_graph(
|
|
62
|
+
list(environment.concepts.values()), list(environment.datasources.values())
|
|
63
|
+
)
|