Example #1
0
def _attribute_upload_response_handler(result: bytes) -> None:
    try:
        parsed = json.loads(result)
    except json.JSONDecodeError:
        raise InternalClientError("Unexpected response from server: {}".format(result))

    if isinstance(parsed, type(None)):
        # old format with empty optional error
        return
    if isinstance(parsed, dict):
        if "errorDescription" in parsed:
            # old format with optional error
            raise MetadataInconsistency(parsed["errorDescription"])
        elif "errors" in parsed:
            # new format with a list of errors
            error_list = parsed["errors"]
            if isinstance(error_list, list):
                if len(error_list) == 0:
                    return
                try:
                    raise MetadataInconsistency(
                        *[item["errorDescription"] for item in parsed["errors"]]
                    )
                except KeyError:
                    # fall into default InternalClientError
                    pass

    raise InternalClientError("Unexpected response from server: {}".format(result))
Example #2
0
    def _execute_operations(
        self,
        container_id: str,
        container_type: ContainerType,
        operations: List[Operation],
    ) -> List[MetadataInconsistency]:
        kwargs = {
            "experimentId": container_id,
            "operations": [
                {
                    "path": path_to_str(op.path),
                    OperationApiNameVisitor()
                    .visit(op): OperationApiObjectConverter()
                    .convert(op),
                }
                for op in operations
            ],
            **DEFAULT_REQUEST_KWARGS,
        }

        try:
            result = (
                self.leaderboard_client.api.executeOperations(**kwargs)
                .response()
                .result
            )
            return [MetadataInconsistency(err.errorDescription) for err in result]
        except HTTPNotFound as e:
            raise_container_not_found(container_id, container_type, from_exception=e)
        except (HTTPPaymentRequired, HTTPUnprocessableEntity) as e:
            raise NeptuneLimitExceedException(
                reason=e.response.json().get("title", "Unknown reason")
            ) from e
Example #3
0
 def _get_attribute(
     self,
     container_id: str,
     container_type: ContainerType,
     path: List[str],
     expected_type: Type[Val],
 ) -> Val:
     run = self._get_container(container_id, container_type)
     value: Optional[Value] = run.get(path)
     str_path = path_to_str(path)
     if value is None:
         raise MetadataInconsistency(
             "Attribute {} not found".format(str_path))
     if isinstance(value, expected_type):
         return value
     raise MetadataInconsistency("Attribute {} is not {}".format(
         str_path, type.__name__))
Example #4
0
 def visit_delete_attribute(self,
                            op: DeleteAttribute) -> Optional[Value]:
     # pylint: disable=unused-argument
     if self._current_value is None:
         raise MetadataInconsistency(
             "Cannot perform delete operation on {}. Attribute is undefined."
             .format(self._path))
     return None
Example #5
0
 def download(self, destination: Optional[str]):
     attr_type = self._run.get_attribute_type(self._path)
     if attr_type == AttributeType.FILE:
         return self._run.download_file_attribute(self._path, destination)
     elif attr_type == AttributeType.FILE_SET:
         return self._run.download_file_set_attribute(
             self._path, destination)
     raise MetadataInconsistency(
         "Cannot download file from attribute of type {}".format(attr_type))
Example #6
0
 def get_attribute_value(self, path: str):
     for attr in self._attributes:
         if attr.path == path:
             _type = attr.type
             if _type == AttributeType.RUN_STATE:
                 return attr.properties.value
             if _type in (
                     AttributeType.FLOAT,
                     AttributeType.INT,
                     AttributeType.BOOL,
                     AttributeType.STRING,
                     AttributeType.DATETIME,
             ):
                 return attr.properties.value
             if (_type == AttributeType.FLOAT_SERIES
                     or _type == AttributeType.STRING_SERIES):
                 return attr.properties.last
             if _type == AttributeType.IMAGE_SERIES:
                 raise MetadataInconsistency(
                     "Cannot get value for image series.")
             if _type == AttributeType.FILE:
                 raise MetadataInconsistency(
                     "Cannot get value for file attribute. Use download() instead."
                 )
             if _type == AttributeType.FILE_SET:
                 raise MetadataInconsistency(
                     "Cannot get value for file set attribute. Use download() instead."
                 )
             if _type == AttributeType.STRING_SET:
                 return set(attr.properties.values)
             if _type == AttributeType.GIT_REF:
                 return attr.properties.commit.commitId
             if _type == AttributeType.NOTEBOOK_REF:
                 return attr.properties.notebookName
             if _type == AttributeType.ARTIFACT:
                 return attr.properties.hash
             logger.error(
                 "Attribute type %s not supported in this version, yielding None. Recommended client upgrade.",
                 _type,
             )
             return None
     raise ValueError("Could not find {} attribute".format(path))
