1# Copyright (c) 2018 Ultimaker B.V. 2# libCharon is released under the terms of the LGPLv3 or higher. 3from typing import Any, Dict, List, IO, Optional, Callable 4 5from Charon.OpenMode import OpenMode 6 7 8## An interface for accessing files. 9# 10# This interface is designed to be able to access 3D-printing related files, 11# and for container-type files to access the resources therein. 12class FileInterface: 13 stream_handler = open # type: Callable[[str, str], IO[bytes]] 14 15 mime_type = "" 16 17 ## Opens a file for reading or writing. 18 # 19 # After opening the file, this instance will represent that file from then 20 # on, meaning that the metadata getters/setters and the streams will be 21 # functioning on that file. 22 # \param path The path to the file on local disk, relative or absolute. 23 # \param mode The mode with which to open the file (see OpenMode). 24 def open(self, path: str, mode: OpenMode = OpenMode.ReadOnly) -> None: 25 raise NotImplementedError("The open() function of " + self.__class__.__qualname__ + " is not implemented.") 26 27 ## Opens a stream for reading or writing. 28 # 29 # After opening the stream, this instance will represent that stream from 30 # then on, meaning that the metadata getters/setters and the streams will 31 # be functioning on that stream. 32 # \param stream The stream to read from or write to. 33 # \param mime The MIME type of the stream. This determines what implementation is used to read/write it. 34 # \param mode The mode with which to open the file (see OpenMode). 35 def openStream(self, stream: IO[bytes], mime: str, mode: OpenMode = OpenMode.ReadOnly) -> None: 36 raise NotImplementedError("The openStream() function of " + self.__class__.__qualname__ + " is not implemented.") 37 38 ## Closes the opened file, releasing the resources in use for it. 39 # 40 # After the file is closed, this instance can no longer be used until the ``open`` method is called again. 41 def close(self) -> None: 42 raise NotImplementedError("The close() function of " + self.__class__.__qualname__ + " is not implemented.") 43 44 ## Ensures that no buffered data is still pending to be read or written. 45 def flush(self) -> None: 46 raise NotImplementedError("The flush() function of " + self.__class__.__qualname__ + " is not implemented.") 47 48 ## Returns a list of all resources and metadata in the file. 49 def listPaths(self) -> List[str]: 50 raise NotImplementedError("The listPaths() function of " + self.__class__.__qualname__ + " is not implemented.") 51 52 ## Gets the data stored at the specified virtual path and all its descendants. 53 # 54 # The returned dictionary may contain normal resources as well as 55 # metadata. If it is a normal resource, the value will contain the 56 # serialised data (either ``bytes`` or ``str``, depending on whether the 57 # file opens in binary mode or not). If it is metadata, all metadata keys 58 # under the specified path are returned (all descendants in the tree). If 59 # there is no metadata and no resource under the selected virtual path, an 60 # empty dictionary is returned. 61 # \param virtual_path The path inside the file to get the data from. 62 # \return The data and metadata under the specified virtual path. 63 def getData(self, virtual_path: str) -> Dict[str, Any]: 64 raise NotImplementedError("The getData() function of " + self.__class__.__qualname__ + " is not implemented.") 65 66 ## Sets the data of several virtual paths at once. 67 # 68 # The ``data`` parameter provides a dictionary mapping virtual paths to 69 # the new data that should be provided in the path. 70 def setData(self, data: Dict[str, Any]) -> None: 71 raise NotImplementedError("The setData() function of " + self.__class__.__qualname__ + " is not implemented.") 72 73 ## Gets metadata entries in the opened file. 74 # 75 # The metadata is a dictionary, where the keys are virtual paths in the 76 # subtree of the resource tree specified by ``virtual_path``. For 77 # instance, when requesting the metadata of the resource with virtual path 78 # ``/metadata``, this function could return a dictionary containing: 79 # * ``/metadata/size``: 12354 80 # * ``/metadata/toolpath/default/size``: 12000 81 # * ``/metadata/toolpath/default/machine_type``: ``ultimaker3`` 82 # * ``/metadata/toolpath/default/print_time``: 121245 83 # * ``/metadata/toolpath/default/print_size``: (0, 0, 0) x (100, 100, 100) 84 # 85 # But a subtree can be requested as well, such as 86 # ``/metadata/toolpath/default/size``, which would then return a 87 # dictionary containing only the key ``/metadata/toolpath/default/size`` 88 # and its value, because there are no other subitems in that subtree. 89 # 90 # If there is no metadata in the requested path, an empty dictionary is 91 # returned. 92 # \param virtual_path The subtree of metadata entries to get the metadata 93 # of. 94 # \return A dictionary of all the metadata entries in the selected 95 # subtree. 96 def getMetadata(self, virtual_path: str) -> Dict[str, Any]: 97 raise NotImplementedError("The getMetadata() function of " + self.__class__.__qualname__ + " is not implemented.") 98 99 ## Changes some metadata entries in the opened file. 100 # 101 # The provided dictionary must have the full virtual paths of the metadata 102 # entries it wants to change as its keys, and the new values along with 103 # every key. 104 # 105 # If a metadata entry didn't exist yet, it is created. 106 # 107 # If a metadata entry by cannot be changed (such as the file size of a 108 # resource) then a ``ReadOnlyError`` must be raised for that resource, and 109 # none of the changes of this function call may be applied (or everything 110 # must be undone). 111 # \param metadata A dictionary of metadata entries to change. 112 # \raises ReadOnlyError A metadata entry cannot be changed (such as the 113 # file size of a resource). 114 def setMetadata(self, metadata: Dict[str, Any]) -> None: 115 raise NotImplementedError("The setMetadata() function of " + self.__class__.__qualname__ + " is not implemented.") 116 117 ## Gets an I/O stream to the resource or metadata at the specified virtual 118 # path. 119 # 120 # This stream may be a normal resource or it may be metadata. If it is 121 # metadata, a stream will be returned in the form of a JSON document 122 # (encoded in UTF-8 for binary streams) containing all the metadata that 123 # would be returned by the getMetadata method. 124 # 125 # Whether the returned stream is an input or an output stream depends on 126 # the mode that was provided in the ``open`` method. This determines 127 # whether you can read from and/or write to the stream. 128 # 129 # If a resource didn't exist and you can write, the resource is created. 130 # \param virtual_path The virtual path to the resource that you want to 131 # read or write. 132 # \raises ReadOnlyError The resource doesn't exist and there are no write 133 # permissions to create it. 134 def getStream(self, virtual_path: str) -> IO[bytes]: 135 raise NotImplementedError("The getStream() function of " + self.__class__.__qualname__ + " is not implemented.") 136 137 ## Gets a bytes representation of the file. 138 # 139 # Resources inside the file are not supported by this method. Use 140 # ``getStream`` for that. 141 # \param offset The number of bytes to skip at the beginning of the file. 142 # \param count The maximum number of bytes to return. If the file is 143 # longer than this, it is truncated. If the file is shorter than this, 144 # fewer bytes than this might be returned. If not specified, the entire 145 # file will be returned except the initial offset. 146 # \return bytes A bytes array representing the file or a part of it. 147 def toByteArray(self, offset: int = 0, count: int = -1) -> bytes: 148 raise NotImplementedError("The toByteArray() function of " + self.__class__.__qualname__ + " is not implemented.")