AAS HTTP Client Documentation
Loading...
Searching...
No Matches
experimental_implementation.py
Go to the documentation of this file.
1"""Experimental implementation of Asset Administration Shell Registry related API calls."""
2
3import logging
4import mimetypes
5from pathlib import Path
6from typing import TYPE_CHECKING
7
8if TYPE_CHECKING:
9 from aas_http_client.classes.client.aas_client import AasHttpClient
10
11import requests
12from pydantic import BaseModel
13
14from aas_http_client.utilities.encoder import encode_base_64
16 STATUS_CODE_200,
17 STATUS_CODE_204,
18 STATUS_CODE_404,
19 log_response,
20)
21
22_logger = logging.getLogger(__name__)
23
24
26 """Implementation of Asset Administration Shell Registry related API calls."""
27
28 def __init__(self, client: "AasHttpClient"):
29 """Initializes the ExperimentalImplementation with the given client."""
30 self._client = client
31
32 session = client.get_session()
33 if session is None:
34 raise ValueError(
35 "HTTP session is not initialized in the client. Call 'initialize()' method of the client before creating SubmodelRegistryImplementation instance."
36 )
37
38 self._session: requests.Session = session
39
40 # GET /submodels/{submodelIdentifier}/submodel-elements/{idShortPath}/attachment
41 def get_file_by_path_submodel_repo(self, submodel_identifier: str, id_short_path: str) -> bytes | None:
42 """Downloads file content from a specific submodel element from the Submodel at a specified path. Experimental feature - may not be supported by all servers.
43
44 :param submodel_identifier: The Submodels unique id
45 :param id_short_path: IdShort path to the submodel element (dot-separated)
46 :return: Attachment file data as bytes (octet-stream) or None if an error occurred
47 """
48 if not self._client.encoded_ids:
49 submodel_identifier = encode_base_64(submodel_identifier)
51 url = f"{self._client.base_url}/submodels/{submodel_identifier}/submodel-elements/{id_short_path}/attachment"
52
53 self._client.set_token() # ensures Authorization header is set
54
55 try:
56 response = self._session.get(url, timeout=self._client.time_out)
57 _logger.debug(f"Call REST API url '{response.url}'")
58
59 if response.status_code == STATUS_CODE_404:
60 _logger.warning(
61 f"Submodel with id '{submodel_identifier}' or Submodel element with IDShort path '{id_short_path}' or file content not found."
62 )
63 _logger.debug(response.text)
64 return None
65
66 if response.status_code != STATUS_CODE_200:
67 log_response(response)
68 return None
69
70 except requests.exceptions.RequestException as e:
71 _logger.error(f"Error calling REST API: {e}")
72 return None
73
74 return response.content
75
76 # POST /submodels/{submodelIdentifier}/submodel-elements/{idShortPath}/attachment
77 def post_file_by_path_submodel_repo(self, submodel_identifier: str, id_short_path: str, file: Path) -> bool:
78 """Uploads file content to an existing submodel element at a specified path within submodel elements hierarchy. Experimental feature - may not be supported by all servers.
79
80 :param submodel_identifier: The Submodels unique id
81 :param id_short_path: IdShort path to the submodel element (dot-separated)
82 :param file: Path to the file to upload as attachment
83 :return: Attachment data as bytes or None if an error occurred
84 """
85 if file.exists() is False or not file.is_file():
86 _logger.error(f"Attachment file '{file}' does not exist.")
87 return False
88
89 if not self._client.encoded_ids:
90 submodel_identifier = encode_base_64(submodel_identifier)
91
92 url = f"{self._client.base_url}/submodels/{submodel_identifier}/submodel-elements/{id_short_path}/attachment"
93
94 self._client.set_token()
95
96 try:
97 mime_type, _ = mimetypes.guess_type(file)
98
99 with file.open("rb") as f:
100 files = {"file": (file.name, f, mime_type or "application/octet-stream")}
101 response = self._session.post(url, files=files, timeout=self._client.time_out)
102
103 _logger.debug(f"Call REST API url '{response.url}'")
104
105 if response.status_code == STATUS_CODE_404:
106 _logger.warning(f"Submodel with id '{submodel_identifier}' or Submodel element with IDShort path '{id_short_path}' not found.")
107 _logger.debug(response.text)
108 return False
109
110 # original dotnet server delivers 200 instead of 204
111 if response.status_code not in (STATUS_CODE_200, STATUS_CODE_204):
112 log_response(response)
113 return False
114
115 except requests.exceptions.RequestException as e:
116 _logger.error(f"Error call REST API: {e}")
117 return False
118
119 return True
120
121 # PUT /submodels/{submodelIdentifier}/submodel-elements/{idShortPath}/attachment
122 def put_file_by_path_submodel_repo(self, submodel_identifier: str, id_short_path: str, file: Path) -> bool:
123 """Uploads file content to an existing submodel element at a specified path within submodel elements hierarchy. Experimental feature - may not be supported by all servers.
124
125 :param submodel_identifier: The Submodels unique id
126 :param id_short_path: IdShort path to the submodel element (dot-separated)
127 :param file: Path to the file to upload as attachment
128 :return: Attachment data as bytes or None if an error occurred
129 """
130 if file.exists() is False or not file.is_file():
131 _logger.error(f"Attachment file '{file}' does not exist.")
132 return False
133
134 if not self._client.encoded_ids:
135 submodel_identifier = encode_base_64(submodel_identifier)
136
137 url = f"{self._client.base_url}/submodels/{submodel_identifier}/submodel-elements/{id_short_path}/attachment"
138
139 self._client.set_token()
140
141 try:
142 mime_type, _ = mimetypes.guess_type(file)
143
144 with file.open("rb") as f:
145 files = {"file": (file.name, f, mime_type or "application/octet-stream")}
146 response = self._session.put(url, files=files, timeout=self._client.time_out)
147
148 _logger.debug(f"Call REST API url '{response.url}'")
149
150 if response.status_code == STATUS_CODE_404:
151 _logger.warning(f"Submodel with id '{submodel_identifier}' or Submodel element with IDShort path '{id_short_path}' not found.")
152 _logger.debug(response.text)
153 return False
154
155 # original dotnet server delivers 200 instead of 204
156 if response.status_code not in (STATUS_CODE_200, STATUS_CODE_204):
157 log_response(response)
158 return False
159
160 except requests.exceptions.RequestException as e:
161 _logger.error(f"Error call REST API: {e}")
162 return False
163
164 return True
165
166 # DELETE /submodels/{submodelIdentifier}/submodel-elements/{idShortPath}/attachment
167 def delete_file_by_path_submodel_repo(self, submodel_identifier: str, id_short_path: str) -> bool:
168 """Deletes file content of an existing submodel element at a specified path within submodel elements hierarchy. Experimental feature - may not be supported by all servers.
169
170 :param submodel_identifier: The Submodels unique id
171 :param id_short_path: IdShort path to the submodel element (dot-separated)
172 :return: True if deletion was successful, False otherwise
173 """
174 if not self._client.encoded_ids:
175 submodel_identifier = encode_base_64(submodel_identifier)
177 url = f"{self._client.base_url}/submodels/{submodel_identifier}/submodel-elements/{id_short_path}/attachment"
178
179 self._client.set_token()
180
181 try:
182 response = self._session.delete(url, timeout=self._client.time_out)
183 _logger.debug(f"Call REST API url '{response.url}'")
184
185 if response.status_code == 404:
186 _logger.warning(f"Submodel with id '{submodel_identifier}' or Submodel element with IDShort path '{id_short_path}' not found.")
187 return False
188
189 if response.status_code != STATUS_CODE_200:
190 log_response(response)
191 return False
192
193 except requests.exceptions.RequestException as e:
194 _logger.error(f"Error calling REST API: {e}")
195 return False
196
197 return True
198
199 def _post_multipart(self, url, files):
200 headers = dict(self._session.headers)
201 headers.pop("Content-Type", None)
202 return self._session.post(url, headers=headers, files=files)
Implementation of Asset Administration Shell Registry related API calls.
bool delete_file_by_path_submodel_repo(self, str submodel_identifier, str id_short_path)
Deletes file content of an existing submodel element at a specified path within submodel elements hie...
bool post_file_by_path_submodel_repo(self, str submodel_identifier, str id_short_path, Path file)
Uploads file content to an existing submodel element at a specified path within submodel elements hie...
bytes|None get_file_by_path_submodel_repo(self, str submodel_identifier, str id_short_path)
Downloads file content from a specific submodel element from the Submodel at a specified path.
__init__(self, "AasHttpClient" client)
Initializes the ExperimentalImplementation with the given client.
bool put_file_by_path_submodel_repo(self, str submodel_identifier, str id_short_path, Path file)
Uploads file content to an existing submodel element at a specified path within submodel elements hie...