Example #7
0
    def _pop_impl(self, ref, sub_path: List[str], attr_path: List[str]):
        if not sub_path:
            return

        head, tail = sub_path[0], sub_path[1:]
        if head not in ref:
            raise MetadataInconsistency(
                "Cannot delete {}. Attribute not found.".format(
                    path_to_str(attr_path)))

        if not tail:
            if isinstance(ref[head], self._node_type):
                raise MetadataInconsistency(
                    "Cannot delete {}. It's a namespace, not an attribute.".
                    format(path_to_str(attr_path)))
            del ref[head]
        else:
            self._pop_impl(ref[head], tail, attr_path)
            if not ref[head]:
                del ref[head]
Example #8
0
 def download_file_attribute(self, path: str, destination: Optional[str]):
     for attr in self._attributes:
         if attr.path == path:
             _type = attr.type
             if _type == AttributeType.FILE:
                 self._backend.download_file(self._id, ContainerType.RUN,
                                             parse_path(path), destination)
                 return
             raise MetadataInconsistency(
                 "Cannot download file from attribute of type {}".format(
                     _type))
     raise ValueError("Could not find {} attribute".format(path))
Example #9
0
    def set(self, path: List[str], attr: T) -> None:
        ref = self._structure
        location, attribute_name = path[:-1], path[-1]

        for idx, part in enumerate(location):
            if part not in ref:
                ref[part] = self._node_factory(location[:idx + 1])
            ref = ref[part]
            if not isinstance(ref, self._node_type):
                raise MetadataInconsistency(
                    "Cannot access path '{}': '{}' is already defined as an attribute, "
                    "not a namespace".format(path_to_str(path), part))

        if attribute_name in ref and isinstance(ref[attribute_name],
                                                self._node_type):
            if isinstance(attr, self._node_type):
                # in-between nodes are auto-created, so ignore it's OK unless we want to change the type
                return
            raise MetadataInconsistency(
                "Cannot set attribute '{}'. It's a namespace".format(
                    path_to_str(path)))

        ref[attribute_name] = attr
Example #10
0
    def get(self, path: List[str]) -> Union[T, Node, None]:
        ref = self._structure

        for index, part in enumerate(path):
            if not isinstance(ref, self._node_type):
                raise MetadataInconsistency(
                    "Cannot access path '{}': '{}' is already defined as an attribute, "
                    "not a namespace".format(path_to_str(path),
                                             path_to_str(path[:index])))
            if part not in ref:
                return None
            ref = ref[part]

        return ref
Example #11
0
 def _execute_operation(self, container_id: str,
                        container_type: ContainerType,
                        op: Operation) -> None:
     run = self._get_container(container_id, container_type)
     val = run.get(op.path)
     if val is not None and not isinstance(val, Value):
         if isinstance(val, dict):
             raise MetadataInconsistency(
                 "{} is a namespace, not an attribute".format(op.path))
         else:
             raise InternalClientError("{} is a {}".format(
                 op.path, type(val)))
     visitor = NeptuneBackendMock.NewValueOpVisitor(self, op.path, val)
     new_val = visitor.visit(op)
     if new_val is not None:
         run.set(op.path, new_val)
     else:
         run.pop(op.path)
Example #12
0
    def _process_config_op(self, expected_type: _DataType,
                           op: Operation) -> None:

        if self._type and self._type != expected_type:
            # This case should never happen since inconsistencies on data types are verified on user api.
            # So such operations should not appear in the queue without delete operation between them.
            # Still we want to support this case to avoid some unclear dependencies and assumptions.
            self._errors.append(
                MetadataInconsistency(
                    "Cannot perform {} operation on {}: Attribute is not a {}".
                    format(
                        op.__class__.__name__,
                        path_to_str(self._path),
                        expected_type.value,
                    )))
        else:
            self._type = expected_type
            self._config_ops = [op]
