digitalhub 0.10.2__py3-none-any.whl → 0.11.0__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 digitalhub might be problematic. Click here for more details.

Files changed (72) hide show
  1. digitalhub/__init__.py +10 -0
  2. digitalhub/context/api.py +10 -4
  3. digitalhub/context/builder.py +35 -20
  4. digitalhub/context/context.py +35 -24
  5. digitalhub/entities/_base/entity/builder.py +11 -0
  6. digitalhub/entities/_base/executable/entity.py +52 -5
  7. digitalhub/entities/_base/material/utils.py +11 -11
  8. digitalhub/entities/_commons/enums.py +4 -0
  9. digitalhub/entities/_processors/base.py +15 -15
  10. digitalhub/entities/_processors/context.py +62 -15
  11. digitalhub/entities/_processors/utils.py +2 -2
  12. digitalhub/entities/builders.py +2 -0
  13. digitalhub/entities/function/_base/entity.py +3 -3
  14. digitalhub/entities/project/_base/builder.py +4 -0
  15. digitalhub/entities/project/_base/entity.py +5 -2
  16. digitalhub/entities/project/_base/models.py +18 -0
  17. digitalhub/entities/project/_base/spec.py +6 -0
  18. digitalhub/entities/project/crud.py +2 -13
  19. digitalhub/entities/run/_base/entity.py +6 -12
  20. digitalhub/entities/task/_base/entity.py +4 -4
  21. digitalhub/entities/task/_base/models.py +20 -2
  22. digitalhub/entities/trigger/__init__.py +0 -0
  23. digitalhub/entities/trigger/_base/__init__.py +0 -0
  24. digitalhub/entities/trigger/_base/builder.py +70 -0
  25. digitalhub/entities/trigger/_base/entity.py +34 -0
  26. digitalhub/entities/trigger/_base/spec.py +40 -0
  27. digitalhub/entities/trigger/_base/status.py +9 -0
  28. digitalhub/entities/trigger/crud.py +309 -0
  29. digitalhub/entities/trigger/lifecycle/__init__.py +0 -0
  30. digitalhub/entities/trigger/lifecycle/builder.py +19 -0
  31. digitalhub/entities/trigger/lifecycle/entity.py +32 -0
  32. digitalhub/entities/trigger/lifecycle/spec.py +38 -0
  33. digitalhub/entities/trigger/lifecycle/status.py +9 -0
  34. digitalhub/entities/trigger/scheduler/__init__.py +0 -0
  35. digitalhub/entities/trigger/scheduler/builder.py +19 -0
  36. digitalhub/entities/trigger/scheduler/entity.py +32 -0
  37. digitalhub/entities/trigger/scheduler/spec.py +29 -0
  38. digitalhub/entities/trigger/scheduler/status.py +9 -0
  39. digitalhub/entities/workflow/_base/entity.py +3 -3
  40. digitalhub/factory/factory.py +113 -26
  41. digitalhub/factory/utils.py +31 -14
  42. digitalhub/runtimes/_base.py +22 -11
  43. digitalhub/runtimes/builder.py +16 -3
  44. digitalhub/runtimes/enums.py +11 -1
  45. digitalhub/stores/client/dhcore/client.py +1 -0
  46. digitalhub/stores/client/dhcore/configurator.py +80 -11
  47. digitalhub/stores/client/dhcore/utils.py +1 -0
  48. digitalhub/stores/configurator/configurator.py +5 -2
  49. digitalhub/stores/configurator/enums.py +9 -0
  50. digitalhub/stores/configurator/ini_module.py +58 -4
  51. digitalhub/stores/data/api.py +2 -2
  52. digitalhub/stores/data/builder.py +5 -6
  53. digitalhub/stores/data/enums.py +11 -0
  54. digitalhub/stores/data/local/store.py +0 -3
  55. digitalhub/stores/data/remote/store.py +0 -3
  56. digitalhub/stores/data/s3/configurator.py +0 -20
  57. digitalhub/stores/data/s3/enums.py +2 -3
  58. digitalhub/stores/data/s3/store.py +4 -10
  59. digitalhub/stores/data/s3/utils.py +13 -18
  60. digitalhub/stores/data/sql/configurator.py +9 -22
  61. digitalhub/stores/data/sql/store.py +1 -3
  62. digitalhub/stores/data/utils.py +34 -0
  63. digitalhub/utils/file_utils.py +1 -1
  64. digitalhub/utils/generic_utils.py +37 -0
  65. digitalhub/utils/uri_utils.py +5 -0
  66. {digitalhub-0.10.2.dist-info → digitalhub-0.11.0.dist-info}/METADATA +1 -1
  67. {digitalhub-0.10.2.dist-info → digitalhub-0.11.0.dist-info}/RECORD +69 -52
  68. digitalhub/factory/api.py +0 -277
  69. digitalhub/stores/data/s3/models.py +0 -21
  70. digitalhub/stores/data/sql/models.py +0 -24
  71. {digitalhub-0.10.2.dist-info → digitalhub-0.11.0.dist-info}/WHEEL +0 -0
  72. {digitalhub-0.10.2.dist-info → digitalhub-0.11.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -3,7 +3,8 @@ from __future__ import annotations
3
3
  import os
4
4
 
5
5
  from digitalhub.stores.configurator.credentials_store import CredentialsStore
6
- from digitalhub.stores.configurator.ini_module import load_from_file, write_config
6
+ from digitalhub.stores.configurator.enums import SetCreds
7
+ from digitalhub.stores.configurator.ini_module import load_from_file, read_env_from_file, set_current_env, write_config
7
8
 
8
9
 
9
10
  class EnvConfigurator:
@@ -16,7 +17,7 @@ class EnvConfigurator:
16
17
  self._creds_store = CredentialsStore()
17
18
 
18
19
  # Current credentials set (__default by default)
19
- self._environment = "__default"
20
+ self._environment = os.getenv(SetCreds.DH_ENV.value, SetCreds.DEFAULT.value)
20
21
 
21
22
  ##############################
22
23
  # Public methods
@@ -36,6 +37,7 @@ class EnvConfigurator:
36
37
  None
37
38
  """
38
39
  self._environment = creds_set
40
+ set_current_env(creds_set)
39
41
 
40
42
  def get_current_env(self) -> str:
41
43
  """
@@ -105,6 +107,7 @@ class EnvConfigurator:
105
107
  str | None
106
108
  Environment variable value.
107
109
  """
110
+ self._environment = read_env_from_file()
108
111
  return load_from_file(var)
109
112
 
110
113
  def write_env(self, key_to_include: list[str] | None = None) -> None:
@@ -10,3 +10,12 @@ class CredsOrigin(Enum):
10
10
 
11
11
  ENV = "env"
12
12
  FILE = "file"
13
+
14
+
15
+ class SetCreds(Enum):
16
+ """
17
+ List supported environments.
18
+ """
19
+
20
+ DEFAULT = "__default"
21
+ DH_ENV = "DH_NAME"
@@ -13,6 +13,23 @@ from digitalhub.utils.exceptions import ClientError
13
13
  ENV_FILE = Path.home() / ".dhcore.ini"
14
14
 
15
15
 
16
+ def load_file() -> ConfigParser:
17
+ """
18
+ Load current credentials set from the .dhcore.ini file.
19
+
20
+ Returns
21
+ -------
22
+ ConfigParser
23
+ Credentials set name.
24
+ """
25
+ try:
26
+ file = ConfigParser()
27
+ file.read(ENV_FILE)
28
+ return file
29
+ except Exception as e:
30
+ raise ClientError(f"Failed to read env file: {e}")
31
+
32
+
16
33
  def load_from_file(var: str) -> str | None:
17
34
  """
18
35
  Load variable from config file.
@@ -29,9 +46,8 @@ def load_from_file(var: str) -> str | None:
29
46
  str | None
30
47
  Environment variable value.
31
48
  """
32
- cfg = ConfigParser()
33
- cfg.read(ENV_FILE)
34
49
  try:
50
+ cfg = load_file()
35
51
  profile = cfg["DEFAULT"]["current_environment"]
36
52
  return cfg[profile].get(var)
37
53
  except KeyError:
@@ -55,8 +71,7 @@ def write_config(creds: dict, environment: str) -> None:
55
71
  None
56
72
  """
57
73
  try:
58
- cfg = ConfigParser()
59
- cfg.read(ENV_FILE)
74
+ cfg = load_file()
60
75
 
61
76
  sections = cfg.sections()
62
77
  if environment not in sections:
@@ -72,3 +87,42 @@ def write_config(creds: dict, environment: str) -> None:
72
87
 
73
88
  except Exception as e:
74
89
  raise ClientError(f"Failed to write env file: {e}")
90
+
91
+
92
+ def set_current_env(environment: str) -> None:
93
+ """
94
+ Set the current credentials set.
95
+
96
+ Parameters
97
+ ----------
98
+ environment : str
99
+ Credentials set name.
100
+
101
+ Returns
102
+ -------
103
+ None
104
+ """
105
+ try:
106
+ cfg = load_file()
107
+ cfg["DEFAULT"]["current_environment"] = environment
108
+ with open(ENV_FILE, "w") as inifile:
109
+ cfg.write(inifile)
110
+
111
+ except Exception as e:
112
+ raise ClientError(f"Failed to write env file: {e}")
113
+
114
+
115
+ def read_env_from_file() -> str | None:
116
+ """
117
+ Read the current credentials set from the .dhcore.ini file.
118
+
119
+ Returns
120
+ -------
121
+ str
122
+ Credentials set name.
123
+ """
124
+ try:
125
+ cfg = load_file()
126
+ return cfg["DEFAULT"]["current_environment"]
127
+ except Exception:
128
+ return None
@@ -8,7 +8,7 @@ if typing.TYPE_CHECKING:
8
8
  from digitalhub.stores.data._base.store import Store
9
9
 
10
10
 
11
- def get_store(project: str, uri: str, config: dict | None = None) -> Store:
11
+ def get_store(project: str, uri: str) -> Store:
12
12
  """
13
13
  Get store instance by URI.
14
14
 
@@ -26,4 +26,4 @@ def get_store(project: str, uri: str, config: dict | None = None) -> Store:
26
26
  Store
27
27
  Store instance.
28
28
  """
29
- return store_builder.get(uri, config)
29
+ return store_builder.get(project, uri)
@@ -44,9 +44,9 @@ class StoreBuilder:
44
44
  """
45
45
 
46
46
  def __init__(self) -> None:
47
- self._instances: dict[str, Store] = {}
47
+ self._instances: dict[str, dict[str, Store]] = {}
48
48
 
49
- def build(self, store_type: str, config: dict | None = None) -> None:
49
+ def build(self, project: str, store_type: str) -> None:
50
50
  """
51
51
  Build a store instance and register it.
52
52
 
@@ -55,7 +55,6 @@ class StoreBuilder:
55
55
  store_type : str
56
56
  Store type.
57
57
  config : dict
58
- Store configuration.
59
58
 
60
59
  Returns
61
60
  -------
@@ -64,9 +63,9 @@ class StoreBuilder:
64
63
  env = get_current_env()
65
64
  if env not in self._instances:
66
65
  self._instances[env] = {}
67
- self._instances[env][store_type] = _get_class_from_type(store_type)(config)
66
+ self._instances[env][store_type] = _get_class_from_type(store_type)()
68
67
 
69
- def get(self, uri: str, config: dict | None = None) -> Store:
68
+ def get(self, project: str, uri: str) -> Store:
70
69
  """
71
70
  Get a store instance by URI.
72
71
 
@@ -87,7 +86,7 @@ class StoreBuilder:
87
86
  try:
88
87
  return self._instances[env][store_type]
89
88
  except KeyError:
90
- self.build(store_type, config)
89
+ self.build(project, store_type)
91
90
  return self._instances[env][store_type]
92
91
 
93
92
 
@@ -0,0 +1,11 @@
1
+ from __future__ import annotations
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class StoreEnv(Enum):
7
+ """
8
+ Environment variables for data stores.
9
+ """
10
+
11
+ DEFAULT_FILES_STORE = "DHCORE_DEFAULT_FILES_STORE"
@@ -17,9 +17,6 @@ class LocalStore(Store):
17
17
  artifacts on local filesystem based storage.
18
18
  """
19
19
 
20
- def __init__(self, config: dict | None = None) -> None:
21
- super().__init__()
22
-
23
20
  ##############################
24
21
  # I/O methods
25
22
  ##############################
@@ -16,9 +16,6 @@ class RemoteStore(Store):
16
16
  artifacts from remote HTTP based storage.
17
17
  """
18
18
 
19
- def __init__(self, config: dict | None = None) -> None:
20
- super().__init__()
21
-
22
19
  ##############################
23
20
  # I/O methods
24
21
  ##############################
@@ -18,7 +18,6 @@ class S3StoreConfigurator:
18
18
  S3StoreEnv.ENDPOINT_URL,
19
19
  S3StoreEnv.ACCESS_KEY_ID,
20
20
  S3StoreEnv.SECRET_ACCESS_KEY,
21
- S3StoreEnv.BUCKET_NAME,
22
21
  ]
23
22
  optional_vars = [
24
23
  S3StoreEnv.REGION,
@@ -26,29 +25,10 @@ class S3StoreConfigurator:
26
25
  S3StoreEnv.SESSION_TOKEN,
27
26
  ]
28
27
 
29
- def __init__(self, config: dict | None = None) -> None:
30
- self.configure(config)
31
-
32
28
  ##############################
33
29
  # Configuration methods
34
30
  ##############################
35
31
 
36
- def configure(self, config: dict | None = None) -> None:
37
- """
38
- Configure the store by getting the credentials from user
39
- provided config or from environment.
40
-
41
- Parameters
42
- ----------
43
- config : dict
44
- Configuration dictionary.
45
-
46
- Returns
47
- -------
48
- None
49
- """
50
- self._get_env_config()
51
-
52
32
  def get_boto3_client_config(self, origin: str) -> dict:
53
33
  """
54
34
  Get S3 credentials (access key, secret key,
@@ -8,10 +8,9 @@ class S3StoreEnv(Enum):
8
8
  S3Store environment
9
9
  """
10
10
 
11
- ENDPOINT_URL = "S3_ENDPOINT_URL"
11
+ ENDPOINT_URL = "AWS_ENDPOINT_URL"
12
12
  ACCESS_KEY_ID = "AWS_ACCESS_KEY_ID"
13
13
  SECRET_ACCESS_KEY = "AWS_SECRET_ACCESS_KEY"
14
14
  SESSION_TOKEN = "AWS_SESSION_TOKEN"
15
- BUCKET_NAME = "S3_BUCKET"
16
- REGION = "S3_REGION"
15
+ REGION = "AWS_REGION"
17
16
  SIGNATURE_VERSION = "S3_SIGNATURE_VERSION"
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import typing
4
3
  from io import BytesIO
5
4
  from pathlib import Path
6
5
  from typing import Any, Type
@@ -8,7 +7,7 @@ from urllib.parse import urlparse
8
7
 
9
8
  import boto3
10
9
  import botocore.client # pylint: disable=unused-import
11
- from botocore.exceptions import ClientError
10
+ from botocore.exceptions import ClientError, NoCredentialsError
12
11
 
13
12
  from digitalhub.stores.configurator.enums import CredsOrigin
14
13
  from digitalhub.stores.data._base.store import Store
@@ -19,9 +18,6 @@ from digitalhub.utils.exceptions import StoreError
19
18
  from digitalhub.utils.file_utils import get_file_info_from_s3, get_file_mime_type
20
19
  from digitalhub.utils.types import SourcesOrListOfSources
21
20
 
22
- if typing.TYPE_CHECKING:
23
- pass
24
-
25
21
  # Type aliases
26
22
  S3Client = Type["botocore.client.S3"]
27
23
 
@@ -32,10 +28,8 @@ class S3Store(Store):
32
28
  artifacts on S3 based storage.
33
29
  """
34
30
 
35
- def __init__(self, config: dict | None = None) -> None:
36
- super().__init__()
31
+ def __init__(self) -> None:
37
32
  self._configurator = S3StoreConfigurator()
38
- self._configurator.configure(config)
39
33
 
40
34
  ##############################
41
35
  # I/O methods
@@ -655,8 +649,8 @@ class S3Store(Store):
655
649
  """
656
650
  try:
657
651
  client.head_bucket(Bucket=bucket)
658
- except ClientError:
659
- raise StoreError("No access to s3 bucket!")
652
+ except (ClientError, NoCredentialsError) as err:
653
+ raise StoreError(f"No access to s3 bucket! Error: {err}")
660
654
 
661
655
  @staticmethod
662
656
  def _get_key(path: str) -> str:
@@ -1,14 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
- import os
4
3
  from pathlib import Path
5
4
  from urllib.parse import urlparse
6
5
 
7
6
  from boto3 import client as boto3_client
8
7
 
9
- from digitalhub.stores.data.s3.enums import S3StoreEnv
10
-
11
- DEFAULT_BUCKET = "datalake"
8
+ from digitalhub.stores.configurator.enums import CredsOrigin
9
+ from digitalhub.stores.data.s3.configurator import S3StoreConfigurator
10
+ from digitalhub.utils.exceptions import StoreError
12
11
 
13
12
 
14
13
  def get_bucket_name(path: str) -> str:
@@ -63,17 +62,13 @@ def get_s3_source(bucket: str, key: str, filename: Path) -> None:
63
62
  -------
64
63
  None
65
64
  """
66
- s3 = boto3_client("s3", endpoint_url=os.getenv(S3StoreEnv.ENDPOINT_URL.value))
67
- s3.download_file(bucket, key, filename)
68
-
69
-
70
- def get_s3_bucket_from_env() -> str | None:
71
- """
72
- Function to get S3 bucket name.
73
-
74
- Returns
75
- -------
76
- str
77
- The S3 bucket name.
78
- """
79
- return os.getenv(S3StoreEnv.BUCKET_NAME.value, DEFAULT_BUCKET)
65
+ # Try to get client from environment variables
66
+ try:
67
+ cfg = S3StoreConfigurator().get_boto3_client_config(CredsOrigin.ENV.value)
68
+ s3 = boto3_client("s3", **cfg)
69
+ s3.download_file(bucket, key, filename)
70
+
71
+ # Fallback to file
72
+ except StoreError:
73
+ cfg = S3StoreConfigurator().get_boto3_client_config(CredsOrigin.FILE.value)
74
+ s3.download_file(bucket, key, filename)
@@ -12,31 +12,18 @@ class SqlStoreConfigurator:
12
12
  provided config or from environment.
13
13
  """
14
14
 
15
- variables = [SqlStoreEnv.USERNAME, SqlStoreEnv.PASSWORD, SqlStoreEnv.HOST, SqlStoreEnv.PORT, SqlStoreEnv.DATABASE]
16
-
17
- def __init__(self, config: dict | None = None) -> None:
18
- self.configure(config)
15
+ required_vars = [
16
+ SqlStoreEnv.USERNAME,
17
+ SqlStoreEnv.PASSWORD,
18
+ SqlStoreEnv.HOST,
19
+ SqlStoreEnv.PORT,
20
+ SqlStoreEnv.DATABASE,
21
+ ]
19
22
 
20
23
  ##############################
21
24
  # Configuration methods
22
25
  ##############################
23
26
 
24
- def configure(self, config: dict | None = None) -> None:
25
- """
26
- Configure the store by getting the credentials from user
27
- provided config or from environment.
28
-
29
- Parameters
30
- ----------
31
- config : dict
32
- Configuration dictionary.
33
-
34
- Returns
35
- -------
36
- None
37
- """
38
- self._get_env_config()
39
-
40
27
  def get_sql_conn_string(self, origin: str) -> str:
41
28
  """
42
29
  Get the connection string from environment variables.
@@ -74,7 +61,7 @@ class SqlStoreConfigurator:
74
61
  dict
75
62
  The credentials.
76
63
  """
77
- credentials = {var.value: configurator.load_from_env(var.value) for var in self.variables}
64
+ credentials = {var.value: configurator.load_from_env(var.value) for var in self.required_vars}
78
65
  self._set_credentials(credentials)
79
66
  return credentials
80
67
 
@@ -87,7 +74,7 @@ class SqlStoreConfigurator:
87
74
  dict
88
75
  The credentials.
89
76
  """
90
- credentials = {var.value: configurator.load_from_file(var.value) for var in self.variables}
77
+ credentials = {var.value: configurator.load_from_file(var.value) for var in self.required_vars}
91
78
  self._set_credentials(credentials)
92
79
  return credentials
93
80
 
@@ -27,10 +27,8 @@ class SqlStore(Store):
27
27
  artifacts on SQL based storage.
28
28
  """
29
29
 
30
- def __init__(self, config: dict | None = None) -> None:
31
- super().__init__()
30
+ def __init__(self) -> None:
32
31
  self._configurator = SqlStoreConfigurator()
33
- self._configurator.configure(config)
34
32
 
35
33
  ##############################
36
34
  # I/O methods
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+
3
+ from digitalhub.context.api import get_context
4
+ from digitalhub.stores.configurator.configurator import configurator
5
+ from digitalhub.stores.data.enums import StoreEnv
6
+
7
+
8
+ def get_default_store(project: str) -> str:
9
+ """
10
+ Get default store URI.
11
+
12
+ Parameters
13
+ ----------
14
+ project : str
15
+ Project name.
16
+
17
+ Returns
18
+ -------
19
+ str
20
+ Default store URI.
21
+ """
22
+ context = get_context(project)
23
+ store = context.config.get(StoreEnv.DEFAULT_FILES_STORE.value.lower())
24
+ if store is not None:
25
+ return store
26
+ store = configurator.load_var(StoreEnv.DEFAULT_FILES_STORE.value)
27
+ if store is None or store == "":
28
+ raise ValueError(
29
+ "No default store found. "
30
+ "Please set a default store "
31
+ f"in your environment (e.g. export {StoreEnv.DEFAULT_FILES_STORE.value}=) "
32
+ "or set it in project config."
33
+ )
34
+ return store
@@ -190,7 +190,7 @@ def get_file_info_from_s3(path: str, metadata: dict) -> None | dict:
190
190
  if size < file_size_limit_multipart:
191
191
  file_hash = "md5:" + file_hash
192
192
  else:
193
- file_hash = "LiteralETag:" + file_hash
193
+ file_hash = "ETag:" + file_hash
194
194
 
195
195
  name = get_path_name(path)
196
196
  content_type = metadata["ContentType"]
@@ -8,6 +8,7 @@ from enum import Enum, EnumMeta
8
8
  from pathlib import Path
9
9
  from types import MappingProxyType
10
10
  from typing import Any, Callable
11
+ from warnings import warn
11
12
  from zipfile import ZipFile
12
13
 
13
14
  import numpy as np
@@ -235,3 +236,39 @@ def list_enum(enum: EnumMeta) -> list[Any]:
235
236
  """
236
237
  vals: MappingProxyType[str, Enum] = enum.__members__
237
238
  return [member.value for member in vals.values()]
239
+
240
+
241
+ def carriage_return_warn(string: str) -> None:
242
+ """
243
+ Print a warning message if string contains a carriage return (\r\n).
244
+
245
+ Parameters
246
+ ----------
247
+ string : str
248
+ The string to check.
249
+
250
+ Returns
251
+ -------
252
+ None
253
+ """
254
+ if "\r\n" in string:
255
+ warn("String contains a carriage return. It may not be parsed correctly from remote runtimes.")
256
+
257
+
258
+ def read_source(path: str) -> str:
259
+ """
260
+ Read a file.
261
+
262
+ Parameters
263
+ ----------
264
+ path : Path
265
+ Path to the file.
266
+
267
+ Returns
268
+ -------
269
+ str
270
+ File content.
271
+ """
272
+ text = read_text(path)
273
+ carriage_return_warn(text)
274
+ return encode_string(text)
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import re
3
4
  from enum import Enum
4
5
  from urllib.parse import unquote, urlparse
5
6
 
@@ -95,6 +96,10 @@ def map_uri_scheme(uri: str) -> str:
95
96
  ValueError
96
97
  If the scheme is unknown or invalid.
97
98
  """
99
+ # Check for Windows paths (e.g. C:\path\to\file or \\network\share)
100
+ if re.match(r"^[a-zA-Z]:\\", uri) or uri.startswith(r"\\"):
101
+ return SchemeCategory.LOCAL.value
102
+
98
103
  scheme = urlparse(uri).scheme
99
104
  if scheme in list_enum(LocalSchemes):
100
105
  return SchemeCategory.LOCAL.value
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalhub
3
- Version: 0.10.2
3
+ Version: 0.11.0
4
4
  Summary: Python SDK for Digitalhub
5
5
  Project-URL: Homepage, https://github.com/scc-digitalhub/digitalhub-sdk
6
6
  Author-email: Fondazione Bruno Kessler <dslab@fbk.eu>, Matteo Martini <mmartini@fbk.eu>