semantic-link-labs 0.12.1__py3-none-any.whl → 0.12.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 semantic-link-labs might be problematic. Click here for more details.
- {semantic_link_labs-0.12.1.dist-info → semantic_link_labs-0.12.2.dist-info}/METADATA +3 -2
- {semantic_link_labs-0.12.1.dist-info → semantic_link_labs-0.12.2.dist-info}/RECORD +27 -23
- sempy_labs/__init__.py +6 -0
- sempy_labs/_a_lib_info.py +1 -1
- sempy_labs/_data_access_security.py +98 -0
- sempy_labs/_data_pipelines.py +23 -9
- sempy_labs/_dataflows.py +0 -1
- sempy_labs/_deployment_pipelines.py +49 -27
- sempy_labs/_eventstreams.py +9 -1
- sempy_labs/_helper_functions.py +16 -1
- sempy_labs/_job_scheduler.py +63 -33
- sempy_labs/_labels.py +4 -6
- sempy_labs/_model_dependencies.py +5 -2
- sempy_labs/_warehouses.py +55 -0
- sempy_labs/admin/__init__.py +6 -0
- sempy_labs/admin/_sharing_links.py +110 -0
- sempy_labs/graph/__init__.py +12 -0
- sempy_labs/graph/_groups.py +157 -2
- sempy_labs/graph/_users.py +162 -0
- sempy_labs/lakehouse/_shortcuts.py +16 -11
- sempy_labs/report/_bpareporttemplate/.pbi/localSettings.json +9 -0
- sempy_labs/report/_bpareporttemplate/.platform +11 -0
- sempy_labs/report/_reportwrapper.py +53 -6
- sempy_labs/tom/_model.py +22 -9
- {semantic_link_labs-0.12.1.dist-info → semantic_link_labs-0.12.2.dist-info}/WHEEL +0 -0
- {semantic_link_labs-0.12.1.dist-info → semantic_link_labs-0.12.2.dist-info}/licenses/LICENSE +0 -0
- {semantic_link_labs-0.12.1.dist-info → semantic_link_labs-0.12.2.dist-info}/top_level.txt +0 -0
sempy_labs/graph/_users.py
CHANGED
|
@@ -301,3 +301,165 @@ def send_mail(
|
|
|
301
301
|
if attachments:
|
|
302
302
|
printout += f" with {len(attachments)} attachment(s)"
|
|
303
303
|
print(f"{printout}.")
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
@log
|
|
307
|
+
def create_user(
|
|
308
|
+
display_name: str,
|
|
309
|
+
user_principal_name: str,
|
|
310
|
+
mail_nickname: str,
|
|
311
|
+
password: str,
|
|
312
|
+
account_enabled: bool = True,
|
|
313
|
+
force_change_password_next_sign_in: bool = True,
|
|
314
|
+
):
|
|
315
|
+
"""
|
|
316
|
+
Creates a new user.
|
|
317
|
+
|
|
318
|
+
This is a wrapper function for the following API: `Create User <https://learn.microsoft.com/graph/api/user-post-users>`_.
|
|
319
|
+
|
|
320
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
321
|
+
|
|
322
|
+
Parameters
|
|
323
|
+
----------
|
|
324
|
+
display_name : str
|
|
325
|
+
The name to display in the address book for the user.
|
|
326
|
+
user_principal_name : str
|
|
327
|
+
The user principal name (someuser@contoso.com).
|
|
328
|
+
mail_nickname : str
|
|
329
|
+
The mail alias for the user.
|
|
330
|
+
password : str
|
|
331
|
+
The initial password for the user.
|
|
332
|
+
account_enabled : bool, default=True
|
|
333
|
+
Whether the account is enabled. Default is True.
|
|
334
|
+
force_change_password_next_sign_in : bool, default=True
|
|
335
|
+
Whether the user must change their password on next sign-in. Default is True.
|
|
336
|
+
"""
|
|
337
|
+
|
|
338
|
+
payload = {
|
|
339
|
+
"accountEnabled": account_enabled,
|
|
340
|
+
"displayName": display_name,
|
|
341
|
+
"mailNickname": mail_nickname,
|
|
342
|
+
"userPrincipalName": user_principal_name,
|
|
343
|
+
"passwordProfile": {
|
|
344
|
+
"forceChangePasswordNextSignIn": force_change_password_next_sign_in,
|
|
345
|
+
"password": password,
|
|
346
|
+
},
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
_base_api(
|
|
350
|
+
request="users",
|
|
351
|
+
client="graph",
|
|
352
|
+
status_codes=201,
|
|
353
|
+
payload=payload,
|
|
354
|
+
method="post",
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
print(f"{icons.green_dot} The '{display_name}' user has been created successfully.")
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
@log
|
|
361
|
+
def delete_user(user: str | UUID):
|
|
362
|
+
"""
|
|
363
|
+
Deletes a user.
|
|
364
|
+
|
|
365
|
+
This is a wrapper function for the following API: `Delete User <https://learn.microsoft.com/graph/api/user-delete>`_.
|
|
366
|
+
|
|
367
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
368
|
+
|
|
369
|
+
Parameters
|
|
370
|
+
----------
|
|
371
|
+
user : str | uuid.UUID
|
|
372
|
+
The user name or ID.
|
|
373
|
+
"""
|
|
374
|
+
|
|
375
|
+
user_id = resolve_user_id(user)
|
|
376
|
+
|
|
377
|
+
_base_api(
|
|
378
|
+
request=f"users/{user_id}",
|
|
379
|
+
client="graph",
|
|
380
|
+
status_codes=204,
|
|
381
|
+
method="delete",
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
print(f"{icons.green_dot} The '{user}' user has been deleted successfully.")
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
@log
|
|
388
|
+
def update_user(
|
|
389
|
+
user: str | UUID,
|
|
390
|
+
display_name: Optional[str] = None,
|
|
391
|
+
user_principal_name: Optional[str] = None,
|
|
392
|
+
given_name: Optional[str] = None,
|
|
393
|
+
surname: Optional[str] = None,
|
|
394
|
+
job_title: Optional[str] = None,
|
|
395
|
+
mail_nickname: Optional[str] = None,
|
|
396
|
+
my_site: Optional[str] = None,
|
|
397
|
+
office_location: Optional[str] = None,
|
|
398
|
+
account_enabled: Optional[bool] = None,
|
|
399
|
+
):
|
|
400
|
+
"""
|
|
401
|
+
Updates a user's properties.
|
|
402
|
+
|
|
403
|
+
This is a wrapper function for the following API: `Update user <https://learn.microsoft.com/graph/api/user-update>`_.
|
|
404
|
+
|
|
405
|
+
Service Principal Authentication is required (see `here <https://github.com/microsoft/semantic-link-labs/blob/main/notebooks/Service%20Principal.ipynb>`_ for examples).
|
|
406
|
+
|
|
407
|
+
Parameters
|
|
408
|
+
----------
|
|
409
|
+
user : str | uuid.UUID
|
|
410
|
+
The user name or ID.
|
|
411
|
+
display_name : str, default=None
|
|
412
|
+
The name displayed in the address book for the user.
|
|
413
|
+
user_principal_name : str, default=None
|
|
414
|
+
The user principal name (UPN) of the user.
|
|
415
|
+
given_name : str, default=None
|
|
416
|
+
The given name (first name) of the user.
|
|
417
|
+
surname : str, default=None
|
|
418
|
+
The user's surname (family name or last name).
|
|
419
|
+
job_title : str, default=None
|
|
420
|
+
The user's job title.
|
|
421
|
+
mail_nickname : str, default=None
|
|
422
|
+
The mail alias for the user. This property must be specified when a user is created.
|
|
423
|
+
my_site : str, default=None
|
|
424
|
+
The URL for the user's personal site.
|
|
425
|
+
office_location : str, default=None
|
|
426
|
+
The office location in the user's place of business.
|
|
427
|
+
account_enabled : bool, default=None
|
|
428
|
+
Whether the account is enabled. If None, the property will not be updated.
|
|
429
|
+
"""
|
|
430
|
+
|
|
431
|
+
user_id = resolve_user_id(user)
|
|
432
|
+
|
|
433
|
+
payload = {}
|
|
434
|
+
if display_name is not None:
|
|
435
|
+
payload["displayName"] = display_name
|
|
436
|
+
if mail_nickname is not None:
|
|
437
|
+
payload["mailNickname"] = mail_nickname
|
|
438
|
+
if user_principal_name is not None:
|
|
439
|
+
payload["userPrincipalName"] = user_principal_name
|
|
440
|
+
if given_name is not None:
|
|
441
|
+
payload["givenName"] = given_name
|
|
442
|
+
if job_title is not None:
|
|
443
|
+
payload["jobTitle"] = job_title
|
|
444
|
+
if my_site is not None:
|
|
445
|
+
payload["mySite"] = my_site
|
|
446
|
+
if office_location is not None:
|
|
447
|
+
payload["officeLocation"] = office_location
|
|
448
|
+
if surname is not None:
|
|
449
|
+
payload["surname"] = surname
|
|
450
|
+
if account_enabled is not None and isinstance(account_enabled, bool):
|
|
451
|
+
payload["accountEnabled"] = account_enabled
|
|
452
|
+
|
|
453
|
+
if not payload:
|
|
454
|
+
print(f"{icons.info} No properties to update.")
|
|
455
|
+
return
|
|
456
|
+
|
|
457
|
+
_base_api(
|
|
458
|
+
request=f"users/{user_id}",
|
|
459
|
+
client="graph",
|
|
460
|
+
status_codes=204,
|
|
461
|
+
payload=payload,
|
|
462
|
+
method="patch",
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
print(f"{icons.green_dot} The '{user}' user has been updated successfully.")
|
|
@@ -396,17 +396,22 @@ def list_shortcuts(
|
|
|
396
396
|
# Cache and use it to getitem type and name
|
|
397
397
|
source_item_type = None
|
|
398
398
|
source_item_name = None
|
|
399
|
-
|
|
400
|
-
source_items_df[
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
dfI
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
399
|
+
try:
|
|
400
|
+
dfI = source_items_df[
|
|
401
|
+
source_items_df["Workspace Id"] == source_workspace_id
|
|
402
|
+
]
|
|
403
|
+
if dfI.empty:
|
|
404
|
+
dfI = fabric.list_items(workspace=source_workspace_id)
|
|
405
|
+
source_items_df = pd.concat(
|
|
406
|
+
[source_items_df, dfI], ignore_index=True
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
dfI_filt = dfI[dfI["Id"] == source_item_id]
|
|
410
|
+
if not dfI_filt.empty:
|
|
411
|
+
source_item_type = dfI_filt["Type"].iloc[0]
|
|
412
|
+
source_item_name = dfI_filt["Display Name"].iloc[0]
|
|
413
|
+
except Exception:
|
|
414
|
+
pass
|
|
410
415
|
|
|
411
416
|
rows.append(
|
|
412
417
|
{
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0",
|
|
3
|
+
"remoteArtifacts": [
|
|
4
|
+
{
|
|
5
|
+
"reportId": "6a91c344-dba8-4ebf-bedb-e07134f2a204"
|
|
6
|
+
}
|
|
7
|
+
],
|
|
8
|
+
"securityBindingsSignature": "AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAMAVu7l76YU6Sl11KOiJdgQAAAAACAAAAAAAQZgAAAAEAACAAAAD1Ty+c7tZLT9/Sjguxhn/5ivfLWfUMNtgudyJ3BKzzZgAAAAAOgAAAAAIAACAAAABAyGf+iKMwvmNtcoRczjgebeIm0nlc9SFYTBYv3N7yvVADAADQN3JsIsvJUcKKc9WMo2EhiE21odezpd35tb+yudHwA/RYhypMA3fwiCTwArLefBZQ3vZ7KYh4MjihXS07i9o1XVqxAmDoli83Yhs/Wei+0HIfYOT5HOVHLUEul5x41Yx/7Bdfhc881SK6IoaJogBdwsiJVxPne+niMYqJQA6qLEPyJ33g6ucUxLA40lwdbN2cMWFzRn6tymmicDPwH0hcGPDMWwseAU+OuUeidkneRWhUGs6lkiiXLiO6kmY5RKq+S4FdtR19/e1B6EjAd94zSw+M5jQzYxn4eCZzWYiB+8Zd/jy07lfyLoGwagNqiQzbcNONqQd5w0n+8/+n4zGkBi2UojfRXoGaYDirQeZMTbt3pfPx2PArxsJ8dF0iT634pHiCF1ZFdtY+79JaFLUUG+Yf7JJv8IxuuuF74tAp4NYmuOij4hTDaf8Jafa5IoRVh7ICkwrjJyVQ8dG7I3tr0VvR+toBPG3Zlbm9BijcaBxhh1AINhnRAIkENOnPFQVH7l3Ml7B60H8Tst6ic3ihCCMYjtmN+NNWqFrJKT2trilh5TAxN+ei4H5fPwM9S7zb2bH5jhExcYTtoe7iCzxOvBsoYoFM+7FMjn9R2FATNICktYdbKDo1Of+u4oZ1+RsvBHQBVaMhSCoZ7+K5T5pZayNK3V2UID3wOuLOYvouxXXr4NVFsdgiV2oMuxTWeqmd/4bLxeqe3uTkGFmQU4mumF2YVsNbdO3IcRXhhrCCZ27ffzXBsH+lE3EhusD37Z0dsVbVVlG8AHXCh7Atgd8n73/eSI5mvj36DCOSRBVauItIATIa2FXueKA7vU6lRDYBSX8FCC2qkeN6dWpMoN5uXXEBsb5Yot1Fgrovcyl5lk7rh772Xon4FaIYFHZpklsY3JK5EXp3bF8UOE6ByN1ZucmkGgYRcTT/up/Uc86TLN6env9XXL4FQYPlReiOGWKBLVi9OoXGRLDshspniULtV3EwQ6WsjF2AyQ+WdLj3bbWKzG5Mg9jvANLrjycZAGWskh4X5JDGiv4TiJmnYQ/xPZAKKiowpVIHikLeG76uXFI+bxtpihV9+DaEJy4UxisHQxwuvUsQs38u3SHgpJmT8CNssZl41+T/IJdoQwJFLUAAAACnUQZGV9DvcOyrj8HBpXBVB5PuOQDxLB4HZOevHqCB5dc5z787E93B51QmN7I15fF6GCdWwN5f94gv1er2dtN3"
|
|
9
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://developer.microsoft.com/json-schemas/fabric/gitIntegration/platformProperties/2.0.0/schema.json",
|
|
3
|
+
"metadata": {
|
|
4
|
+
"type": "Report",
|
|
5
|
+
"displayName": "BPAReport"
|
|
6
|
+
},
|
|
7
|
+
"config": {
|
|
8
|
+
"version": "2.0",
|
|
9
|
+
"logicalId": "a201f2cd-fd25-465f-bfbc-33b151e38b31"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -935,9 +935,6 @@ class ReportWrapper:
|
|
|
935
935
|
"""
|
|
936
936
|
Shows a list of all modified `visual interactions <https://learn.microsoft.com/power-bi/create-reports/service-reports-visual-interactions?tabs=powerbi-desktop>`_ used in the report.
|
|
937
937
|
|
|
938
|
-
Parameters
|
|
939
|
-
----------
|
|
940
|
-
|
|
941
938
|
Returns
|
|
942
939
|
-------
|
|
943
940
|
pandas.DataFrame
|
|
@@ -980,6 +977,56 @@ class ReportWrapper:
|
|
|
980
977
|
|
|
981
978
|
return df
|
|
982
979
|
|
|
980
|
+
def list_visual_calculations(self) -> pd.DataFrame:
|
|
981
|
+
"""
|
|
982
|
+
Shows a list of all `visual calculations <https://learn.microsoft.com/power-bi/transform-model/desktop-visual-calculations-overview>`_.
|
|
983
|
+
|
|
984
|
+
Returns
|
|
985
|
+
-------
|
|
986
|
+
pandas.DataFrame
|
|
987
|
+
A pandas dataframe containing a list of all visual calculations within the report.
|
|
988
|
+
"""
|
|
989
|
+
|
|
990
|
+
self._ensure_pbir()
|
|
991
|
+
|
|
992
|
+
columns = {
|
|
993
|
+
"Page Display Name": "str",
|
|
994
|
+
"Visual Name": "str",
|
|
995
|
+
"Name": "str",
|
|
996
|
+
"Language": "str",
|
|
997
|
+
"Expression": "str",
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
df = _create_dataframe(columns=columns)
|
|
1001
|
+
visual_mapping = self._visual_page_mapping()
|
|
1002
|
+
|
|
1003
|
+
rows = []
|
|
1004
|
+
for v in self.__all_visuals():
|
|
1005
|
+
path = v.get("path")
|
|
1006
|
+
payload = v.get("payload")
|
|
1007
|
+
page_name = visual_mapping.get(path)[0]
|
|
1008
|
+
page_display_name = visual_mapping.get(path)[1]
|
|
1009
|
+
visual_name = payload.get("name")
|
|
1010
|
+
matches = parse("$..field.NativeVisualCalculation").find(payload)
|
|
1011
|
+
if matches:
|
|
1012
|
+
for match in matches:
|
|
1013
|
+
m = match.value
|
|
1014
|
+
rows.append(
|
|
1015
|
+
{
|
|
1016
|
+
"Page Display Name": page_display_name,
|
|
1017
|
+
"Page Name": page_name,
|
|
1018
|
+
"Visual Name": visual_name,
|
|
1019
|
+
"Name": m.get("Name"),
|
|
1020
|
+
"Language": m.get("Language"),
|
|
1021
|
+
"Expression": m.get("Expression"),
|
|
1022
|
+
}
|
|
1023
|
+
)
|
|
1024
|
+
|
|
1025
|
+
if rows:
|
|
1026
|
+
df = pd.DataFrame(rows, columns=list(columns.keys()))
|
|
1027
|
+
|
|
1028
|
+
return df
|
|
1029
|
+
|
|
983
1030
|
def list_pages(self) -> pd.DataFrame:
|
|
984
1031
|
"""
|
|
985
1032
|
Shows a list of all pages in the report.
|
|
@@ -1651,7 +1698,7 @@ class ReportWrapper:
|
|
|
1651
1698
|
bookmarks = [
|
|
1652
1699
|
o
|
|
1653
1700
|
for o in self._report_definition.get("parts")
|
|
1654
|
-
if o.get("path").endswith("
|
|
1701
|
+
if o.get("path").endswith(".bookmark.json")
|
|
1655
1702
|
]
|
|
1656
1703
|
|
|
1657
1704
|
rows = []
|
|
@@ -2069,8 +2116,8 @@ class ReportWrapper:
|
|
|
2069
2116
|
df = dfCV[dfCV["Used in Report"] == False]
|
|
2070
2117
|
|
|
2071
2118
|
if not df.empty:
|
|
2072
|
-
cv_remove = df["Custom Visual Name"].values
|
|
2073
|
-
cv_remove_display = df["Custom Visual Display Name"].values
|
|
2119
|
+
cv_remove = df["Custom Visual Name"].values
|
|
2120
|
+
cv_remove_display = df["Custom Visual Display Name"].values
|
|
2074
2121
|
else:
|
|
2075
2122
|
print(
|
|
2076
2123
|
f"{icons.red_dot} There are no unnecessary custom visuals in the '{self._report_name}' report within the '{self._workspace_name}' workspace."
|
sempy_labs/tom/_model.py
CHANGED
|
@@ -6,7 +6,7 @@ import os
|
|
|
6
6
|
import json
|
|
7
7
|
from datetime import datetime
|
|
8
8
|
from decimal import Decimal
|
|
9
|
-
from
|
|
9
|
+
from sempy_labs._helper_functions import (
|
|
10
10
|
format_dax_object_name,
|
|
11
11
|
generate_guid,
|
|
12
12
|
_make_list_unique,
|
|
@@ -17,10 +17,11 @@ from .._helper_functions import (
|
|
|
17
17
|
resolve_item_id,
|
|
18
18
|
resolve_lakehouse_id,
|
|
19
19
|
_validate_weight,
|
|
20
|
+
_get_url_prefix,
|
|
20
21
|
)
|
|
21
|
-
from
|
|
22
|
-
from
|
|
23
|
-
from
|
|
22
|
+
from sempy_labs._list_functions import list_relationships
|
|
23
|
+
from sempy_labs._refresh_semantic_model import refresh_semantic_model
|
|
24
|
+
from sempy_labs.directlake._dl_helper import check_fallback_reason
|
|
24
25
|
from contextlib import contextmanager
|
|
25
26
|
from typing import List, Iterator, Optional, Union, TYPE_CHECKING, Literal
|
|
26
27
|
from sempy._utils._log import log
|
|
@@ -28,7 +29,9 @@ import sempy_labs._icons as icons
|
|
|
28
29
|
import ast
|
|
29
30
|
from uuid import UUID
|
|
30
31
|
import sempy_labs._authentication as auth
|
|
31
|
-
from
|
|
32
|
+
from sempy_labs.lakehouse._lakehouse import lakehouse_attached
|
|
33
|
+
import requests
|
|
34
|
+
from sempy.fabric.exceptions import FabricHTTPException
|
|
32
35
|
|
|
33
36
|
|
|
34
37
|
if TYPE_CHECKING:
|
|
@@ -4601,8 +4604,12 @@ class TOMWrapper:
|
|
|
4601
4604
|
pandas.DataFrame
|
|
4602
4605
|
A pandas dataframe showing the updated measure(s) and their new description(s).
|
|
4603
4606
|
"""
|
|
4607
|
+
import notebookutils
|
|
4608
|
+
|
|
4604
4609
|
icons.sll_tags.append("GenerateMeasureDescriptions")
|
|
4605
4610
|
|
|
4611
|
+
prefix = _get_url_prefix()
|
|
4612
|
+
|
|
4606
4613
|
df = pd.DataFrame(
|
|
4607
4614
|
columns=["Table Name", "Measure Name", "Expression", "Description"]
|
|
4608
4615
|
)
|
|
@@ -4655,11 +4662,17 @@ class TOMWrapper:
|
|
|
4655
4662
|
"modelItems"
|
|
4656
4663
|
].append(new_item)
|
|
4657
4664
|
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4665
|
+
token = notebookutils.credentials.getToken("pbi")
|
|
4666
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
4667
|
+
response = requests.post(
|
|
4668
|
+
f"{prefix}/explore/v202304/nl2nl/completions",
|
|
4669
|
+
headers=headers,
|
|
4670
|
+
json=payload,
|
|
4662
4671
|
)
|
|
4672
|
+
if response.status_code != 200:
|
|
4673
|
+
raise FabricHTTPException(
|
|
4674
|
+
f"Failed to retrieve descriptions: {response.text}"
|
|
4675
|
+
)
|
|
4663
4676
|
|
|
4664
4677
|
for item in response.json().get("modelItems", []):
|
|
4665
4678
|
ms_name = item["urn"]
|
|
File without changes
|
{semantic_link_labs-0.12.1.dist-info → semantic_link_labs-0.12.2.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|