mlrun 1.3.1rc5__py3-none-any.whl → 1.4.0rc2__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 mlrun might be problematic. Click here for more details.
- mlrun/__main__.py +57 -4
- mlrun/api/api/endpoints/marketplace.py +57 -4
- mlrun/api/api/endpoints/runs.py +2 -0
- mlrun/api/api/utils.py +102 -0
- mlrun/api/crud/__init__.py +1 -0
- mlrun/api/crud/marketplace.py +133 -44
- mlrun/api/crud/notifications.py +80 -0
- mlrun/api/crud/runs.py +2 -0
- mlrun/api/crud/secrets.py +1 -0
- mlrun/api/db/base.py +32 -0
- mlrun/api/db/session.py +3 -11
- mlrun/api/db/sqldb/db.py +162 -1
- mlrun/api/db/sqldb/models/models_mysql.py +41 -0
- mlrun/api/db/sqldb/models/models_sqlite.py +35 -0
- mlrun/api/main.py +54 -1
- mlrun/api/migrations_mysql/versions/c905d15bd91d_notifications.py +70 -0
- mlrun/api/migrations_sqlite/versions/959ae00528ad_notifications.py +61 -0
- mlrun/api/schemas/__init__.py +1 -0
- mlrun/api/schemas/marketplace.py +18 -8
- mlrun/api/{db/filedb/__init__.py → schemas/notification.py} +17 -1
- mlrun/api/utils/singletons/db.py +8 -14
- mlrun/builder.py +37 -26
- mlrun/config.py +12 -2
- mlrun/data_types/spark.py +9 -2
- mlrun/datastore/base.py +10 -1
- mlrun/datastore/sources.py +1 -1
- mlrun/db/__init__.py +6 -4
- mlrun/db/base.py +1 -2
- mlrun/db/httpdb.py +32 -6
- mlrun/db/nopdb.py +463 -0
- mlrun/db/sqldb.py +47 -7
- mlrun/execution.py +3 -0
- mlrun/feature_store/api.py +26 -12
- mlrun/feature_store/common.py +1 -1
- mlrun/feature_store/steps.py +110 -13
- mlrun/k8s_utils.py +10 -0
- mlrun/model.py +43 -0
- mlrun/projects/operations.py +5 -2
- mlrun/projects/pipelines.py +4 -3
- mlrun/projects/project.py +50 -10
- mlrun/run.py +5 -4
- mlrun/runtimes/__init__.py +2 -6
- mlrun/runtimes/base.py +82 -31
- mlrun/runtimes/function.py +22 -0
- mlrun/runtimes/kubejob.py +10 -8
- mlrun/runtimes/serving.py +1 -1
- mlrun/runtimes/sparkjob/__init__.py +0 -1
- mlrun/runtimes/sparkjob/abstract.py +0 -2
- mlrun/serving/states.py +2 -2
- mlrun/utils/helpers.py +1 -1
- mlrun/utils/notifications/notification/__init__.py +1 -1
- mlrun/utils/notifications/notification/base.py +14 -13
- mlrun/utils/notifications/notification/console.py +6 -3
- mlrun/utils/notifications/notification/git.py +19 -12
- mlrun/utils/notifications/notification/ipython.py +6 -3
- mlrun/utils/notifications/notification/slack.py +13 -12
- mlrun/utils/notifications/notification_pusher.py +185 -37
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.3.1rc5.dist-info → mlrun-1.4.0rc2.dist-info}/METADATA +6 -2
- {mlrun-1.3.1rc5.dist-info → mlrun-1.4.0rc2.dist-info}/RECORD +64 -63
- mlrun/api/db/filedb/db.py +0 -518
- mlrun/db/filedb.py +0 -899
- mlrun/runtimes/sparkjob/spark2job.py +0 -59
- {mlrun-1.3.1rc5.dist-info → mlrun-1.4.0rc2.dist-info}/LICENSE +0 -0
- {mlrun-1.3.1rc5.dist-info → mlrun-1.4.0rc2.dist-info}/WHEEL +0 -0
- {mlrun-1.3.1rc5.dist-info → mlrun-1.4.0rc2.dist-info}/entry_points.txt +0 -0
- {mlrun-1.3.1rc5.dist-info → mlrun-1.4.0rc2.dist-info}/top_level.txt +0 -0
mlrun/api/schemas/marketplace.py
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
#
|
|
15
15
|
from datetime import datetime, timezone
|
|
16
|
-
from typing import List, Optional
|
|
16
|
+
from typing import Dict, List, Optional
|
|
17
17
|
|
|
18
18
|
from pydantic import BaseModel, Extra, Field
|
|
19
19
|
|
|
@@ -23,7 +23,7 @@ from mlrun.api.schemas.object import ObjectKind, ObjectSpec, ObjectStatus
|
|
|
23
23
|
from mlrun.config import config
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
# Defining a different base class (not ObjectMetadata), as there's no project and it differs enough to
|
|
26
|
+
# Defining a different base class (not ObjectMetadata), as there's no project, and it differs enough to
|
|
27
27
|
# justify a new class
|
|
28
28
|
class MarketplaceObjectMetadata(BaseModel):
|
|
29
29
|
name: str
|
|
@@ -46,6 +46,9 @@ class MarketplaceSourceSpec(ObjectSpec):
|
|
|
46
46
|
path: str # URL to base directory, should include schema (s3://, etc...)
|
|
47
47
|
channel: str
|
|
48
48
|
credentials: Optional[dict] = {}
|
|
49
|
+
object_type: MarketplaceSourceType = Field(
|
|
50
|
+
MarketplaceSourceType.functions, const=True
|
|
51
|
+
)
|
|
49
52
|
|
|
50
53
|
|
|
51
54
|
class MarketplaceSource(BaseModel):
|
|
@@ -55,8 +58,11 @@ class MarketplaceSource(BaseModel):
|
|
|
55
58
|
status: Optional[ObjectStatus] = ObjectStatus(state="created")
|
|
56
59
|
|
|
57
60
|
def get_full_uri(self, relative_path):
|
|
58
|
-
return "{base}/{channel}/{relative_path}".format(
|
|
59
|
-
base=self.spec.path,
|
|
61
|
+
return "{base}/{object_type}/{channel}/{relative_path}".format(
|
|
62
|
+
base=self.spec.path,
|
|
63
|
+
object_type=self.spec.object_type,
|
|
64
|
+
channel=self.spec.channel,
|
|
65
|
+
relative_path=relative_path,
|
|
60
66
|
)
|
|
61
67
|
|
|
62
68
|
def get_catalog_uri(self):
|
|
@@ -79,6 +85,9 @@ class MarketplaceSource(BaseModel):
|
|
|
79
85
|
spec=MarketplaceSourceSpec(
|
|
80
86
|
path=config.marketplace.default_source.url,
|
|
81
87
|
channel=config.marketplace.default_source.channel,
|
|
88
|
+
object_type=MarketplaceSourceType(
|
|
89
|
+
config.marketplace.default_source.object_type
|
|
90
|
+
),
|
|
82
91
|
),
|
|
83
92
|
status=ObjectStatus(state="created"),
|
|
84
93
|
)
|
|
@@ -88,14 +97,13 @@ last_source_index = -1
|
|
|
88
97
|
|
|
89
98
|
|
|
90
99
|
class IndexedMarketplaceSource(BaseModel):
|
|
91
|
-
index: int = last_source_index # Default last. Otherwise must be > 0
|
|
100
|
+
index: int = last_source_index # Default last. Otherwise, must be > 0
|
|
92
101
|
source: MarketplaceSource
|
|
93
102
|
|
|
94
103
|
|
|
95
104
|
# Item-related objects
|
|
96
105
|
class MarketplaceItemMetadata(MarketplaceObjectMetadata):
|
|
97
106
|
source: MarketplaceSourceType = Field(MarketplaceSourceType.functions, const=True)
|
|
98
|
-
channel: str
|
|
99
107
|
version: str
|
|
100
108
|
tag: Optional[str]
|
|
101
109
|
|
|
@@ -103,9 +111,9 @@ class MarketplaceItemMetadata(MarketplaceObjectMetadata):
|
|
|
103
111
|
if self.source == MarketplaceSourceType.functions:
|
|
104
112
|
# This is needed since the marketplace deployment script modifies the paths to use _ instead of -.
|
|
105
113
|
modified_name = self.name.replace("-", "_")
|
|
106
|
-
# Prefer using the tag if exists. Otherwise use version.
|
|
114
|
+
# Prefer using the tag if exists. Otherwise, use version.
|
|
107
115
|
version = self.tag or self.version
|
|
108
|
-
return f"{
|
|
116
|
+
return f"{modified_name}/{version}/"
|
|
109
117
|
else:
|
|
110
118
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
111
119
|
f"Bad source for marketplace item - {self.source}"
|
|
@@ -114,6 +122,7 @@ class MarketplaceItemMetadata(MarketplaceObjectMetadata):
|
|
|
114
122
|
|
|
115
123
|
class MarketplaceItemSpec(ObjectSpec):
|
|
116
124
|
item_uri: str
|
|
125
|
+
assets: Dict[str, str] = {}
|
|
117
126
|
|
|
118
127
|
|
|
119
128
|
class MarketplaceItem(BaseModel):
|
|
@@ -125,4 +134,5 @@ class MarketplaceItem(BaseModel):
|
|
|
125
134
|
|
|
126
135
|
class MarketplaceCatalog(BaseModel):
|
|
127
136
|
kind: ObjectKind = Field(ObjectKind.marketplace_catalog, const=True)
|
|
137
|
+
channel: str
|
|
128
138
|
catalog: List[MarketplaceItem]
|
|
@@ -11,4 +11,20 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
import mlrun.api.utils.helpers
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class NotificationSeverity(mlrun.api.utils.helpers.StrEnum):
|
|
20
|
+
INFO = "info"
|
|
21
|
+
DEBUG = "debug"
|
|
22
|
+
VERBOSE = "verbose"
|
|
23
|
+
WARNING = "warning"
|
|
24
|
+
ERROR = "error"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class NotificationStatus(mlrun.api.utils.helpers.StrEnum):
|
|
28
|
+
PENDING = "pending"
|
|
29
|
+
SENT = "sent"
|
|
30
|
+
ERROR = "error"
|
mlrun/api/utils/singletons/db.py
CHANGED
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
#
|
|
15
15
|
from mlrun.api.db.base import DBInterface
|
|
16
|
-
from mlrun.api.db.filedb.db import FileDB
|
|
17
16
|
from mlrun.api.db.sqldb.db import SQLDB
|
|
18
17
|
from mlrun.api.db.sqldb.session import create_session
|
|
19
18
|
from mlrun.config import config
|
|
@@ -33,16 +32,11 @@ def initialize_db(override_db=None):
|
|
|
33
32
|
if override_db:
|
|
34
33
|
db = override_db
|
|
35
34
|
return
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
db_session
|
|
44
|
-
try:
|
|
45
|
-
db_session = create_session()
|
|
46
|
-
db.initialize(db_session)
|
|
47
|
-
finally:
|
|
48
|
-
db_session.close()
|
|
35
|
+
logger.info("Creating sql db")
|
|
36
|
+
db = SQLDB(config.httpdb.dsn)
|
|
37
|
+
db_session = None
|
|
38
|
+
try:
|
|
39
|
+
db_session = create_session()
|
|
40
|
+
db.initialize(db_session)
|
|
41
|
+
finally:
|
|
42
|
+
db_session.close()
|
mlrun/builder.py
CHANGED
|
@@ -35,14 +35,14 @@ IMAGE_NAME_ENRICH_REGISTRY_PREFIX = "."
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def make_dockerfile(
|
|
38
|
-
base_image,
|
|
39
|
-
commands=None,
|
|
40
|
-
source=None,
|
|
41
|
-
|
|
42
|
-
workdir="/mlrun",
|
|
43
|
-
extra="",
|
|
44
|
-
user_unix_id=None,
|
|
45
|
-
enriched_group_id=None,
|
|
38
|
+
base_image: str,
|
|
39
|
+
commands: list = None,
|
|
40
|
+
source: str = None,
|
|
41
|
+
requirements_path: str = None,
|
|
42
|
+
workdir: str = "/mlrun",
|
|
43
|
+
extra: str = "",
|
|
44
|
+
user_unix_id: int = None,
|
|
45
|
+
enriched_group_id: int = None,
|
|
46
46
|
):
|
|
47
47
|
dock = f"FROM {base_image}\n"
|
|
48
48
|
|
|
@@ -76,10 +76,13 @@ def make_dockerfile(
|
|
|
76
76
|
dock += f"RUN chown -R {user_unix_id}:{enriched_group_id} {workdir}\n"
|
|
77
77
|
|
|
78
78
|
dock += f"ENV PYTHONPATH {workdir}\n"
|
|
79
|
-
if requirements:
|
|
80
|
-
dock += f"RUN python -m pip install -r {requirements}\n"
|
|
81
79
|
if commands:
|
|
82
80
|
dock += "".join([f"RUN {command}\n" for command in commands])
|
|
81
|
+
if requirements_path:
|
|
82
|
+
dock += (
|
|
83
|
+
f"RUN echo 'Installing {requirements_path}...'; cat {requirements_path}\n"
|
|
84
|
+
)
|
|
85
|
+
dock += f"RUN python -m pip install -r {requirements_path}\n"
|
|
83
86
|
if extra:
|
|
84
87
|
dock += extra
|
|
85
88
|
logger.debug("Resolved dockerfile", dockfile_contents=dock)
|
|
@@ -95,6 +98,7 @@ def make_kaniko_pod(
|
|
|
95
98
|
inline_code=None,
|
|
96
99
|
inline_path=None,
|
|
97
100
|
requirements=None,
|
|
101
|
+
requirements_path=None,
|
|
98
102
|
secret_name=None,
|
|
99
103
|
name="",
|
|
100
104
|
verbose=False,
|
|
@@ -193,19 +197,23 @@ def make_kaniko_pod(
|
|
|
193
197
|
commands = []
|
|
194
198
|
env = {}
|
|
195
199
|
if dockertext:
|
|
196
|
-
|
|
200
|
+
# set and encode docker content to the DOCKERFILE environment variable in the kaniko pod
|
|
197
201
|
env["DOCKERFILE"] = b64encode(dockertext.encode("utf-8")).decode("utf-8")
|
|
202
|
+
# dump dockerfile content and decode to Dockerfile destination
|
|
203
|
+
commands.append("echo ${DOCKERFILE} | base64 -d > /empty/Dockerfile")
|
|
198
204
|
if inline_code:
|
|
199
205
|
name = inline_path or "main.py"
|
|
200
|
-
commands.append("echo ${CODE} | base64 -d > /empty/" + name)
|
|
201
206
|
env["CODE"] = b64encode(inline_code.encode("utf-8")).decode("utf-8")
|
|
207
|
+
commands.append("echo ${CODE} | base64 -d > /empty/" + name)
|
|
202
208
|
if requirements:
|
|
203
|
-
|
|
204
|
-
"echo ${REQUIREMENTS} | base64 -d > /empty/requirements.txt"
|
|
205
|
-
)
|
|
209
|
+
# set and encode requirements to the REQUIREMENTS environment variable in the kaniko pod
|
|
206
210
|
env["REQUIREMENTS"] = b64encode(
|
|
207
211
|
"\n".join(requirements).encode("utf-8")
|
|
208
212
|
).decode("utf-8")
|
|
213
|
+
# dump requirement content and decode to the requirement.txt destination
|
|
214
|
+
commands.append(
|
|
215
|
+
"echo ${REQUIREMENTS}" + " | " + f"base64 -d > {requirements_path}"
|
|
216
|
+
)
|
|
209
217
|
|
|
210
218
|
kpod.append_init_container(
|
|
211
219
|
config.httpdb.builder.kaniko_init_container_image,
|
|
@@ -312,7 +320,6 @@ def build_image(
|
|
|
312
320
|
image_target,
|
|
313
321
|
commands=None,
|
|
314
322
|
source="",
|
|
315
|
-
mounter="v3io",
|
|
316
323
|
base_image=None,
|
|
317
324
|
requirements=None,
|
|
318
325
|
inline_code=None,
|
|
@@ -335,15 +342,12 @@ def build_image(
|
|
|
335
342
|
image_target, secret_name = _resolve_image_target_and_registry_secret(
|
|
336
343
|
image_target, registry, secret_name
|
|
337
344
|
)
|
|
338
|
-
|
|
339
|
-
if isinstance(requirements, list):
|
|
345
|
+
if requirements and isinstance(requirements, list):
|
|
340
346
|
requirements_list = requirements
|
|
341
|
-
requirements_path = "requirements.txt"
|
|
342
|
-
if source:
|
|
343
|
-
raise ValueError("requirements list only works with inline code")
|
|
347
|
+
requirements_path = "/empty/requirements.txt"
|
|
344
348
|
else:
|
|
345
349
|
requirements_list = None
|
|
346
|
-
requirements_path = requirements
|
|
350
|
+
requirements_path = requirements or ""
|
|
347
351
|
|
|
348
352
|
commands = commands or []
|
|
349
353
|
if with_mlrun:
|
|
@@ -358,7 +362,7 @@ def build_image(
|
|
|
358
362
|
if mlrun_command:
|
|
359
363
|
commands.append(mlrun_command)
|
|
360
364
|
|
|
361
|
-
if not inline_code and not source and not commands:
|
|
365
|
+
if not inline_code and not source and not commands and not requirements:
|
|
362
366
|
logger.info("skipping build, nothing to add")
|
|
363
367
|
return "skipped"
|
|
364
368
|
|
|
@@ -431,7 +435,7 @@ def build_image(
|
|
|
431
435
|
base_image,
|
|
432
436
|
commands,
|
|
433
437
|
source=source_to_copy,
|
|
434
|
-
|
|
438
|
+
requirements_path=requirements_path,
|
|
435
439
|
extra=extra,
|
|
436
440
|
user_unix_id=user_unix_id,
|
|
437
441
|
enriched_group_id=enriched_group_id,
|
|
@@ -446,6 +450,7 @@ def build_image(
|
|
|
446
450
|
inline_code=inline_code,
|
|
447
451
|
inline_path=inline_path,
|
|
448
452
|
requirements=requirements_list,
|
|
453
|
+
requirements_path=requirements_path,
|
|
449
454
|
secret_name=secret_name,
|
|
450
455
|
name=name,
|
|
451
456
|
verbose=verbose,
|
|
@@ -555,7 +560,13 @@ def build_runtime(
|
|
|
555
560
|
# if the base is one of mlrun images - no need to install mlrun
|
|
556
561
|
if any([image in build.base_image for image in mlrun_images]):
|
|
557
562
|
with_mlrun = False
|
|
558
|
-
if
|
|
563
|
+
if (
|
|
564
|
+
not build.source
|
|
565
|
+
and not build.commands
|
|
566
|
+
and not build.requirements
|
|
567
|
+
and not build.extra
|
|
568
|
+
and not with_mlrun
|
|
569
|
+
):
|
|
559
570
|
if not runtime.spec.image:
|
|
560
571
|
if build.base_image:
|
|
561
572
|
runtime.spec.image = build.base_image
|
|
@@ -599,8 +610,8 @@ def build_runtime(
|
|
|
599
610
|
image_target=build.image,
|
|
600
611
|
base_image=enriched_base_image,
|
|
601
612
|
commands=build.commands,
|
|
613
|
+
requirements=build.requirements,
|
|
602
614
|
namespace=namespace,
|
|
603
|
-
# inline_code=inline,
|
|
604
615
|
source=build.source,
|
|
605
616
|
secret_name=build.secret,
|
|
606
617
|
interactive=interactive,
|
mlrun/config.py
CHANGED
|
@@ -372,6 +372,15 @@ default_config = {
|
|
|
372
372
|
},
|
|
373
373
|
"v3io_api": "",
|
|
374
374
|
"v3io_framesd": "",
|
|
375
|
+
# If running from sdk and MLRUN_DBPATH is not set, the db will fallback to a nop db which will not preform any
|
|
376
|
+
# run db operations.
|
|
377
|
+
"nop_db": {
|
|
378
|
+
# if set to true, will raise an error for trying to use run db functionality
|
|
379
|
+
# if set to false, will use a nop db which will not preform any run db operations
|
|
380
|
+
"raise_error": False,
|
|
381
|
+
# if set to true, will log a warning for trying to use run db functionality while in nop db mode
|
|
382
|
+
"verbose": True,
|
|
383
|
+
},
|
|
375
384
|
},
|
|
376
385
|
"model_endpoint_monitoring": {
|
|
377
386
|
"serving_stream_args": {"shard_count": 1, "retention_period_hours": 24},
|
|
@@ -432,11 +441,12 @@ default_config = {
|
|
|
432
441
|
"k8s_secrets_project_name": "-marketplace-secrets",
|
|
433
442
|
"catalog_filename": "catalog.json",
|
|
434
443
|
"default_source": {
|
|
435
|
-
# Set
|
|
444
|
+
# Set false to avoid creating a global source (for example in a dark site)
|
|
436
445
|
"create": True,
|
|
437
446
|
"name": "mlrun_global_hub",
|
|
438
447
|
"description": "MLRun global function hub",
|
|
439
|
-
"url": "https://raw.githubusercontent.com/mlrun/marketplace",
|
|
448
|
+
"url": "https://raw.githubusercontent.com/mlrun/marketplace/master",
|
|
449
|
+
"object_type": "functions",
|
|
440
450
|
"channel": "master",
|
|
441
451
|
},
|
|
442
452
|
},
|
mlrun/data_types/spark.py
CHANGED
|
@@ -16,6 +16,8 @@ from datetime import datetime
|
|
|
16
16
|
from os import environ
|
|
17
17
|
|
|
18
18
|
import numpy as np
|
|
19
|
+
import pytz
|
|
20
|
+
from pyspark.sql.functions import to_utc_timestamp
|
|
19
21
|
from pyspark.sql.types import BooleanType, DoubleType, TimestampType
|
|
20
22
|
|
|
21
23
|
from mlrun.utils import logger
|
|
@@ -143,6 +145,9 @@ def get_df_stats_spark(df, options, num_bins=20, sample_size=None):
|
|
|
143
145
|
is_timestamp = isinstance(field.dataType, TimestampType)
|
|
144
146
|
is_boolean = isinstance(field.dataType, BooleanType)
|
|
145
147
|
if is_timestamp:
|
|
148
|
+
df_after_type_casts = df_after_type_casts.withColumn(
|
|
149
|
+
field.name, to_utc_timestamp(df_after_type_casts[field.name], "UTC")
|
|
150
|
+
)
|
|
146
151
|
timestamp_columns.add(field.name)
|
|
147
152
|
if is_boolean:
|
|
148
153
|
boolean_columns.add(field.name)
|
|
@@ -210,11 +215,13 @@ def get_df_stats_spark(df, options, num_bins=20, sample_size=None):
|
|
|
210
215
|
if col in timestamp_columns:
|
|
211
216
|
for stat, val in stats.items():
|
|
212
217
|
if stat == "mean" or stat in original_type_stats:
|
|
213
|
-
stats[stat] = datetime.fromtimestamp(val).isoformat()
|
|
218
|
+
stats[stat] = datetime.fromtimestamp(val, tz=pytz.UTC).isoformat()
|
|
214
219
|
elif stat == "hist":
|
|
215
220
|
values = stats[stat][1]
|
|
216
221
|
for i in range(len(values)):
|
|
217
|
-
values[i] = datetime.fromtimestamp(
|
|
222
|
+
values[i] = datetime.fromtimestamp(
|
|
223
|
+
values[i], tz=pytz.UTC
|
|
224
|
+
).isoformat()
|
|
218
225
|
# for boolean values, keep mean and histogram values numeric (0 to 1 representation)
|
|
219
226
|
if col in boolean_columns:
|
|
220
227
|
for stat, val in stats.items():
|
mlrun/datastore/base.py
CHANGED
|
@@ -383,7 +383,7 @@ class DataItem:
|
|
|
383
383
|
return self._store.listdir(self._path)
|
|
384
384
|
|
|
385
385
|
def local(self):
|
|
386
|
-
"""get the local path of the file, download to tmp first if
|
|
386
|
+
"""get the local path of the file, download to tmp first if it's a remote object"""
|
|
387
387
|
if self.kind == "file":
|
|
388
388
|
return self._path
|
|
389
389
|
if self._local_path:
|
|
@@ -397,6 +397,15 @@ class DataItem:
|
|
|
397
397
|
self.download(self._local_path)
|
|
398
398
|
return self._local_path
|
|
399
399
|
|
|
400
|
+
def remove_local(self):
|
|
401
|
+
"""remove the local file if it exists and was downloaded from a remote object"""
|
|
402
|
+
if self.kind == "file":
|
|
403
|
+
return
|
|
404
|
+
|
|
405
|
+
if self._local_path:
|
|
406
|
+
remove(self._local_path)
|
|
407
|
+
self._local_path = ""
|
|
408
|
+
|
|
400
409
|
def as_df(
|
|
401
410
|
self,
|
|
402
411
|
columns=None,
|
mlrun/datastore/sources.py
CHANGED
|
@@ -885,7 +885,7 @@ class SQLSource(BaseSourceDriver):
|
|
|
885
885
|
Reads SqlDB as input source for a flow.
|
|
886
886
|
example::
|
|
887
887
|
db_path = "mysql+pymysql://<username>:<password>@<host>:<port>/<db_name>"
|
|
888
|
-
source =
|
|
888
|
+
source = SQLSource(
|
|
889
889
|
collection_name='source_name', db_path=self.db, key_field='key'
|
|
890
890
|
)
|
|
891
891
|
:param name: source name
|
mlrun/db/__init__.py
CHANGED
|
@@ -18,7 +18,7 @@ from ..config import config
|
|
|
18
18
|
from ..platforms import add_or_refresh_credentials
|
|
19
19
|
from ..utils import logger
|
|
20
20
|
from .base import RunDBError, RunDBInterface # noqa
|
|
21
|
-
from .
|
|
21
|
+
from .nopdb import NopDB
|
|
22
22
|
from .sqldb import SQLDB
|
|
23
23
|
|
|
24
24
|
|
|
@@ -69,12 +69,14 @@ def get_run_db(url="", secrets=None, force_reconnect=False):
|
|
|
69
69
|
kwargs = {}
|
|
70
70
|
if "://" not in str(url) or scheme in ["file", "s3", "v3io", "v3ios"]:
|
|
71
71
|
logger.warning(
|
|
72
|
-
"Could not detect path to API server,
|
|
72
|
+
"Could not detect path to API server, not connected to API server!"
|
|
73
73
|
)
|
|
74
74
|
logger.warning(
|
|
75
|
-
"
|
|
75
|
+
"MLRUN_DBPATH is not set. Set this environment variable to the URL of the API server"
|
|
76
|
+
" in order to connect"
|
|
76
77
|
)
|
|
77
|
-
cls =
|
|
78
|
+
cls = NopDB
|
|
79
|
+
|
|
78
80
|
elif scheme in ("http", "https"):
|
|
79
81
|
# import here to avoid circular imports
|
|
80
82
|
from .httpdb import HTTPRunDB
|
mlrun/db/base.py
CHANGED
|
@@ -76,6 +76,7 @@ class RunDBInterface(ABC):
|
|
|
76
76
|
partition_sort_by: Union[schemas.SortField, str] = None,
|
|
77
77
|
partition_order: Union[schemas.OrderType, str] = schemas.OrderType.desc,
|
|
78
78
|
max_partitions: int = 0,
|
|
79
|
+
with_notifications: bool = False,
|
|
79
80
|
):
|
|
80
81
|
pass
|
|
81
82
|
|
|
@@ -555,7 +556,6 @@ class RunDBInterface(ABC):
|
|
|
555
556
|
def get_marketplace_catalog(
|
|
556
557
|
self,
|
|
557
558
|
source_name: str,
|
|
558
|
-
channel: str = None,
|
|
559
559
|
version: str = None,
|
|
560
560
|
tag: str = None,
|
|
561
561
|
force_refresh: bool = False,
|
|
@@ -567,7 +567,6 @@ class RunDBInterface(ABC):
|
|
|
567
567
|
self,
|
|
568
568
|
source_name: str,
|
|
569
569
|
item_name: str,
|
|
570
|
-
channel: str = "development",
|
|
571
570
|
version: str = None,
|
|
572
571
|
tag: str = "latest",
|
|
573
572
|
force_refresh: bool = False,
|
mlrun/db/httpdb.py
CHANGED
|
@@ -565,6 +565,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
565
565
|
partition_sort_by: Union[schemas.SortField, str] = None,
|
|
566
566
|
partition_order: Union[schemas.OrderType, str] = schemas.OrderType.desc,
|
|
567
567
|
max_partitions: int = 0,
|
|
568
|
+
with_notifications: bool = False,
|
|
568
569
|
) -> RunList:
|
|
569
570
|
"""Retrieve a list of runs, filtered by various options.
|
|
570
571
|
Example::
|
|
@@ -598,6 +599,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
598
599
|
:param partition_order: Order of sorting within partitions - `asc` or `desc`. Default is `desc`.
|
|
599
600
|
:param max_partitions: Maximal number of partitions to include in the result. Default is `0` which means no
|
|
600
601
|
limit.
|
|
602
|
+
:param with_notifications: Return runs with notifications, and join them to the response. Default is `False`.
|
|
601
603
|
"""
|
|
602
604
|
|
|
603
605
|
project = project or config.default_project
|
|
@@ -613,6 +615,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
613
615
|
"start_time_to": datetime_to_iso(start_time_to),
|
|
614
616
|
"last_update_time_from": datetime_to_iso(last_update_time_from),
|
|
615
617
|
"last_update_time_to": datetime_to_iso(last_update_time_to),
|
|
618
|
+
"with_notifications": with_notifications,
|
|
616
619
|
}
|
|
617
620
|
|
|
618
621
|
if partition_by:
|
|
@@ -2847,7 +2850,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2847
2850
|
def get_marketplace_catalog(
|
|
2848
2851
|
self,
|
|
2849
2852
|
source_name: str,
|
|
2850
|
-
channel: str = None,
|
|
2851
2853
|
version: str = None,
|
|
2852
2854
|
tag: str = None,
|
|
2853
2855
|
force_refresh: bool = False,
|
|
@@ -2857,7 +2859,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2857
2859
|
The list of items can be filtered according to various filters, using item's metadata to filter.
|
|
2858
2860
|
|
|
2859
2861
|
:param source_name: Name of the source.
|
|
2860
|
-
:param channel: Filter items according to their channel. For example ``development``.
|
|
2861
2862
|
:param version: Filter items according to their version.
|
|
2862
2863
|
:param tag: Filter items based on tag.
|
|
2863
2864
|
:param force_refresh: Make the server fetch the catalog from the actual marketplace source,
|
|
@@ -2869,7 +2870,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2869
2870
|
"""
|
|
2870
2871
|
path = (f"marketplace/sources/{source_name}/items",)
|
|
2871
2872
|
params = {
|
|
2872
|
-
"channel": channel,
|
|
2873
2873
|
"version": version,
|
|
2874
2874
|
"tag": tag,
|
|
2875
2875
|
"force-refresh": force_refresh,
|
|
@@ -2881,7 +2881,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2881
2881
|
self,
|
|
2882
2882
|
source_name: str,
|
|
2883
2883
|
item_name: str,
|
|
2884
|
-
channel: str = "development",
|
|
2885
2884
|
version: str = None,
|
|
2886
2885
|
tag: str = "latest",
|
|
2887
2886
|
force_refresh: bool = False,
|
|
@@ -2891,7 +2890,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2891
2890
|
|
|
2892
2891
|
:param source_name: Name of source.
|
|
2893
2892
|
:param item_name: Name of the item to retrieve, as it appears in the catalog.
|
|
2894
|
-
:param channel: Get the item from the specified channel. Default is ``development``.
|
|
2895
2893
|
:param version: Get a specific version of the item. Default is ``None``.
|
|
2896
2894
|
:param tag: Get a specific version of the item identified by tag. Default is ``latest``.
|
|
2897
2895
|
:param force_refresh: Make the server fetch the information from the actual marketplace
|
|
@@ -2901,7 +2899,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2901
2899
|
"""
|
|
2902
2900
|
path = (f"marketplace/sources/{source_name}/items/{item_name}",)
|
|
2903
2901
|
params = {
|
|
2904
|
-
"channel": channel,
|
|
2905
2902
|
"version": version,
|
|
2906
2903
|
"tag": tag,
|
|
2907
2904
|
"force-refresh": force_refresh,
|
|
@@ -2909,6 +2906,35 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2909
2906
|
response = self.api_call(method="GET", path=path, params=params)
|
|
2910
2907
|
return schemas.MarketplaceItem(**response.json())
|
|
2911
2908
|
|
|
2909
|
+
def get_marketplace_asset(
|
|
2910
|
+
self,
|
|
2911
|
+
source_name: str,
|
|
2912
|
+
item_name: str,
|
|
2913
|
+
asset_name: str,
|
|
2914
|
+
version: str = None,
|
|
2915
|
+
tag: str = "latest",
|
|
2916
|
+
):
|
|
2917
|
+
"""
|
|
2918
|
+
Get marketplace asset from item.
|
|
2919
|
+
|
|
2920
|
+
:param source_name: Name of source.
|
|
2921
|
+
:param item_name: Name of the item which holds the asset.
|
|
2922
|
+
:param asset_name: Name of the asset to retrieve.
|
|
2923
|
+
:param version: Get a specific version of the item. Default is ``None``.
|
|
2924
|
+
:param tag: Get a specific version of the item identified by tag. Default is ``latest``.
|
|
2925
|
+
|
|
2926
|
+
:return: http response with the asset in the content attribute
|
|
2927
|
+
"""
|
|
2928
|
+
path = (
|
|
2929
|
+
f"marketplace/sources/{source_name}/items/{item_name}/assets/{asset_name}",
|
|
2930
|
+
)
|
|
2931
|
+
params = {
|
|
2932
|
+
"version": version,
|
|
2933
|
+
"tag": tag,
|
|
2934
|
+
}
|
|
2935
|
+
response = self.api_call(method="GET", path=path, params=params)
|
|
2936
|
+
return response
|
|
2937
|
+
|
|
2912
2938
|
def verify_authorization(
|
|
2913
2939
|
self, authorization_verification_input: schemas.AuthorizationVerificationInput
|
|
2914
2940
|
):
|