Example #13
0
    def test_file_set(self):
        # given
        processor = OperationsPreprocessor()

        # when
        processor.process([
            UploadFileSet(["a"], ["xx", "y", "abc"], reset=False),
            DeleteAttribute(["a"]),
            UploadFileSet(["a"], ["hhh", "gij"], reset=False),
            DeleteAttribute(["b"]),
            UploadFileSet(["b"], ["abc", "defgh"], reset=True),
            UploadFileSet(["c"], ["hhh", "gij"], reset=False),
            UploadFileSet(["c"], ["abc", "defgh"], reset=True),
            UploadFileSet(["c"], ["qqq"], reset=False),
            UploadFileSet(["d"], ["hhh", "gij"], reset=False),
            AssignFloat(["e"], 5),
            UploadFileSet(["e"], [""], reset=False),
        ])

        # then
        self.assertEqual(
            processor.get_operations(),
            [
                UploadFileSet(["a"], ["xx", "y", "abc"], reset=False),
                DeleteAttribute(["a"]),
                UploadFileSet(["a"], ["hhh", "gij"], reset=False),
                DeleteAttribute(["b"]),
                UploadFileSet(["b"], ["abc", "defgh"], reset=True),
                UploadFileSet(["c"], ["abc", "defgh"], reset=True),
                UploadFileSet(["c"], ["qqq"], reset=False),
                UploadFileSet(["d"], ["hhh", "gij"], reset=False),
                AssignFloat(["e"], 5),
            ],
        )
        self.assertEqual(
            processor.get_errors(),
            [
                MetadataInconsistency(
                    "Cannot perform UploadFileSet operation on e: Attribute is not a File Set"
                )
            ],
        )
Example #14
0
    def test_assign(self):
        # given
        processor = OperationsPreprocessor()

        # when
        processor.process([
            AssignFloat(["a"], 1),
            DeleteAttribute(["a"]),
            AssignString(["a"], "111"),
            DeleteAttribute(["b"]),
            AssignFloat(["b"], 2),
            AssignFloat(["c"], 3),
            AssignString(["c"], "333"),
            AssignString(["d"], "44"),
            AssignFloat(["e"], 5),
            AssignFloat(["e"], 10),
            AssignFloat(["e"], 33),
        ])

        # then
        self.assertEqual(
            processor.get_operations(),
            [
                AssignFloat(["a"], 1),
                DeleteAttribute(["a"]),
                AssignString(["a"], "111"),
                DeleteAttribute(["b"]),
                AssignFloat(["b"], 2),
                AssignFloat(["c"], 3),
                AssignString(["d"], "44"),
                AssignFloat(["e"], 33),
            ],
        )
        self.assertEqual(
            processor.get_errors(),
            [
                MetadataInconsistency(
                    "Cannot perform AssignString operation on c: Attribute is not a String"
                )
            ],
        )
Example #15
0
    def define(
        self,
        path: str,
        value: Union[Value, int, float, str, datetime],
        wait: bool = False,
    ) -> Attribute:
        if isinstance(value, Value):
            pass
        elif isinstance(value, Handler):
            value = ValueCopy(value)
        elif is_bool(value):
            value = Boolean(value)
        elif is_int(value):
            value = Integer(value)
        elif is_float(value):
            value = Float(value)
        elif is_string(value):
            value = String(value)
        elif isinstance(value, datetime):
            value = Datetime(value)
        elif is_float_like(value):
            value = Float(float(value))
        elif is_dict_like(value):
            value = Namespace(value)
        elif is_string_like(value):
            value = String(str(value))
        else:
            raise TypeError("Value of unsupported type {}".format(type(value)))
        parsed_path = parse_path(path)

        with self._lock:
            old_attr = self._structure.get(parsed_path)
            if old_attr:
                raise MetadataInconsistency(
                    "Attribute or namespace {} is already defined".format(
                        path))
            attr = ValueToAttributeVisitor(self, parsed_path).visit(value)
            self._structure.set(parsed_path, attr)
            attr.process_assignment(value, wait)
            return attr
