ADN Open CIS
Сообщество программистов Autodesk в СНГ

31/10/2017

Примеры скриптов по базовому рабочему процессу модели преобразования в Python

Когда я исследовал один случай перевода модели в SVF (формат Forge Viewer), я нашел старый скрипт Python, который не был перенесен. Поэтому я потратил время на то, чтобы работать с последней версией слежб Forge. Скрипт показывает весь рабочий процесс от получения токена, создания bucket, загрузки объекта для запроса преобразования объекта. Я думаю, что это было бы полезно для некоторых программистов Python, поэтому я выложил его на мой Github:

https://github.com/xiaodongliang/forge.workflow-python-sample

Код также прилагается сюда, чтобы его можно было найти в Интернете.

Код - Python: [Выделить]
  1. #!/usr/bin/env python
  2. # pyadva.py - продемонстрировать авторизацию Autodesk View и Data API и процесс преобразования на Python
  3. #
  4. # Copyright (C) 2017 by Forge Partnership, Autodesk Inc.
  5. #
  6. import base64, json, md5, os.path, requests, shutil, time
  7. from optparse import OptionParser
  8.  
  9. _version = '2.0'
  10.  
  11. BASE_URL = 'https://developer.api.autodesk.com/'
  12. BUCKET_KEY = '<your bucket name>'
  13.  
  14. _file_missing_prompt = "Error: specified %s file '%s' does not exist.\n"
  15.  
  16.  
  17. def parse_credentials(filename):
  18.   "Разобрать учетные данные из заданного текстового файла."
  19.   f = open( filename )
  20.   lines = f.readlines()
  21.   f.close()
  22.   credentials = []
  23.   for line in lines:
  24.     i = line.find('#')
  25.     if -1 < i: line = line[0:i]
  26.     i = line.find(':')
  27.     if -1 < i: line = line[i+1:]
  28.     line = line.strip()
  29.     if 0 < len(line):
  30.       print line
  31.       line = line.strip("\"'")
  32.       credentials.append(line)
  33.  
  34.   if 2 != len(credentials):
  35.     raise "Недопустимые учетные данные: ожидается две записи, ключ пользователя и секрет;\nпрочитано %s строк, %s после снятия комментариев." % (len(lines),len(credentials))
  36.     credentials = null
  37.  
  38.   return credentials
  39.  
  40.  
  41. def main():
  42.   "Управление авторизацией Autodesk 3D процессом преобразования."
  43.   global BUCKET_KEY
  44.  
  45.   progname = 'pylmv'
  46.   use = 'используется: %s [options]'% progname
  47.   parser = OptionParser( usage, version = progname + ' ' + _version )
  48.   parser.add_option( '-b', '--bucketskip', action='store_true', dest='bucketskip', help = 'skip bucket creation' )
  49.   parser.add_option( '-c', '--credentials', dest='credentials_filename', help = 'credentials filename', metavar="FILE", default='credentials.txt' )
  50.   parser.add_option( '-m', '--model', dest='model_filename', help = 'model filename', metavar="FILE", default='samples/mytestmodel.rvt' )
  51.   parser.add_option( '-q', '--quiet', dest='quiet', action='store_true', default=False, help = 'reduce verbosity' )
  52.   parser.add_option( '-u', '--urn', dest='urn', help = 'specify urn of already uploaded model file', default='' )
  53.  
  54.   (options, args) = parser.parse_args()
  55.  
  56.   print options
  57.   print args
  58.  
  59.   verbose = not options.quiet
  60.  
  61.   if 1 < len( args ):
  62.     raise SystemExit(parser.print_help() or 1)
  63.  
  64.   model_filepath = options.model_filename
  65.  
  66.   if not model_filepath:
  67.     print 'Пожалуйста, укажите файл модели для обработки.'
  68.     raise SystemExit(parser.print_help() or 2)
  69.  
  70.   if not os.path.exists( model_filepath ):
  71.     print _file_missing_prompt % ('model', model_filepath)
  72.     raise SystemExit(parser.print_help() or 3)
  73.  
  74.   # Шаг 1: зарегистрируйте и создайте приложение, извлеките учетные данные
  75.  
  76.   if not os.path.exists( options.credentials_filename ):
  77.     print _file_missing_prompt % ('credentials', options.credentials_filename)
  78.     raise SystemExit(parser.print_help() or 4)
  79.  
  80.   credentials = parse_credentials(options.credentials_filename)
  81.  
  82.   if not credentials:
  83.     print "Неверные учетные данные, указанные в '%s'." % options.credentials_filename
  84.     raise SystemExit(parser.print_help() or 5)
  85.  
  86.   consumer_key = credentials[0]
  87.   consumer_secret = credentials[1]
  88.   BUCKET_KEY =(BUCKET_KEY + '-' + consumer_key).lower ()
  89.  
  90.   # Шаг 2: Получите ваш токен доступа
  91.  
  92.   # curl -k \
  93.   # --data "client_id=<ваш идентификатор клиента>&client_secret = <ваш секрет клиента>&grant_type=client_credentials&scope=data:read data:write bucket:create bucket:read" \
  94.   # https://developer.api.autodesk.com/authentication/v1/authenticate \
  95.   # --header "Content-Type: application/x-www-form-urlencoded"
  96.  
  97.   url = BASE_URL + 'authentication/v1/authenticate'
  98.  
  99.   data = {
  100.     'client_id' : consumer_key,
  101.     'client_secret' : consumer_secret,
  102.     'grant_type' : 'client_credentials',
  103.     'scope''data:read data:write bucket:create bucket:read'
  104.    
  105.   }
  106.  
  107.   headers = {
  108.     'Content-Type' : 'application/x-www-form-urlencoded'
  109.   }
  110.  
  111.   r = requests.post(url, data=data, headers=headers)
  112.  
  113.   content = eval(r.content)
  114.  
  115.   if verbose or 200 != r.status_code:
  116.     print r.status_code
  117.     print r.headers['content-type']
  118.     print type(r.content)
  119.     print content
  120.     # -- пример результатов --
  121.     # 200
  122.     # application/json
  123.     # {"token_type":"Bearer","expires_in":1799,"access_token":"ESzsFt7OZ90tSUBGh6JrPoBjpdEp"}
  124.  
  125.   if 200 != r.status_code:
  126.     print "Код аутентификации, возвращаемый статусом %s." % r.status_code
  127.     raise SystemExit(6)
  128.  
  129.   access_token = content['access_token']
  130.  
  131.   print 'Шаг 2 возвращает токен доступа', access_token
  132.  
  133.   # Шаг 3: Создайте контейнер
  134.  
  135.   if not options.bucketskip:
  136.  
  137.     # Проверка первичного существования:
  138.  
  139.     # curl -k -X GET \
  140.     # -H "Authorization: Bearer lEaixuJ5wXby7Trk6Tb77g6Mi8IL" \
  141.     # https://developer.api.autodesk.com/oss/v2/buckets/<название вашего контейнера>/details
  142.  
  143.     url = BASE_URL + 'oss/v2/buckets/' + BUCKET_KEY + '/details'
  144.  
  145.     headers = {
  146.       'Authorization' : 'Bearer ' + access_token
  147.     }
  148.  
  149.     print 'Шаг 3: проверьте, существует ли контейнер'
  150.     print 'curl -k -X GET -H "Authorization: Bearer %s" %s' % (access_token, url)
  151.  
  152.     print url
  153.     print headers
  154.  
  155.     r = requests.get(url, headers=headers)
  156.  
  157.     if verbose:
  158.       print r.status_code
  159.       print r.headers['content-type']
  160.       print r.content
  161.       # -- пример результатов --
  162.       # 200
  163.       # application/json; charset=utf-8
  164.       # {
  165.       #  "key":"jtbucket",
  166.       #  "owner":"NjEasFuPL6WAsNctq3VCgXDnTUBGa858",
  167.       #  "createDate":1404399358062,
  168.       #  "permissions":[{"serviceId":"NjEasFuPL6WAsNctq3VCgXDnTUBGa858","access":"full"}],
  169.       #  "policyKey":"transient"
  170.       # }
  171.  
  172.     if 200 != r.status_code:
  173.  
  174.       # Создать новый контейнер:
  175.  
  176.       # curl -k \
  177.       # --header "Content-Type: application/json" --header "Authorization: Bearer fDqpZKYM7ExcC2694eQ1pwe8nwnW" \
  178.       # --data '{\"bucketKey\":\"<your bucket name>\",\"policyKey\":\"transient\"}' \
  179.       # https://developer.api.autodesk.com/oss/v2/buckets
  180.  
  181.       url = BASE_URL + 'oss/v2/buckets'
  182.  
  183.       data = {
  184.         'bucketKey' : BUCKET_KEY,
  185.         'policyKey' : 'transient'
  186.       }
  187.  
  188.       headers = {
  189.         'Content-Type' : 'application/json',
  190.         'Authorization' : 'Bearer ' + access_token
  191.       }
  192.  
  193.       print 'Шаг 3: Создайте контейнер'
  194.       print 'curl -k -H "Authorization: Bearer %s" -H "Content-Type:application/json" --data "{\\"bucketKey\\":\\"%s\\",\\"policyKey\\":\\"transient\\"}" %s' % (access_token, BUCKET_KEY, url)
  195.  
  196.       print url
  197.       print json.dumps(data)
  198.       print headers
  199.  
  200.       r = requests.post(url, data=json.dumps(data), headers=headers)
  201.  
  202.       if verbose or 200 != r.status_code:
  203.         print r.status_code
  204.         print r.headers['content-type']
  205.         print r.content
  206.         # -- пример результатов --
  207.         # Запрос Python завершился ошибкой, но сгенерированная команда curl
  208.         # отработала, и предоставила
  209.         # следующий результат:
  210.         #
  211.         # {
  212.         #  "key":"jtbucket",
  213.         #  "owner":"NjEasFuPL6WAsNctq3VCgXDnTUBGa858",
  214.         #  "createDate":1404399358062,
  215.         #  "permissions":[{"serviceId":"NjEasFuPL6WAsNctq3VCgXDnTUBGa858","access":"full"}],
  216.         #  "policyKey":"transient"
  217.         # }
  218.  
  219.       if 200 != r.status_code:
  220.         print "Создание ведра возвращает код состояния %s." % r.status_code
  221.         raise SystemExit(7)
  222.  
  223.   # Шаг 4: Загрузите файл
  224.  
  225.   if options.urn:
  226.     urn = options.urn
  227.   else:
  228.     # curl -k \
  229.     # --header "Authorization: Bearer K16B98iaYNElzVheldlUAUqOoMRC" \
  230.     # -H "Content-Type:application/octet-stream" \
  231.     # --upload-file "<имя вашего объекта>"
  232.     # -X PUT https://developer.api.autodesk.com/oss/v2/buckets/<your bucket name>/objects/<имя вашего объекта>
  233.  
  234.     filesize = os.path.getsize( model_filepath )
  235.     model_filename = os.path.basename( model_filepath ).replace(' ', '+')
  236.     #model_filename = model_filename.replace('.','_')
  237.  
  238.     url = 'https://developer.api.autodesk.com/oss/v2/buckets/' + BUCKET_KEY + '/objects/' + model_filename
  239.  
  240.     headers = {
  241.       'Content-Type' : 'application/octet-stream',
  242.       #'Content-Length' : str(filesize),
  243.       'Authorization' : 'Bearer ' + access_token,
  244.       #'Expect' : ''
  245.     }
  246.  
  247.     print "Шаг 4: начало загрузки файла модели '%s', %s байт..."% (model_filename,filesize)
  248.  
  249.     print 'curl -k -H "Authorization: Bearer %s" -H "Content-Type:application/octet-stream" -T "%s" -X PUT %s' % (access_token, model_filepath, url)
  250.  
  251.     with open(model_filepath, 'rb') as f:
  252.       #files = { model_filename : f }
  253.       #r = requests.put(url, headers=headers, files=files)
  254.       # выгрузка не принимает объекты, состоящие из нескольких частей
  255.       # смотрите http://docs.python-requests.org/en/latest/api/
  256.       # files: Словарь 'name': file-like-objects (or {'name': ('filename', fileobj)}) для выгрузки, состоящей из нескольких частей.
  257.       # data: Словарь, байты или файл-подобный объект для отправки в тело запроса.
  258.       r = requests.put(url, headers=headers, data=f)
  259.  
  260.     #with open(model_filepath, 'rb') as f:
  261.     #  request = requests.put(url, headers=headers, data=f)
  262.  
  263.     if verbose:
  264.       print r.status_code
  265.       print r.headers['content-type']
  266.       print r.content
  267.       # -- пример результатов --
  268.       # Запрос Python завершился ошибкой, но curl
  269.       # отработала, и предоставила
  270.       # следующий результат:
  271.       #
  272.       # {
  273.       # "bucket-key": "<ваше имя контейнера>",
  274.       #   "objects" : [ {
  275.       #     "location" : "https://developer.api.autodesk.com/oss/v1/buckets/jtbucket/objects/two_columns_rvt",
  276.       #     "size" : 4165632,
  277.       #     "key" : "two_columns_rvt",
  278.       #     "id" : "urn:adsk.objects:os.object:jtbucket/two_columns_rvt",
  279.       #     "sha-1" : "cb15374248562743c5a99e0bdb0535f508a19848",
  280.       #     "content-type" : "application/octet-stream"
  281.       #   } ]
  282.       # }
  283.     content = eval(r.content)
  284.     #urn = content['objects'][0]['id']
  285.     urn = content['objectId']
  286.     print 'id:', urn
  287.  
  288.     # import base64
  289.     # base64.b64encode("urn:adsk.objects:os.object:<имя вашего контейнера>/имя вашего объекта")
  290.     # 'dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6anRidWNrZXQvdHdvX2NvbHVtbnNfcnZ0'
  291.  
  292.     urn = base64.b64encode(urn)
  293.     print 'urn:', urn
  294.  
  295.   # Шаг 6: Регистрация данных с помощью служб просмотра
  296.  
  297.   # curl -k \
  298.   # -H "Content-Type: application/json" \
  299.   # -H "Authorization:Bearer 1f4bEhzvxJ9CMvMPSHD4gXO4SYEr" \
  300.   # -i -d "{\"urn\":\"dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6bXlidWNrZXQvc2t5c2NwcjEuM2Rz\"}" \
  301.   # https://developer.api.autodesk.com/modelderivative/v2/designdata/job
  302.  
  303.   url = BASE_URL + 'modelderivative/v2/designdata/job'
  304.  
  305.   data = {
  306.     "input": {
  307.         "urn": urn
  308.     },
  309.     "output": {
  310.         "destination": {
  311.             "region": "us"
  312.         },
  313.         "formats": [
  314.         {
  315.             "type": "svf",
  316.             "views":["2d", "3d"]
  317.         }]
  318.     }
  319.   }
  320.  
  321.   headers = {
  322.     'Content-Type' : 'application/json',
  323.     'Authorization' : 'Bearer ' + access_token
  324.   }
  325.  
  326.   print 'Шаг 6: запрос на преобразование объекта'
  327.   print 'curl -k -H "Authorization: Bearer %s" -H "Content-Type:application/json" -i -d "{\\"urn\\":\\"%s\\"}" %s' % (access_token, urn, url)
  328.  
  329.   print url
  330.   print json.dumps(data)
  331.   print headers
  332.  
  333.   r = requests.post(url, data=json.dumps(data), headers=headers)
  334.  
  335.   if verbose or 200 != r.status_code:
  336.     print r.status_code
  337.     print r.headers['content-type']
  338.     print r.content
  339.     # -- пример результатов --
  340.     # Запрос Python завершился ошибкой, но curl
  341.     # отработала, и предоставила
  342.     # следующий результат:
  343.     #
  344.  
  345.   if 200 != r.status_code:
  346.     print "Регистрировать данные, возвращаемые кодом состояния %s." % r.status_code
  347.     raise SystemExit(9)
  348.  
  349.  
  350. if __name__ == '__main__':
  351.   main()

Оригинальным автором этого образца является мой коллега Джереми Таммик. Недавно он также выпустил еще один блог по скриптам Python. 

https://forge.autodesk.com/cloud_and_mobile/2016/12/forge-formats-python-scripts.html

Источник: https://forge.autodesk.com/blog/sample-scripts-basic-workflow-translating-model-python

Автор перевода: Дмитрий Емельянов

Обсуждение: http://adn-cis.org/forum/index.php?topic=8121

Опубликовано 31.10.2017