fdsempy 1.3.0__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.
- fdsempy-1.3.0/PKG-INFO +14 -0
- fdsempy-1.3.0/fdsempy/__init__.py +0 -0
- fdsempy-1.3.0/fdsempy/fdsempy.py +376 -0
- fdsempy-1.3.0/fdsempy.egg-info/PKG-INFO +14 -0
- fdsempy-1.3.0/fdsempy.egg-info/SOURCES.txt +8 -0
- fdsempy-1.3.0/fdsempy.egg-info/dependency_links.txt +1 -0
- fdsempy-1.3.0/fdsempy.egg-info/requires.txt +6 -0
- fdsempy-1.3.0/fdsempy.egg-info/top_level.txt +1 -0
- fdsempy-1.3.0/setup.cfg +4 -0
- fdsempy-1.3.0/setup.py +15 -0
fdsempy-1.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fdsempy
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: Fairday Sempy - semantic model utilities
|
|
5
|
+
Author: Peter Johnson - Fairday Research Limited
|
|
6
|
+
Requires-Dist: semantic-link-labs
|
|
7
|
+
Requires-Dist: pandas
|
|
8
|
+
Requires-Dist: json
|
|
9
|
+
Requires-Dist: requests
|
|
10
|
+
Requires-Dist: sempy
|
|
11
|
+
Requires-Dist: notebookutils
|
|
12
|
+
Dynamic: author
|
|
13
|
+
Dynamic: requires-dist
|
|
14
|
+
Dynamic: summary
|
|
File without changes
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
#######################################
|
|
2
|
+
# fdsempy.py
|
|
3
|
+
# (c)2025 Fairday Research Limited
|
|
4
|
+
# Dependencies: semantic-link-labs
|
|
5
|
+
#######################################
|
|
6
|
+
|
|
7
|
+
### imports ###
|
|
8
|
+
import pandas as pd
|
|
9
|
+
import json
|
|
10
|
+
import requests
|
|
11
|
+
from sempy.fabric import list_tables, list_columns, list_workspaces
|
|
12
|
+
from sempy_labs import deploy_semantic_model, refresh_semantic_model
|
|
13
|
+
from sempy_labs.directlake import update_direct_lake_model_connection
|
|
14
|
+
from sempy_labs.environment import list_environments
|
|
15
|
+
from sempy_labs.report import clone_report
|
|
16
|
+
from sempy_labs.tom import connect_semantic_model
|
|
17
|
+
from sempy_labs.warehouse import get_warehouse_columns
|
|
18
|
+
from notebookutils.notebook import list, getDefinition, updateDefinition, update, create
|
|
19
|
+
from notebookutils.lakehouse import get as lhGet
|
|
20
|
+
from notebookutils.credentials import getToken
|
|
21
|
+
|
|
22
|
+
########################################
|
|
23
|
+
# Helper functions
|
|
24
|
+
########################################
|
|
25
|
+
def _wh_convert_dtype(input_data_type: str) -> str:
|
|
26
|
+
|
|
27
|
+
if not input_data_type:
|
|
28
|
+
return None
|
|
29
|
+
|
|
30
|
+
input_data_type = input_data_type.lower()
|
|
31
|
+
|
|
32
|
+
data_type_mapping = {
|
|
33
|
+
"varchar": "String",
|
|
34
|
+
"int": "Int64",
|
|
35
|
+
"tinyint": "Int64",
|
|
36
|
+
"smallint": "Int64",
|
|
37
|
+
"bigint": "Int64",
|
|
38
|
+
"boolean": "Boolean",
|
|
39
|
+
"timestamp": "DateTime",
|
|
40
|
+
"date": "DateTime",
|
|
41
|
+
"decimal": "Double",
|
|
42
|
+
"numeric": "Double",
|
|
43
|
+
"double": "Double",
|
|
44
|
+
"float": "Double",
|
|
45
|
+
"binary": "Boolean",
|
|
46
|
+
"bit": "Boolean",
|
|
47
|
+
"long": "Int64",
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if input_data_type.startswith("decimal"):
|
|
51
|
+
return "Double"
|
|
52
|
+
elif input_data_type.startswith("datetime"):
|
|
53
|
+
return "DateTime"
|
|
54
|
+
|
|
55
|
+
return data_type_mapping.get(input_data_type)
|
|
56
|
+
|
|
57
|
+
########################################
|
|
58
|
+
# Version
|
|
59
|
+
########################################
|
|
60
|
+
def libver():
|
|
61
|
+
print("fdsempy.py (c)2025 Fairday Research Ltd\nVersion 1.3.0 - July 2026")
|
|
62
|
+
|
|
63
|
+
########################################
|
|
64
|
+
# Add warehouse table to semantic model
|
|
65
|
+
########################################
|
|
66
|
+
def sempy_add_warehouse_table(workspace: str, dataset: str, table_name: str, warehouse: str, schema: str, source: str):
|
|
67
|
+
# get meta data of warehouse columns
|
|
68
|
+
meta_df = get_warehouse_columns(warehouse=warehouse, workspace=workspace)
|
|
69
|
+
# filter on target schema & table
|
|
70
|
+
tbl_meta_df = meta_df[(meta_df['Schema'] == schema) & (meta_df['Table Name'] == source)]
|
|
71
|
+
|
|
72
|
+
with connect_semantic_model(dataset=dataset, readonly=False, workspace=workspace) as tom:
|
|
73
|
+
# create table
|
|
74
|
+
tom.add_table(name=table_name)
|
|
75
|
+
tom.add_entity_partition(table_name=table_name, entity_name=source, schema_name=schema)
|
|
76
|
+
|
|
77
|
+
# iterate through columns and convert SQ data types to SM data types
|
|
78
|
+
# then add the columns to the new table
|
|
79
|
+
count = 0
|
|
80
|
+
for _, row in tbl_meta_df.iterrows():
|
|
81
|
+
cname = row["Column Name"]
|
|
82
|
+
src_dtype = row["Data Type"]
|
|
83
|
+
tom_dtype = _wh_convert_dtype(src_dtype)
|
|
84
|
+
tom.add_data_column(
|
|
85
|
+
table_name=table_name,
|
|
86
|
+
column_name=cname,
|
|
87
|
+
source_column=cname,
|
|
88
|
+
data_type=tom_dtype,
|
|
89
|
+
)
|
|
90
|
+
count+=1
|
|
91
|
+
print(f"\U00002705 Columns added: {count}")
|
|
92
|
+
|
|
93
|
+
########################################
|
|
94
|
+
# Format semantic model tables
|
|
95
|
+
########################################
|
|
96
|
+
def sempy_format_tables(workspace: str, dataset: str):
|
|
97
|
+
|
|
98
|
+
# read tables & columns from model
|
|
99
|
+
tables = list_tables(dataset=dataset, workspace=workspace)
|
|
100
|
+
|
|
101
|
+
# read tables from mapping file and join to sempy list
|
|
102
|
+
fmtmap = pd.read_csv("/lakehouse/default/Files/fdsempymap.csv").set_index("Name")
|
|
103
|
+
fmttabs = tables.join(fmtmap, on="Name", how="left", lsuffix="_sm", rsuffix="_map")
|
|
104
|
+
|
|
105
|
+
with connect_semantic_model(dataset=dataset, readonly=False, workspace=workspace) as tom:
|
|
106
|
+
count = 0
|
|
107
|
+
# rename tables
|
|
108
|
+
for _, row in fmttabs.iterrows():
|
|
109
|
+
tablename = row["Name"]
|
|
110
|
+
# rename table
|
|
111
|
+
if not pd.isna(row["Model Name"]):
|
|
112
|
+
print(f"Changing {tablename} to {row['Model Name']}")
|
|
113
|
+
tablename = row["Name"]
|
|
114
|
+
tab = tom.model.Tables[tablename]
|
|
115
|
+
tab.Name = row["Model Name"]
|
|
116
|
+
tom.add_changed_property(tab,"Name")
|
|
117
|
+
count+=1
|
|
118
|
+
if not pd.isna(row["Description_map"]):
|
|
119
|
+
tab.Description = row["Description_map"]
|
|
120
|
+
tom.add_changed_property(tab,"Description")
|
|
121
|
+
print(f"\U00002705 Formatted tables: {count}")
|
|
122
|
+
|
|
123
|
+
########################################
|
|
124
|
+
# Format semantic model columns
|
|
125
|
+
########################################
|
|
126
|
+
def sempy_format_columns(workspace: str, dataset: str, table: str):
|
|
127
|
+
|
|
128
|
+
cols = list_columns(dataset=dataset, workspace=workspace)
|
|
129
|
+
hide_n = 0
|
|
130
|
+
date_n = 0
|
|
131
|
+
dp6_n = 0
|
|
132
|
+
dp4_n = 0
|
|
133
|
+
int_n = 0
|
|
134
|
+
with connect_semantic_model(dataset=dataset, readonly=False, workspace=workspace) as tom:
|
|
135
|
+
print("Updating columns")
|
|
136
|
+
# go through columns making changes
|
|
137
|
+
for _, row in cols.iterrows():
|
|
138
|
+
if (table == None) | (row["Table Name"] == table):
|
|
139
|
+
# hide columns
|
|
140
|
+
if row["Column Name"].startswith("scd_") | row["Column Name"].startswith("nk_"): # hide scd/nk columns
|
|
141
|
+
#print(f"Set {row['Table Name']}.{row['Column Name']} to hidden")
|
|
142
|
+
tom.update_column(table_name=row["Table Name"], column_name=row["Column Name"], hidden=True)
|
|
143
|
+
hide_n+=1
|
|
144
|
+
if row["Column Name"].endswith("id") & (row["Data Type"] == "Int64"): # hide numeric id columns
|
|
145
|
+
#print(f"Set {row['Table Name']}.{row['Column Name']} to hidden")
|
|
146
|
+
tom.update_column(table_name=row["Table Name"], column_name=row["Column Name"], hidden=True)
|
|
147
|
+
hide_n+=1
|
|
148
|
+
# set date format
|
|
149
|
+
if row["Data Type"].startswith("Date") & (not row["Column Name"].startswith("scd")): # change non scd date formats
|
|
150
|
+
#print(f"Set {row['Table Name']}.{row['Column Name']} to short date")
|
|
151
|
+
tom.update_column(table_name=row["Table Name"], column_name=row["Column Name"], format_string='Short Date')
|
|
152
|
+
date_n+=1
|
|
153
|
+
if (row["Data Type"] == "Double") & ("(6 dp)" in row['Column Name']): # decimal type add comma, set dps
|
|
154
|
+
# set thousands separator (comma) and six dps
|
|
155
|
+
#print(f"Set {row['Table Name']}.{row['Column Name']} to #,0.000000")
|
|
156
|
+
tom.update_column(table_name=row["Table Name"], column_name=row["Column Name"], format_string='#,0.000000')
|
|
157
|
+
dp6_n+=1
|
|
158
|
+
elif row["Data Type"] == "Double": # decimal type add comma, set dps
|
|
159
|
+
# set thousands separator (comma) and four dps
|
|
160
|
+
#print(f"Set {row['Table Name']}.{row['Column Name']} to #,0.0000")
|
|
161
|
+
tom.update_column(table_name=row["Table Name"], column_name=row["Column Name"], format_string='#,0.0000')
|
|
162
|
+
dp4_n+=1
|
|
163
|
+
if row["Data Type"].startswith("Int") & (not row["Column Name"].endswith("id")) & (not row["Table Name"].startswith("Date")) & (not row["Table Name"].startswith("dim_date")): # int type addcomma
|
|
164
|
+
# set thousands separator (comma) and four dps
|
|
165
|
+
#print(f"Set {row['Table Name']}.{row['Column Name']} to #,0")
|
|
166
|
+
tom.update_column(table_name=row["Table Name"], column_name=row["Column Name"], format_string='#,0')
|
|
167
|
+
int_n+=1
|
|
168
|
+
print(f"\U00002705 Hidden: {hide_n}, Date formatted: {date_n}, 6dp formatted {dp6_n}, 4dp formatted: {dp4_n}, int formatted: {int_n}")
|
|
169
|
+
|
|
170
|
+
########################################
|
|
171
|
+
# Deploy Notebooks to Workspace
|
|
172
|
+
########################################
|
|
173
|
+
def sempy_notebooks_deploy(src_workspace_id: str, tgt_workspace_id: str, core_notebooks: list, util_notebooks: list=[]):
|
|
174
|
+
## get the id of the DWH environment in the target workspace (assume that it exists)
|
|
175
|
+
dwh_env = 'DWH'
|
|
176
|
+
env_df = list_environments(tgt_workspace_id) # get all the environments in the target workspace
|
|
177
|
+
tgt_dwh_env_id = env_df.loc[env_df['Environment Name']==dwh_env]['Environment Id'].values[0] # get the id of the first one that matches DWH
|
|
178
|
+
|
|
179
|
+
# create a dict in the expected json format
|
|
180
|
+
tgt_env_ws_dict = dict(environmentId=tgt_dwh_env_id, workspaceId=tgt_workspace_id)
|
|
181
|
+
|
|
182
|
+
# feedback to user
|
|
183
|
+
aw_df = list_workspaces()
|
|
184
|
+
|
|
185
|
+
src_name = aw_df[aw_df['Id'] == src_workspace_id]['Name'].values[0]
|
|
186
|
+
tgt_name = aw_df[aw_df['Id'] == tgt_workspace_id]['Name'].values[0]
|
|
187
|
+
|
|
188
|
+
print(f"\U00002139 Cloning notebooks from \033[1m{src_name}\033[0m to \033[1m{tgt_name}\033[0m")
|
|
189
|
+
for nb in core_notebooks:
|
|
190
|
+
print(f"\U000025AA {nb}")
|
|
191
|
+
if "_dev_" in tgt_name:
|
|
192
|
+
for nb in util_notebooks:
|
|
193
|
+
print(f"\U000025AA {nb}")
|
|
194
|
+
|
|
195
|
+
count = 0
|
|
196
|
+
# get a list of artifacts in target
|
|
197
|
+
print(f"Building lists from target workspace...")
|
|
198
|
+
namelist = []
|
|
199
|
+
artifacts = list(tgt_workspace_id)
|
|
200
|
+
for artifact in artifacts:
|
|
201
|
+
if (artifact.type == 'Notebook') & ((artifact.displayName in core_notebooks) | (("_dev_" in tgt_name) & (artifact.displayName in util_notebooks))):
|
|
202
|
+
namelist.append(artifact.displayName)
|
|
203
|
+
|
|
204
|
+
# Loop through notebook artifacts in source:
|
|
205
|
+
artifacts = list(src_workspace_id)
|
|
206
|
+
for artifact in artifacts:
|
|
207
|
+
json_hacked = False
|
|
208
|
+
if (artifact.type == 'Notebook') & ((artifact.displayName in core_notebooks) | (("_dev_" in tgt_name) & (artifact.displayName in util_notebooks))):
|
|
209
|
+
print(f"\U000025B6 Processing {artifact.displayName}")
|
|
210
|
+
nb_name = artifact.displayName # grab notebook name
|
|
211
|
+
print(f"\U0000231B getting definition of {artifact.displayName} from {src_name}...")
|
|
212
|
+
content = getDefinition(name=nb_name,workspaceId=src_workspace_id) # get notebook ipynb definition
|
|
213
|
+
|
|
214
|
+
### hack of target nb json ###
|
|
215
|
+
# turn content into json
|
|
216
|
+
json_def = json.loads(content)
|
|
217
|
+
|
|
218
|
+
# if content contains a default lakehouse name
|
|
219
|
+
if json_def.get("metadata", {}).get("dependencies", {}).get("lakehouse", {}).get("default_lakehouse_name", {}):
|
|
220
|
+
# grab the default lakehouse name
|
|
221
|
+
src_nb_lh_name = json_def.get("metadata", {}).get("dependencies", {}).get("lakehouse", {}).get("default_lakehouse_name", {})
|
|
222
|
+
|
|
223
|
+
# then get id of tgt lakehouse id with same name as default lakehouse in src notebook
|
|
224
|
+
tgt_lh = lhGet(name=src_nb_lh_name, workspaceId=tgt_workspace_id)
|
|
225
|
+
tgt_def_lh_id = tgt_lh.id
|
|
226
|
+
|
|
227
|
+
# then create a dict containing tgt lakehouse id and workspace id
|
|
228
|
+
tgt_def_lh_dict_list = [dict(id=tgt_def_lh_id)]
|
|
229
|
+
|
|
230
|
+
# if the known_lakehouses key is populated in the json
|
|
231
|
+
if json_def.get("metadata", {}).get("dependencies", {}).get("lakehouse", {}).get("known_lakehouses", {}):
|
|
232
|
+
print(f"\U0000231B modifying [lakehouses] json key...")
|
|
233
|
+
json_def["metadata"]["dependencies"]["lakehouse"]["known_lakehouses"] = tgt_def_lh_dict_list
|
|
234
|
+
json_def["metadata"]["dependencies"]["lakehouse"]["default_lakehouse"] = tgt_def_lh_id
|
|
235
|
+
json_def["metadata"]["dependencies"]["lakehouse"]["default_lakehouse_workspace_id"] = workspaceId=tgt_workspace_id
|
|
236
|
+
#print(f"\U0000267B new: %s" % (json_def["metadata"]["dependencies"]["lakehouse"]))
|
|
237
|
+
json_hacked = True
|
|
238
|
+
|
|
239
|
+
# if the environment is populated in the json
|
|
240
|
+
if json_def.get("metadata", {}).get("dependencies", {}).get("environment", {}):
|
|
241
|
+
print("\U0000231B modifying [environment] json key...")
|
|
242
|
+
json_def["metadata"]["dependencies"]["environment"] = tgt_env_ws_dict
|
|
243
|
+
#print(f"\U0000267B new: %s" % (json_def["metadata"]["dependencies"]["environment"]))
|
|
244
|
+
json_hacked = True
|
|
245
|
+
|
|
246
|
+
if json_hacked:
|
|
247
|
+
# save this definition to a string. Otherwise we'll use the original content
|
|
248
|
+
content = json.dumps(json_def)
|
|
249
|
+
|
|
250
|
+
# check if notebook exists in target (from artifact list)
|
|
251
|
+
if nb_name in namelist: # if your name's not on the list you ain't getting in mate
|
|
252
|
+
print(f"\U0000231B updating {nb_name} in {tgt_name}")
|
|
253
|
+
# if it does exist update the content:
|
|
254
|
+
updateDefinition(name=nb_name, content=content, workspaceId=tgt_workspace_id)
|
|
255
|
+
# then update the properties
|
|
256
|
+
update(name=nb_name, newName=nb_name, description=artifact.description, workspaceId=tgt_workspace_id)
|
|
257
|
+
count+=1
|
|
258
|
+
else:
|
|
259
|
+
# if notebook doesn't exist create it
|
|
260
|
+
print(f"\U0000231B creating {nb_name} in {tgt_name}")
|
|
261
|
+
create(name=nb_name, description=artifact.description, content=content, workspaceId=tgt_workspace_id)
|
|
262
|
+
count+=1
|
|
263
|
+
print(f"\U0001F197 {artifact.displayName} complete\n")
|
|
264
|
+
|
|
265
|
+
# and we're done
|
|
266
|
+
print(f"\U00002705 Done. Notebooks processed: {count}")
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
########################################
|
|
271
|
+
# Deploy Models to Workspace
|
|
272
|
+
########################################
|
|
273
|
+
def sempy_models_deploy(src_workspace: str, tgt_workspace: str, models: list, source: str, source_type: str, refresh: bool=False):
|
|
274
|
+
count = 0
|
|
275
|
+
for dataset in models:
|
|
276
|
+
deploy_semantic_model(
|
|
277
|
+
source_dataset=dataset,
|
|
278
|
+
source_workspace=src_workspace,
|
|
279
|
+
target_dataset=dataset,
|
|
280
|
+
target_workspace=tgt_workspace,
|
|
281
|
+
refresh_target_dataset=False,
|
|
282
|
+
overwrite=True
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
# update models to point to local workspace
|
|
286
|
+
update_direct_lake_model_connection(
|
|
287
|
+
dataset = dataset,
|
|
288
|
+
workspace = tgt_workspace,
|
|
289
|
+
source = source,
|
|
290
|
+
source_type = source_type,
|
|
291
|
+
source_workspace = tgt_workspace
|
|
292
|
+
)
|
|
293
|
+
count+=1
|
|
294
|
+
# refresh the model if selected
|
|
295
|
+
if refresh:
|
|
296
|
+
refresh_semantic_model(dataset=dataset, workspace=tgt_workspace)
|
|
297
|
+
print(f"\U00002705 Models deployed: {count}")
|
|
298
|
+
|
|
299
|
+
########################################
|
|
300
|
+
# Deploy Reports to Workspace
|
|
301
|
+
########################################
|
|
302
|
+
def sempy_reports_deploy(src_workspace: str, tgt_workspace: str, dataset: str, reports: list):
|
|
303
|
+
count = 0
|
|
304
|
+
for report in reports:
|
|
305
|
+
clone_report(
|
|
306
|
+
report = report,
|
|
307
|
+
cloned_report = report,
|
|
308
|
+
workspace = src_workspace,
|
|
309
|
+
target_workspace = tgt_workspace,
|
|
310
|
+
target_dataset = dataset,
|
|
311
|
+
target_dataset_workspace = tgt_workspace
|
|
312
|
+
)
|
|
313
|
+
count+=1
|
|
314
|
+
print(f"\U00002705 Reports deployed: {count}")
|
|
315
|
+
|
|
316
|
+
########################################
|
|
317
|
+
# Advanvced Deploy Reports to Workspace
|
|
318
|
+
########################################
|
|
319
|
+
def sempy_reports_deploy_adv(src_workspace: str, tgt_workspace: str, dataset: str, ds_workspace: str, reports: list):
|
|
320
|
+
count = 0
|
|
321
|
+
for (src_report, tgt_report) in reports:
|
|
322
|
+
if tgt_report == None:
|
|
323
|
+
tgt_report = src_report
|
|
324
|
+
clone_report(
|
|
325
|
+
report = src_report,
|
|
326
|
+
cloned_report = tgt_report,
|
|
327
|
+
workspace = src_workspace,
|
|
328
|
+
target_workspace = tgt_workspace,
|
|
329
|
+
target_dataset = dataset,
|
|
330
|
+
target_dataset_workspace = ds_workspace
|
|
331
|
+
)
|
|
332
|
+
count+=1
|
|
333
|
+
print(f"\U00002705 Reports deployed: {count}")
|
|
334
|
+
|
|
335
|
+
########################################
|
|
336
|
+
# Bind SM Connection (REST API call)
|
|
337
|
+
########################################
|
|
338
|
+
def set_conn(workspace_id: str, semantic_model_id: str, connection_id: str, connection_path: str) -> str:
|
|
339
|
+
# Authentication/token stuff
|
|
340
|
+
access_url = "https://analysis.windows.net/powerbi/api"
|
|
341
|
+
token = getToken(access_url)
|
|
342
|
+
|
|
343
|
+
bind_url = f"https://api.fabric.microsoft.com/v1/workspaces/{workspace_id}/semanticModels/{semantic_model_id}/bindConnection"
|
|
344
|
+
|
|
345
|
+
headers = {
|
|
346
|
+
"Authorization": f"Bearer {token}",
|
|
347
|
+
"Content-Type": "application/json"
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
payload = {
|
|
351
|
+
"connectionBinding": {
|
|
352
|
+
"id": connection_id,
|
|
353
|
+
"connectivityType": "ShareableCloud",
|
|
354
|
+
"connectionDetails": {
|
|
355
|
+
"type": "SQL",
|
|
356
|
+
"path": connection_path
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
# do it
|
|
362
|
+
response = requests.post(bind_url, json=payload, headers=headers)
|
|
363
|
+
if response.status_code == 200:
|
|
364
|
+
ret = 'Success'
|
|
365
|
+
else:
|
|
366
|
+
ret = f'Error: {response.text}'
|
|
367
|
+
return ret
|
|
368
|
+
|
|
369
|
+
########################################
|
|
370
|
+
# Connection selector
|
|
371
|
+
########################################
|
|
372
|
+
def sel_conn(connections: list, workspace: str) -> str:
|
|
373
|
+
for ws, conn in connections:
|
|
374
|
+
if ws == workspace:
|
|
375
|
+
ret = conn
|
|
376
|
+
return(ret)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fdsempy
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: Fairday Sempy - semantic model utilities
|
|
5
|
+
Author: Peter Johnson - Fairday Research Limited
|
|
6
|
+
Requires-Dist: semantic-link-labs
|
|
7
|
+
Requires-Dist: pandas
|
|
8
|
+
Requires-Dist: json
|
|
9
|
+
Requires-Dist: requests
|
|
10
|
+
Requires-Dist: sempy
|
|
11
|
+
Requires-Dist: notebookutils
|
|
12
|
+
Dynamic: author
|
|
13
|
+
Dynamic: requires-dist
|
|
14
|
+
Dynamic: summary
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fdsempy
|
fdsempy-1.3.0/setup.cfg
ADDED
fdsempy-1.3.0/setup.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
setup(name='fdsempy',
|
|
3
|
+
description='Fairday Sempy - semantic model utilities',
|
|
4
|
+
author='Peter Johnson - Fairday Research Limited',
|
|
5
|
+
version='1.3.0',
|
|
6
|
+
packages=['fdsempy'],
|
|
7
|
+
install_requires=[
|
|
8
|
+
'semantic-link-labs',
|
|
9
|
+
'pandas',
|
|
10
|
+
'json',
|
|
11
|
+
'requests',
|
|
12
|
+
'sempy',
|
|
13
|
+
'notebookutils'
|
|
14
|
+
]
|
|
15
|
+
)
|