Example #16
0
    def test_artifacts(self):
        # given
        processor = OperationsPreprocessor()
        project_uuid = uuid.uuid4()

        # when
        processor.process([
            TrackFilesToArtifact(["a"], project_uuid, [("dir1/", None)]),
            DeleteAttribute(["a"]),
            TrackFilesToArtifact(["b"], project_uuid, [("dir1/", None)]),
            TrackFilesToArtifact(["b"], project_uuid,
                                 [("dir2/dir3/", "dir2/")]),
            TrackFilesToArtifact(["b"], project_uuid,
                                 [("dir4/dir5/", "dir4/")]),
            AssignFloat(["c"], 5),
            TrackFilesToArtifact(["c"], project_uuid, [("dir1/", None)]),
            TrackFilesToArtifact(["d"], project_uuid,
                                 [("dir2/dir3/", "dir2/")]),
            TrackFilesToArtifact(["d"], project_uuid, [("dir4/", None)]),
            TrackFilesToArtifact(["e"], project_uuid, [("dir1/", None)]),
            TrackFilesToArtifact(["e"], project_uuid,
                                 [("dir2/dir3/", "dir2/")]),
            TrackFilesToArtifact(["f"], project_uuid, [("dir1/", None)]),
            TrackFilesToArtifact(["f"], project_uuid,
                                 [("dir2/dir3/", "dir2/")]),
            TrackFilesToArtifact(["f"], project_uuid, [("dir4/", None)]),
        ])

        # then
        self.assertEqual(
            processor.get_operations(),
            [
                TrackFilesToArtifact(["a"], project_uuid, [("dir1/", None)]),
                DeleteAttribute(["a"]),
                TrackFilesToArtifact(
                    ["b"],
                    project_uuid,
                    [("dir1/", None), ("dir2/dir3/", "dir2/"),
                     ("dir4/dir5/", "dir4/")],
                ),
                AssignFloat(["c"], 5),
                TrackFilesToArtifact(["d"],
                                     project_uuid, [("dir2/dir3/", "dir2/"),
                                                    ("dir4/", None)]),
                TrackFilesToArtifact(["e"],
                                     project_uuid, [("dir1/", None),
                                                    ("dir2/dir3/", "dir2/")]),
                TrackFilesToArtifact(
                    ["f"],
                    project_uuid,
                    [("dir1/", None), ("dir2/dir3/", "dir2/"),
                     ("dir4/", None)],
                ),
            ],
        )
        self.assertEqual(
            processor.get_errors(),
            [
                MetadataInconsistency(
                    "Cannot perform TrackFilesToArtifact operation on c: Attribute is not a Artifact"
                ),
            ],
        )
Example #17
0
    def test_sets(self):
        # given
        processor = OperationsPreprocessor()

        # when
        processor.process([
            AddStrings(["a"], {"xx", "y", "abc"}),
            DeleteAttribute(["a"]),
            AddStrings(["a"], {"hhh", "gij"}),
            DeleteAttribute(["b"]),
            RemoveStrings(["b"], {"abc", "defgh"}),
            AddStrings(["c"], {"hhh", "gij"}),
            RemoveStrings(["c"], {"abc", "defgh"}),
            AddStrings(["c"], {"qqq"}),
            ClearStringSet(["d"]),
            RemoveStrings(["e"], {"abc", "defgh"}),
            AddStrings(["e"], {"qqq"}),
            ClearStringSet(["e"]),
            AddStrings(["f"], {"hhh", "gij"}),
            RemoveStrings(["f"], {"abc", "defgh"}),
            AddStrings(["f"], {"qqq"}),
            ClearStringSet(["f"]),
            AddStrings(["f"], {"xx", "y", "abc"}),
            RemoveStrings(["f"], {"abc", "defgh"}),
            AssignString(["h"], "44"),
            RemoveStrings(["h"], {""}),
            AssignFloat(["i"], 5),
            AddStrings(["i"], {""}),
        ])

        # then
        self.assertEqual(
            processor.get_operations(),
            [
                AddStrings(["a"], {"xx", "y", "abc"}),
                DeleteAttribute(["a"]),
                AddStrings(["a"], {"hhh", "gij"}),
                DeleteAttribute(["b"]),
                RemoveStrings(["b"], {"abc", "defgh"}),
                AddStrings(["c"], {"hhh", "gij"}),
                RemoveStrings(["c"], {"abc", "defgh"}),
                AddStrings(["c"], {"qqq"}),
                ClearStringSet(["d"]),
                ClearStringSet(["e"]),
                ClearStringSet(["f"]),
                AddStrings(["f"], {"xx", "y", "abc"}),
                RemoveStrings(["f"], {"abc", "defgh"}),
                AssignString(["h"], "44"),
                AssignFloat(["i"], 5),
            ],
        )
        self.assertEqual(
            processor.get_errors(),
            [
                MetadataInconsistency(
                    "Cannot perform RemoveStrings operation on h: Attribute is not a String Set"
                ),
                MetadataInconsistency(
                    "Cannot perform AddStrings operation on i: Attribute is not a String Set"
                ),
            ],
        )
