dtlpy 1.118.14__py3-none-any.whl → 1.119.5__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.
- dtlpy/__version__.py +1 -1
- dtlpy/entities/annotation.py +0 -7
- dtlpy/entities/app.py +19 -9
- dtlpy/entities/compute.py +122 -331
- dtlpy/entities/dpk.py +315 -2
- dtlpy/entities/model.py +0 -23
- dtlpy/entities/service.py +46 -1
- dtlpy/repositories/annotations.py +4 -2
- dtlpy/repositories/apps.py +1 -1
- dtlpy/repositories/computes.py +1 -1
- dtlpy/repositories/feature_sets.py +1 -1
- dtlpy/repositories/models.py +68 -56
- dtlpy/repositories/tasks.py +10 -3
- dtlpy/repositories/uploader.py +18 -2
- {dtlpy-1.118.14.dist-info → dtlpy-1.119.5.dist-info}/METADATA +1 -1
- {dtlpy-1.118.14.dist-info → dtlpy-1.119.5.dist-info}/RECORD +23 -23
- {dtlpy-1.118.14.dist-info → dtlpy-1.119.5.dist-info}/WHEEL +1 -1
- {dtlpy-1.118.14.data → dtlpy-1.119.5.data}/scripts/dlp +0 -0
- {dtlpy-1.118.14.data → dtlpy-1.119.5.data}/scripts/dlp.bat +0 -0
- {dtlpy-1.118.14.data → dtlpy-1.119.5.data}/scripts/dlp.py +0 -0
- {dtlpy-1.118.14.dist-info → dtlpy-1.119.5.dist-info}/entry_points.txt +0 -0
- {dtlpy-1.118.14.dist-info → dtlpy-1.119.5.dist-info}/licenses/LICENSE +0 -0
- {dtlpy-1.118.14.dist-info → dtlpy-1.119.5.dist-info}/top_level.txt +0 -0
dtlpy/entities/dpk.py
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
from collections import namedtuple
|
|
2
|
-
from typing import List, Union
|
|
2
|
+
from typing import List, Union, Tuple
|
|
3
3
|
import traceback
|
|
4
4
|
import enum
|
|
5
|
+
import tempfile
|
|
6
|
+
import inspect
|
|
7
|
+
import os
|
|
8
|
+
import typing
|
|
5
9
|
|
|
6
|
-
from .. import entities, repositories, exceptions
|
|
10
|
+
from .. import entities, repositories, exceptions, assets
|
|
7
11
|
from ..services.api_client import ApiClient
|
|
12
|
+
from . import package_defaults
|
|
8
13
|
|
|
9
14
|
|
|
10
15
|
class SlotType(str, enum.Enum):
|
|
@@ -29,6 +34,18 @@ DEFAULT_STOPS = {SlotType.ITEM_VIEWER: {"type": "itemViewer",
|
|
|
29
34
|
}
|
|
30
35
|
}
|
|
31
36
|
|
|
37
|
+
DEFAULT_RUNTIME = {
|
|
38
|
+
"podType": "regular-xs",
|
|
39
|
+
"concurrency": 1,
|
|
40
|
+
"runnerImage": "docker.io/dataloopai/dtlpy-agent:cpu.py3.10.opencv",
|
|
41
|
+
"autoscaler": {
|
|
42
|
+
"type": "rabbitmq",
|
|
43
|
+
"minReplicas": 0,
|
|
44
|
+
"maxReplicas": 2,
|
|
45
|
+
"queueLength": 100
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
32
49
|
|
|
33
50
|
class Slot(entities.DlEntity):
|
|
34
51
|
type: str = entities.DlProperty(location=['type'], _type=str)
|
|
@@ -468,3 +485,299 @@ class Dpk(entities.DlEntity):
|
|
|
468
485
|
)
|
|
469
486
|
|
|
470
487
|
return res
|
|
488
|
+
|
|
489
|
+
@staticmethod
|
|
490
|
+
def _parse_function_io(func) -> Tuple[List[dict], List[dict]]:
|
|
491
|
+
"""
|
|
492
|
+
Parse function inputs and outputs from function signature and type hints.
|
|
493
|
+
|
|
494
|
+
This helper function extracts:
|
|
495
|
+
- Inputs: from function parameters (inspect.signature)
|
|
496
|
+
- Outputs: from return type hints (typing.get_type_hints)
|
|
497
|
+
|
|
498
|
+
:param func: The function to parse
|
|
499
|
+
:return: Tuple of (inputs, outputs) where each is a list of dicts with 'name' and 'type' keys
|
|
500
|
+
:rtype: Tuple[List[dict], List[dict]]
|
|
501
|
+
"""
|
|
502
|
+
# ============================================
|
|
503
|
+
# PARSE INPUTS FROM FUNCTION SIGNATURE
|
|
504
|
+
# ============================================
|
|
505
|
+
# Get all parameter names from the function signature
|
|
506
|
+
params = list(inspect.signature(func).parameters)
|
|
507
|
+
inputs = []
|
|
508
|
+
|
|
509
|
+
# Create a mapping of known input type names (lowercase) to PackageInputType values
|
|
510
|
+
# This allows matching parameter names like 'item', 'items', 'annotation', etc. to their types
|
|
511
|
+
inputs_types = {i.name.lower(): i.value for i in list(entities.PackageInputType)}
|
|
512
|
+
|
|
513
|
+
# Process each parameter
|
|
514
|
+
for arg in params:
|
|
515
|
+
# Check if the parameter name matches a known PackageInputType (case-insensitive)
|
|
516
|
+
# For example: 'item' -> PackageInputType.ITEM, 'items' -> PackageInputType.ITEMS
|
|
517
|
+
if arg in inputs_types:
|
|
518
|
+
inpt_type = inputs_types[arg]
|
|
519
|
+
else:
|
|
520
|
+
# If parameter name doesn't match a known type, default to JSON
|
|
521
|
+
inpt_type = entities.PackageInputType.JSON
|
|
522
|
+
|
|
523
|
+
# Create input dict with name and type
|
|
524
|
+
inputs.append({
|
|
525
|
+
'name': arg,
|
|
526
|
+
'type': inpt_type
|
|
527
|
+
})
|
|
528
|
+
|
|
529
|
+
# ============================================
|
|
530
|
+
# PARSE OUTPUTS FROM TYPE HINTS
|
|
531
|
+
# ============================================
|
|
532
|
+
outputs = []
|
|
533
|
+
try:
|
|
534
|
+
# Get return type hint from function annotations
|
|
535
|
+
# Returns None if no return type is specified
|
|
536
|
+
hint_outputs = typing.get_type_hints(func).get('return', None)
|
|
537
|
+
|
|
538
|
+
if hint_outputs is not None:
|
|
539
|
+
# ============================================
|
|
540
|
+
# STEP 1: Extract output types from type hint
|
|
541
|
+
# ============================================
|
|
542
|
+
# Handle different return type patterns:
|
|
543
|
+
# - Tuple[Type1, Type2, ...] -> multiple outputs
|
|
544
|
+
# - List[Type] -> single output that's a list
|
|
545
|
+
# - Type -> single output
|
|
546
|
+
output_types = []
|
|
547
|
+
|
|
548
|
+
if hasattr(hint_outputs, '__origin__') and hint_outputs.__origin__ is tuple:
|
|
549
|
+
# Multiple returns: Tuple[Type1, Type2, ...]
|
|
550
|
+
# Extract all types from the tuple
|
|
551
|
+
output_types = list(hint_outputs.__args__) if hasattr(hint_outputs, '__args__') else []
|
|
552
|
+
elif hasattr(hint_outputs, '__args__'):
|
|
553
|
+
# Single generic type (e.g., List[Item], Dict[str, int])
|
|
554
|
+
# Extract the inner type from the generic
|
|
555
|
+
output_types = [hint_outputs.__args__[0]]
|
|
556
|
+
else:
|
|
557
|
+
# Single simple type (e.g., Item, str, int)
|
|
558
|
+
output_types = [hint_outputs]
|
|
559
|
+
|
|
560
|
+
# ============================================
|
|
561
|
+
# STEP 2: Process each output type
|
|
562
|
+
# ============================================
|
|
563
|
+
for idx, output_type in enumerate(output_types):
|
|
564
|
+
io_type = output_type
|
|
565
|
+
is_list = False
|
|
566
|
+
|
|
567
|
+
# ============================================
|
|
568
|
+
# STEP 2a: Check if it's a List type
|
|
569
|
+
# ============================================
|
|
570
|
+
# Handle List[Type] patterns (e.g., List[Item], List[Annotation])
|
|
571
|
+
if hasattr(io_type, '__origin__'):
|
|
572
|
+
origin = io_type.__origin__
|
|
573
|
+
origin_str = str(origin)
|
|
574
|
+
|
|
575
|
+
# Check if origin is list or typing.List
|
|
576
|
+
# This handles both 'list' and 'typing.List' cases
|
|
577
|
+
if origin is list or origin_str.startswith('typing.List') or origin_str.startswith('<class \'list\'>'):
|
|
578
|
+
is_list = True
|
|
579
|
+
# Extract inner type from List[InnerType]
|
|
580
|
+
# Example: List[Item] -> extract 'Item'
|
|
581
|
+
if hasattr(io_type, '__args__') and len(io_type.__args__) > 0:
|
|
582
|
+
io_type = io_type.__args__[0]
|
|
583
|
+
|
|
584
|
+
# ============================================
|
|
585
|
+
# STEP 2b: Handle special type cases
|
|
586
|
+
# ============================================
|
|
587
|
+
# Handle Enum types - convert to string name
|
|
588
|
+
if isinstance(io_type, enum.Enum):
|
|
589
|
+
io_type = io_type.name
|
|
590
|
+
|
|
591
|
+
# Handle nested generic types (only if not already extracted from List)
|
|
592
|
+
# Example: Optional[List[Item]] -> extract List[Item] first, then Item
|
|
593
|
+
if not is_list and hasattr(io_type, '__args__'):
|
|
594
|
+
io_type = io_type.__args__[0]
|
|
595
|
+
|
|
596
|
+
# ============================================
|
|
597
|
+
# STEP 2c: Extract type name as string
|
|
598
|
+
# ============================================
|
|
599
|
+
# Convert type to string representation
|
|
600
|
+
if isinstance(io_type, type):
|
|
601
|
+
# Direct type object (e.g., Item class) -> get class name
|
|
602
|
+
type_str = io_type.__name__
|
|
603
|
+
else:
|
|
604
|
+
# Type hint object -> convert to string
|
|
605
|
+
type_str = str(io_type)
|
|
606
|
+
# Extract class name from fully qualified name
|
|
607
|
+
# Example: "dtlpy.entities.item.Item" -> "Item"
|
|
608
|
+
if '.' in type_str:
|
|
609
|
+
type_str = type_str.rsplit('.', maxsplit=1)[-1]
|
|
610
|
+
|
|
611
|
+
# ============================================
|
|
612
|
+
# STEP 2d: Map type string to PackageInputType
|
|
613
|
+
# ============================================
|
|
614
|
+
# Map Python type names to PackageInputType enum values
|
|
615
|
+
# Special case: 'str' maps to STRING
|
|
616
|
+
if type_str == 'str':
|
|
617
|
+
mapped_type = entities.PackageInputType.STRING
|
|
618
|
+
else:
|
|
619
|
+
mapped_type = None
|
|
620
|
+
|
|
621
|
+
# If it's a list, try to find the array version first
|
|
622
|
+
# Example: Item -> ITEMS, Annotation -> ANNOTATIONS
|
|
623
|
+
if is_list:
|
|
624
|
+
array_type_name = f"{type_str.upper()}S" # Item -> ITEMS
|
|
625
|
+
for pkg_input_type in entities.PackageInputType:
|
|
626
|
+
if pkg_input_type.name.upper() == array_type_name:
|
|
627
|
+
mapped_type = pkg_input_type
|
|
628
|
+
break
|
|
629
|
+
|
|
630
|
+
# If not found or not a list, try the regular type
|
|
631
|
+
# Example: Item -> ITEM, Annotation -> ANNOTATION
|
|
632
|
+
if mapped_type is None:
|
|
633
|
+
for pkg_input_type in entities.PackageInputType:
|
|
634
|
+
if pkg_input_type.name.upper() == type_str.upper():
|
|
635
|
+
mapped_type = pkg_input_type
|
|
636
|
+
break
|
|
637
|
+
|
|
638
|
+
# Default to JSON if no match found
|
|
639
|
+
# This handles unknown types gracefully
|
|
640
|
+
if mapped_type is None:
|
|
641
|
+
mapped_type = entities.PackageInputType.JSON
|
|
642
|
+
|
|
643
|
+
# ============================================
|
|
644
|
+
# STEP 2e: Create output dict
|
|
645
|
+
# ============================================
|
|
646
|
+
# Name outputs: 'output' for single, 'output_0', 'output_1', etc. for multiple
|
|
647
|
+
output_name = 'output' if len(output_types) == 1 else f'output_{idx}'
|
|
648
|
+
outputs.append({
|
|
649
|
+
'name': output_name,
|
|
650
|
+
'type': mapped_type
|
|
651
|
+
})
|
|
652
|
+
except Exception:
|
|
653
|
+
# If type hints extraction fails (e.g., no type hints, invalid syntax),
|
|
654
|
+
# leave outputs empty - this is not a fatal error
|
|
655
|
+
pass
|
|
656
|
+
|
|
657
|
+
return inputs, outputs
|
|
658
|
+
|
|
659
|
+
@classmethod
|
|
660
|
+
def from_function(
|
|
661
|
+
cls,
|
|
662
|
+
func,
|
|
663
|
+
name: str = None,
|
|
664
|
+
version: str = '1.0.0',
|
|
665
|
+
description: str = None,
|
|
666
|
+
project: 'entities.Project' = None,
|
|
667
|
+
client_api: ApiClient = None,
|
|
668
|
+
scope: str = 'project',
|
|
669
|
+
runtime: dict = None,
|
|
670
|
+
execution_timeout: int = 3600,
|
|
671
|
+
) -> 'entities.Dpk':
|
|
672
|
+
"""
|
|
673
|
+
Build a DPK from a Python function (codebase + components). Does not publish or install.
|
|
674
|
+
Runtime is held on the service component (modules have no runtime). Use the runtime param to override defaults.
|
|
675
|
+
|
|
676
|
+
:param Callable func: Function to deploy
|
|
677
|
+
:param str name: DPK name (default: function __name__)
|
|
678
|
+
:param str version: DPK version (default: '1.0.0')
|
|
679
|
+
:param str description: DPK description
|
|
680
|
+
:param entities.Project project: Project (required)
|
|
681
|
+
:param ApiClient client_api: API client (required)
|
|
682
|
+
:param str scope: 'project' or 'organization'
|
|
683
|
+
:param dict runtime: podType, concurrency, runnerImage, autoscaler; default: DEFAULT_RUNTIME
|
|
684
|
+
:param int execution_timeout: Service timeout in seconds (default: 3600)
|
|
685
|
+
:return: Built DPK (with codebase); use Service.from_function to publish, install, and get the Service
|
|
686
|
+
:rtype: dtlpy.entities.Dpk
|
|
687
|
+
"""
|
|
688
|
+
if client_api is None:
|
|
689
|
+
raise ValueError('client_api is required')
|
|
690
|
+
if project is None:
|
|
691
|
+
raise ValueError('project is required for codebase packing')
|
|
692
|
+
|
|
693
|
+
# Get function name if name not provided
|
|
694
|
+
if name is None:
|
|
695
|
+
name = func.__name__
|
|
696
|
+
|
|
697
|
+
# Resolve runtime: use copy to avoid mutating caller's dict or DEFAULT_RUNTIME
|
|
698
|
+
if runtime is None:
|
|
699
|
+
runtime = dict(DEFAULT_RUNTIME)
|
|
700
|
+
else:
|
|
701
|
+
runtime = dict(runtime)
|
|
702
|
+
|
|
703
|
+
# Create temporary directory for the function code
|
|
704
|
+
dpk_dir = tempfile.mkdtemp()
|
|
705
|
+
|
|
706
|
+
# Create main.py file with the function
|
|
707
|
+
main_file = os.path.join(dpk_dir, package_defaults.DEFAULT_PACKAGE_ENTRY_POINT)
|
|
708
|
+
|
|
709
|
+
# Read the partial main template (ServiceRunner class structure)
|
|
710
|
+
with open(assets.paths.PARTIAL_MAIN_FILEPATH, 'r') as f:
|
|
711
|
+
main_template = f.read()
|
|
712
|
+
|
|
713
|
+
# Extract function source code and adjust indentation
|
|
714
|
+
lines = inspect.getsourcelines(func)
|
|
715
|
+
tabs_diff = lines[0][0].count(' ') - 1
|
|
716
|
+
for line_index in range(len(lines[0])):
|
|
717
|
+
line_tabs = lines[0][line_index].count(' ') - tabs_diff
|
|
718
|
+
lines[0][line_index] = (' ' * line_tabs) + lines[0][line_index].strip() + '\n'
|
|
719
|
+
|
|
720
|
+
method_func_string = "".join(lines[0])
|
|
721
|
+
|
|
722
|
+
# Write main.py with ServiceRunner class and function
|
|
723
|
+
with open(main_file, 'w') as f:
|
|
724
|
+
f.write(f'{main_template}\n @staticmethod\n{method_func_string}')
|
|
725
|
+
|
|
726
|
+
# Parse function inputs and outputs from signature and type hints
|
|
727
|
+
inputs, outputs = cls._parse_function_io(func)
|
|
728
|
+
|
|
729
|
+
# Build module dict (no runtime on module/functions)
|
|
730
|
+
function_dict = {
|
|
731
|
+
'name': func.__name__,
|
|
732
|
+
'input': inputs,
|
|
733
|
+
'output': outputs,
|
|
734
|
+
}
|
|
735
|
+
module_dict = {
|
|
736
|
+
'name': package_defaults.DEFAULT_PACKAGE_MODULE_NAME,
|
|
737
|
+
'entryPoint': package_defaults.DEFAULT_PACKAGE_ENTRY_POINT,
|
|
738
|
+
'className': package_defaults.DEFAULT_PACKAGE_CLASS_NAME,
|
|
739
|
+
'functions': [function_dict],
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
# Service component (smart-search style): holds runtime, references module
|
|
743
|
+
service_name = f"{name}-service".replace("_", "-")
|
|
744
|
+
service_entry = {
|
|
745
|
+
"name": service_name,
|
|
746
|
+
"moduleName": package_defaults.DEFAULT_PACKAGE_MODULE_NAME,
|
|
747
|
+
"packageRevision": "latest",
|
|
748
|
+
"runtime": runtime,
|
|
749
|
+
"executionTimeout": execution_timeout,
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
components_dict = {
|
|
753
|
+
"modules": [module_dict],
|
|
754
|
+
"services": [service_entry],
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
# Create DPK entity
|
|
758
|
+
dpk_json = {
|
|
759
|
+
'name': name,
|
|
760
|
+
'version': version,
|
|
761
|
+
'display_name': name,
|
|
762
|
+
'description': description or f'DPK created from function {func.__name__}',
|
|
763
|
+
'scope': scope,
|
|
764
|
+
'components': components_dict,
|
|
765
|
+
'context': {
|
|
766
|
+
'project': project.id
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
dpk = cls.from_json(
|
|
771
|
+
_json=dpk_json,
|
|
772
|
+
client_api=client_api,
|
|
773
|
+
project=project
|
|
774
|
+
)
|
|
775
|
+
|
|
776
|
+
# Pack the temporary directory as codebase
|
|
777
|
+
dpk.codebase = project.codebases.pack(
|
|
778
|
+
directory=dpk_dir,
|
|
779
|
+
name=name,
|
|
780
|
+
extension='dpk'
|
|
781
|
+
)
|
|
782
|
+
|
|
783
|
+
return dpk
|
dtlpy/entities/model.py
CHANGED
|
@@ -51,29 +51,6 @@ class PlotSample:
|
|
|
51
51
|
return _json
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
# class MatrixSample:
|
|
55
|
-
# def __init__(self, figure, legend, x, y):
|
|
56
|
-
# """
|
|
57
|
-
# Create a single metric sample for Model
|
|
58
|
-
#
|
|
59
|
-
# :param figure: figure name identifier
|
|
60
|
-
# :param legend: line name identifier
|
|
61
|
-
# :param x: x value for the current sample
|
|
62
|
-
# :param y: y value for the current sample
|
|
63
|
-
# """
|
|
64
|
-
# self.figure = figure
|
|
65
|
-
# self.legend = legend
|
|
66
|
-
# self.x = x
|
|
67
|
-
# self.y = y
|
|
68
|
-
#
|
|
69
|
-
# def to_json(self) -> dict:
|
|
70
|
-
# _json = {'figure': self.figure,
|
|
71
|
-
# 'legend': self.legend,
|
|
72
|
-
# 'data': {'x': self.x,
|
|
73
|
-
# 'y': self.y}}
|
|
74
|
-
# return _json
|
|
75
|
-
|
|
76
|
-
|
|
77
54
|
@attr.s
|
|
78
55
|
class Model(entities.BaseEntity):
|
|
79
56
|
"""
|
dtlpy/entities/service.py
CHANGED
|
@@ -8,6 +8,7 @@ from urllib.parse import urlsplit
|
|
|
8
8
|
import attr
|
|
9
9
|
from .. import repositories, entities
|
|
10
10
|
from ..services.api_client import ApiClient
|
|
11
|
+
from .dpk import Dpk
|
|
11
12
|
|
|
12
13
|
logger = logging.getLogger(name='dtlpy')
|
|
13
14
|
|
|
@@ -359,6 +360,50 @@ class Service(entities.BaseEntity):
|
|
|
359
360
|
inst.is_fetched = is_fetched
|
|
360
361
|
return inst
|
|
361
362
|
|
|
363
|
+
@classmethod
|
|
364
|
+
def from_function(
|
|
365
|
+
cls,
|
|
366
|
+
func,
|
|
367
|
+
name: str = None,
|
|
368
|
+
version: str = '1.0.0',
|
|
369
|
+
description: str = None,
|
|
370
|
+
project: 'entities.Project' = None,
|
|
371
|
+
client_api: ApiClient = None,
|
|
372
|
+
scope: str = 'project',
|
|
373
|
+
runtime: dict = None,
|
|
374
|
+
execution_timeout: int = 3600,
|
|
375
|
+
) -> 'Service':
|
|
376
|
+
"""
|
|
377
|
+
Create a Service from a Python function: build DPK via Dpk.from_function, then publish, install, and return the Service.
|
|
378
|
+
"""
|
|
379
|
+
built_dpk = Dpk.from_function(
|
|
380
|
+
func=func,
|
|
381
|
+
name=name,
|
|
382
|
+
version=version,
|
|
383
|
+
description=description,
|
|
384
|
+
project=project,
|
|
385
|
+
client_api=client_api,
|
|
386
|
+
scope=scope,
|
|
387
|
+
runtime=runtime,
|
|
388
|
+
execution_timeout=execution_timeout,
|
|
389
|
+
)
|
|
390
|
+
published_dpk = project.dpks.publish(dpk=built_dpk)
|
|
391
|
+
app = project.apps.install(dpk=published_dpk, app_name=published_dpk.display_name)
|
|
392
|
+
service_name = f"{built_dpk.name}-service".replace("_", "-")
|
|
393
|
+
filters = entities.Filters(
|
|
394
|
+
resource=entities.FiltersResource.SERVICE,
|
|
395
|
+
field='name',
|
|
396
|
+
values=service_name,
|
|
397
|
+
use_defaults=False
|
|
398
|
+
)
|
|
399
|
+
services = project.services.list(filters=filters)
|
|
400
|
+
if services.items_count == 0:
|
|
401
|
+
raise RuntimeError(
|
|
402
|
+
"No service found with name %s for installed app (app id=%s). "
|
|
403
|
+
"The app was installed but the service may not be listed yet." % (service_name, app.id)
|
|
404
|
+
)
|
|
405
|
+
return services.items[0]
|
|
406
|
+
|
|
362
407
|
############
|
|
363
408
|
# Entities #
|
|
364
409
|
############
|
|
@@ -397,7 +442,7 @@ class Service(entities.BaseEntity):
|
|
|
397
442
|
dpk_id=dpk_id,
|
|
398
443
|
version=dpk_version)
|
|
399
444
|
|
|
400
|
-
assert isinstance(self._package,
|
|
445
|
+
assert isinstance(self._package, Dpk)
|
|
401
446
|
except:
|
|
402
447
|
self._package = repositories.Packages(client_api=self._client_api).get(package_id=self.package_id,
|
|
403
448
|
fetch=None,
|
|
@@ -653,7 +653,8 @@ class Annotations:
|
|
|
653
653
|
not a.get('clean', False) and a.get("metadata", {}).get('system', {}).get('objectId',
|
|
654
654
|
None) ==
|
|
655
655
|
annotation.get("metadata", {}).get('system', {}).get('objectId', None) and a['label'] ==
|
|
656
|
-
annotation['label']
|
|
656
|
+
annotation['label']
|
|
657
|
+
and a['type'] == annotation['type']]
|
|
657
658
|
if len(to_merge) == 0:
|
|
658
659
|
# no annotation to merge with
|
|
659
660
|
continue
|
|
@@ -677,7 +678,8 @@ class Annotations:
|
|
|
677
678
|
to_merge = [a for a in exist_annotations if
|
|
678
679
|
a.object_id == ann.get("metadata", {}).get('system', {}).get('objectId',
|
|
679
680
|
None) and a.label == ann[
|
|
680
|
-
'label']
|
|
681
|
+
'label']
|
|
682
|
+
and a.type == ann['type']]
|
|
681
683
|
if len(to_merge) == 0:
|
|
682
684
|
# no annotation to merge with
|
|
683
685
|
continue
|
dtlpy/repositories/apps.py
CHANGED
|
@@ -11,7 +11,7 @@ class Apps:
|
|
|
11
11
|
def __init__(self, client_api: ApiClient, project: entities.Project = None, project_id: str = None):
|
|
12
12
|
self._client_api = client_api
|
|
13
13
|
self._project = project
|
|
14
|
-
self._project_id = project_id
|
|
14
|
+
self._project_id = project_id
|
|
15
15
|
self._commands = None
|
|
16
16
|
|
|
17
17
|
@property
|
dtlpy/repositories/computes.py
CHANGED
|
@@ -358,7 +358,7 @@ class Computes:
|
|
|
358
358
|
project_id = project.id
|
|
359
359
|
compute = self.create(
|
|
360
360
|
config['config']['name'],
|
|
361
|
-
ComputeContext([], org_id, project_id),
|
|
361
|
+
ComputeContext(labels=[], org=org_id, project=project_id),
|
|
362
362
|
[],
|
|
363
363
|
cluster,
|
|
364
364
|
ComputeType.KUBERNETES,
|
|
@@ -223,7 +223,7 @@ class FeatureSets:
|
|
|
223
223
|
|
|
224
224
|
@_api_reference.add(path='/features/sets', method='post')
|
|
225
225
|
def create(
|
|
226
|
-
self, name: str, size: int, set_type: str, entity_type: entities.FeatureEntityType, project_id: str = None, model_id:
|
|
226
|
+
self, name: str, size: int, set_type: str, entity_type: entities.FeatureEntityType, project_id: str = None, model_id: str = None, org_id: str = None
|
|
227
227
|
):
|
|
228
228
|
"""
|
|
229
229
|
Create a new Feature Set
|