Skip to content

Commit a9ef460

Browse files
committed
Added support for downloading MD derivatives.
1 parent 939b3ee commit a9ef460

File tree

1 file changed

+73
-0
lines changed
  • src/autodesk_forge_sdk

1 file changed

+73
-0
lines changed

src/autodesk_forge_sdk/md.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,3 +333,76 @@ def get_viewable_properties(self, urn: str, guid: str) -> dict:
333333
# TODO: what about the EMEA endpoint?
334334
endpoint = "/designdata/{}/metadata/{}/properties".format(urn, guid)
335335
return self._get(endpoint, scopes=READ_SCOPES).json()
336+
337+
def get_derivative_info(self, urn: str, deriv_urn: str) -> dict:
338+
"""
339+
Return information about the specified derivative.
340+
341+
**Documentation**:
342+
https://forge.autodesk.com/en/docs/model-derivative/v2/reference/http/urn-manifest-derivativeurn-HEAD
343+
344+
Args:
345+
urn (str): Base64-encoded ID of the source file.
346+
deriv_urn (str): ID of one of the derivatives generated from the source file.
347+
348+
Returns:
349+
dict: Derivative information, currently with just a single property, "size",
350+
indicating the size of the derivative in bytes.
351+
"""
352+
# TODO: what about the EMEA endpoint?
353+
endpoint = "/designdata/{}/manifest/{}".format(urn, deriv_urn)
354+
resp = self._head(endpoint, scopes=READ_SCOPES)
355+
return { "size": int(resp.headers["Content-Length"]) }
356+
357+
def get_derivative(self, urn: str, deriv_urn: str, byte_range: tuple=None) -> bytes:
358+
"""
359+
Download a derivative generated from a specific source model. To download the derivative,
360+
you need to specify its URN which can be retrieved from the Model Derivative manifest.
361+
362+
**Documentation**:
363+
https://forge.autodesk.com/en/docs/model-derivative/v2/reference/http/urn-manifest-derivativeurn-GET
364+
365+
Args:
366+
urn (str): Base64-encoded ID of the source file.
367+
deriv_urn (str): ID of one of the derivatives generated from the source file.
368+
byte_range ((int,int), optional): Optional tuple with first and last byte
369+
of a range to download.
370+
371+
Returns:
372+
bytes: Derivative content.
373+
"""
374+
# TODO: what about the EMEA endpoint?
375+
endpoint = "/designdata/{}/manifest/{}".format(urn, deriv_urn)
376+
headers = {}
377+
if byte_range:
378+
headers["Range"] = "bytes={}-{}".format(byte_range[0], byte_range[1])
379+
return self._get(endpoint, scopes=READ_SCOPES, headers=headers).content
380+
381+
def get_derivative_chunked(self, urn: str, deriv_urn: str, chunk_size: int=1024*1024) -> bytes:
382+
"""
383+
Download complete derivative in chunks of specific size.
384+
385+
**Documentation**:
386+
https://forge.autodesk.com/en/docs/model-derivative/v2/reference/http/urn-manifest-derivativeurn-GET
387+
388+
Args:
389+
urn (str): Base64-encoded ID of the source file.
390+
deriv_urn (str): ID of one of the derivatives generated from the source file.
391+
chunk_size (int, optional): Size of individual chunks (in bytes).
392+
393+
Returns:
394+
bytes: Derivative content.
395+
"""
396+
deriv_info = self.get_derivative_info(urn, deriv_urn)
397+
buff = bytes()
398+
# TODO: what about the EMEA endpoint?
399+
downloaded_bytes = 0
400+
while downloaded_bytes < deriv_info["size"]:
401+
byte_range = (
402+
downloaded_bytes,
403+
min(downloaded_bytes + chunk_size - 1, deriv_info["size"] - 1)
404+
)
405+
# TODO: better way to concat buffers in memory?
406+
buff = buff + self.get_derivative(urn, deriv_urn, byte_range)
407+
downloaded_bytes += byte_range[1] - byte_range[0] + 1
408+
return buff

0 commit comments

Comments
 (0)