Example #18
0
    def test_series(self):
        # given
        processor = OperationsPreprocessor()

        # when
        processor.process([
            LogFloats(["a"], [FLog(1, 2, 3)]),
            ConfigFloatSeries(["a"], min=7, max=70, unit="%"),
            DeleteAttribute(["a"]),
            LogStrings(["a"], [SLog("111", 3, 4)]),
            DeleteAttribute(["b"]),
            LogStrings(["b"], [SLog("222", None, 6)]),
            LogFloats(["c"], [FLog(1, 2, 3)]),
            LogFloats(["c"],
                      [FLog(10, 20, 30), FLog(100, 200, 300)]),
            LogStrings(["d"], [SLog("4", 111, 222)]),
            ClearFloatLog(["e"]),
            LogImages(["f"], [ILog("1", 2, 3)]),
            LogImages(
                ["f"],
                [ILog("10", 20, 30), FLog("100", 200, 300)]),
            LogImages(["f"], [ILog("1", 2, 3)]),
            LogImages(
                ["f"],
                [ILog("10", 20, 30), FLog("100", 200, 300)]),
            ClearImageLog(["f"]),
            LogImages(
                ["f"],
                [ILog("3", 20, 30), FLog("4", 200, 300)]),
            LogImages(["f"], [ILog("5", 2, 3)]),
            LogImages(
                ["f"],
                [ILog("8", 20, 30), FLog("1000", 200, 300)]),
            LogImages(
                ["g"],
                [ILog("10", 20, 30), FLog("100", 200, 300)]),
            ClearImageLog(["g"]),
            AssignString(["h"], "44"),
            LogFloats(["h"],
                      [FLog(10, 20, 30), FLog(100, 200, 300)]),
            LogFloats(["i"], [FLog(1, 2, 3)]),
            ConfigFloatSeries(["i"], min=7, max=70, unit="%"),
            ClearFloatLog(["i"]),
            LogFloats(["i"],
                      [FLog(10, 20, 30), FLog(100, 200, 300)]),
        ])

        # then
        self.assertEqual(
            processor.get_operations(),
            [
                LogFloats(["a"], [FLog(1, 2, 3)]),
                DeleteAttribute(["a"]),
                LogStrings(["a"], [FLog("111", 3, 4)]),
                DeleteAttribute(["b"]),
                LogStrings(["b"], [SLog("222", None, 6)]),
                LogFloats(
                    ["c"],
                    [FLog(1, 2, 3),
                     FLog(10, 20, 30),
                     FLog(100, 200, 300)]),
                LogStrings(["d"], [SLog("4", 111, 222)]),
                ClearFloatLog(["e"]),
                ClearImageLog(["f"]),
                LogImages(
                    ["f"],
                    [
                        ILog("3", 20, 30),
                        FLog("4", 200, 300),
                        ILog("5", 2, 3),
                        ILog("8", 20, 30),
                        FLog("1000", 200, 300),
                    ],
                ),
                ClearImageLog(["g"]),
                AssignString(["h"], "44"),
                ClearFloatLog(["i"]),
                LogFloats(["i"], [FLog(10, 20, 30),
                                  FLog(100, 200, 300)]),
                ConfigFloatSeries(["i"], min=7, max=70, unit="%"),
            ],
        )
        self.assertEqual(
            processor.get_errors(),
            [
                MetadataInconsistency(
                    "Cannot perform LogFloats operation on h: Attribute is not a Float Series"
                )
            ],
        )
Example #19
0
    def test_execute_operations(self, upload_mock, swagger_client_factory):
        # given
        swagger_client = self._get_swagger_client_mock(swagger_client_factory)
        backend = HostedNeptuneBackend(credentials)
        container_uuid = str(uuid.uuid4())

        response_error = MagicMock()
        response_error.errorDescription = "error1"
        swagger_client.api.executeOperations().response().result = [response_error]
        swagger_client.api.executeOperations.reset_mock()
        upload_mock.return_value = [FileUploadError("file1", "error2")]
        some_text = "Some streamed text"
        some_binary = b"Some streamed binary"

        for container_type in self.container_types:
            with self.subTest(msg=f"For type {container_type.value}"):
                upload_mock.reset_mock()
                swagger_client_factory.reset_mock()

                # when
                result = backend.execute_operations(
                    container_id=container_uuid,
                    container_type=container_type,
                    operations=[
                        UploadFile(
                            path=["some", "files", "some_file"],
                            ext="",
                            file_path="path_to_file",
                        ),
                        UploadFileContent(
                            path=["some", "files", "some_text_stream"],
                            ext="txt",
                            file_content=base64_encode(some_text.encode("utf-8")),
                        ),
                        UploadFileContent(
                            path=["some", "files", "some_binary_stream"],
                            ext="bin",
                            file_content=base64_encode(some_binary),
                        ),
                        LogFloats(["images", "img1"], [LogFloats.ValueType(1, 2, 3)]),
                        AssignString(["properties", "name"], "some text"),
                        UploadFile(
                            path=["some", "other", "file.txt"],
                            ext="txt",
                            file_path="other/file/path.txt",
                        ),
                    ],
                )

                # then
                swagger_client.api.executeOperations.assert_called_once_with(
                    **{
                        "experimentId": str(container_uuid),
                        "operations": [
                            {
                                "path": "images/img1",
                                "logFloats": {
                                    "entries": [
                                        {
                                            "value": 1,
                                            "step": 2,
                                            "timestampMilliseconds": 3000,
                                        }
                                    ]
                                },
                            },
                            {
                                "path": "properties/name",
                                "assignString": {"value": "some text"},
                            },
                        ],
                        **DEFAULT_REQUEST_KWARGS,
                    }
                )

                upload_mock.assert_has_calls(
                    [
                        call(
                            swagger_client=backend.leaderboard_client,
                            container_id=container_uuid,
                            attribute="some/other/file.txt",
                            source="other/file/path.txt",
                            ext="txt",
                            multipart_config=backend._client_config.multipart_config,
                        ),
                        call(
                            swagger_client=backend.leaderboard_client,
                            container_id=container_uuid,
                            attribute="some/files/some_file",
                            source="path_to_file",
                            ext="",
                            multipart_config=backend._client_config.multipart_config,
                        ),
                        call(
                            swagger_client=backend.leaderboard_client,
                            container_id=container_uuid,
                            attribute="some/files/some_text_stream",
                            source=some_text.encode("utf-8"),
                            ext="txt",
                            multipart_config=backend._client_config.multipart_config,
                        ),
                        call(
                            swagger_client=backend.leaderboard_client,
                            container_id=container_uuid,
                            attribute="some/files/some_binary_stream",
                            source=some_binary,
                            ext="bin",
                            multipart_config=backend._client_config.multipart_config,
                        ),
                    ],
                    any_order=True,
                )

                self.assertEqual(
                    (
                        6,
                        [
                            FileUploadError("file1", "error2"),
                            FileUploadError("file1", "error2"),
                            FileUploadError("file1", "error2"),
                            FileUploadError("file1", "error2"),
                            MetadataInconsistency("error1"),
                        ],
                    ),
                    result,
                )
Example #20
0
def _multichunk_upload(
    upload_entry: UploadEntry,
    swagger_client: SwaggerClient,
    query_params: dict,
    multipart_config: MultipartConfig,
    target: FileUploadTarget,
):
    urlset = _build_multipart_urlset(swagger_client, target)
    file_stream = upload_entry.get_stream()
    entry_length = upload_entry.length()
    try:
        if entry_length <= multipart_config.max_single_part_size:
            # single upload
            data = file_stream.read()
            result = upload_raw_data(
                http_client=swagger_client.swagger_spec.http_client,
                url=urlset.single,
                data=data,
                query_params=query_params,
            )
            _attribute_upload_response_handler(result)
        else:
            # chunked upload
            result = (
                urlset.start_chunked(**query_params, totalLength=entry_length)
                .response()
                .result
            )
            if result.errors:
                raise MetadataInconsistency(
                    [err.errorDescription for err in result.errors]
                )

            if "ext" in query_params:
                del query_params["ext"]

            upload_id = result.uploadId
            chunker = FileChunker(
                upload_entry.source_path, file_stream, entry_length, multipart_config
            )
            for idx, chunk in enumerate(chunker.generate()):
                result = upload_raw_data(
                    http_client=swagger_client.swagger_spec.http_client,
                    url=urlset.send_chunk,
                    data=chunk.data,
                    headers={"X-Range": _build_x_range(chunk, entry_length)},
                    query_params={
                        "uploadId": upload_id,
                        "uploadPartIdx": idx,
                        **query_params,
                    },
                )
                _attribute_upload_response_handler(result)

            result = (
                urlset.finish_chunked(**query_params, uploadId=upload_id)
                .response()
                .result
            )
            if result.errors:
                raise MetadataInconsistency(
                    [err.errorDescription for err in result.errors]
                )
        return []
    finally:
        file_stream.close()
Example #21
0
 def visit_copy_attribute(self, op: CopyAttribute) -> None:
     raise MetadataInconsistency(
         "No CopyAttribute should reach accumulator")
Example #22
0
def upload_file_set_attribute(
    swagger_client: SwaggerClient,
    container_id: str,
    attribute: str,
    file_globs: Iterable[str],
    reset: bool,
    multipart_config: Optional[MultipartConfig],
) -> List[NeptuneException]:
    unique_upload_entries = get_unique_upload_entries(file_globs)

    try:
        upload_configuration = DEFAULT_UPLOAD_CONFIG
        for package in split_upload_files(
            upload_entries=unique_upload_entries,
            upload_configuration=upload_configuration,
        ):
            if package.is_empty() and not reset:
                continue

            uploading_multiple_entries = package.len > 1
            creating_a_single_empty_dir = (
                package.len == 1
                and not package.items[0].is_stream()
                and os.path.isdir(package.items[0].source_path)
            )

            if (
                uploading_multiple_entries
                or creating_a_single_empty_dir
                or package.is_empty()
            ):
                data = compress_to_tar_gz_in_memory(upload_entries=package.items)
                url = build_operation_url(
                    swagger_client.swagger_spec.api_url,
                    swagger_client.api.uploadFileSetAttributeTar.operation.path_name,
                )
                result = upload_raw_data(
                    http_client=swagger_client.swagger_spec.http_client,
                    url=url,
                    data=data,
                    headers={"Content-Type": "application/octet-stream"},
                    query_params={
                        "experimentId": container_id,
                        "attribute": attribute,
                        "reset": str(reset),
                    },
                )
                _attribute_upload_response_handler(result)
            else:
                upload_entry = package.items[0]
                if multipart_config is None:
                    # the legacy upload procedure
                    url = build_operation_url(
                        swagger_client.swagger_spec.api_url,
                        swagger_client.api.uploadFileSetAttributeChunk.operation.path_name,
                    )
                    file_chunk_stream = FileChunkStream(
                        upload_entry=upload_entry,
                        upload_configuration=upload_configuration,
                    )
                    _upload_loop(
                        file_chunk_stream=file_chunk_stream,
                        http_client=swagger_client.swagger_spec.http_client,
                        url=url,
                        query_params={
                            "experimentId": container_id,
                            "attribute": attribute,
                            "reset": str(reset),
                            "path": upload_entry.target_path,
                        },
                    )
                else:
                    _multichunk_upload(
                        upload_entry,
                        query_params={
                            "experimentIdentifier": container_id,
                            "attribute": attribute,
                            "subPath": upload_entry.target_path,
                        },
                        swagger_client=swagger_client,
                        multipart_config=multipart_config,
                        target=FileUploadTarget.FILE_SET,
                    )

            reset = False
    except MetadataInconsistency as e:
        if len(e.args) == 1:
            return [e]
        else:
            return [MetadataInconsistency(desc) for desc in e.args]
Example #23
0
 def _create_type_error(self, op_name, expected):
     return MetadataInconsistency(
         "Cannot perform {} operation on {}. Expected {}, {} found.".
         format(op_name, self._path, expected,
                type(self._current_value)))