text: 
  import os
  import json
  import uuid
  import logging
  import requests
  
  import predix.config
  import predix.service
  import predix.security.uaa
  
  
  class Asset(object):
      """
      Client library for working with the Predix Asset Service.  For more details
      on use of the service please see official docs:
      https://www.predix.io/services/service.html?id=1171
      """
      def __init__(self, *args, **kwargs):
          super(Asset, self).__init__(*args, **kwargs)
  
          key = predix.config.get_env_key(self, 'zone_id')
          self.zone_id = os.environ.get(key)
          if not self.zone_id:
              raise ValueError("%s environment unset" % key)
  
          key = predix.config.get_env_key(self, 'uri')
          self.uri = os.environ.get(key)
          if not self.uri:
              raise ValueError("%s environment unset" % key)
  
          self.service = predix.service.Service(self.zone_id)
  
      def authenticate_as_client(self, client_id, client_secret):
          """
          Will authenticate for the given client / secret.
          """
          self.service.uaa.authenticate(client_id, client_secret)
  
      def _get_collections(self):
          """
          Returns the names of all user-defined domain object collections with
          counts for number of domain objects contained in that collection.
  
          ..
  
              [ { "collection": "volcano", "count": 1 }, ... ]
  
          """
          uri = self.uri
          return self.service._get(uri)
  
      def get_collections(self):
          """
          Returns a flat list of the names of collections in the asset
          service.
  
          ..
  
              ['wind-turbines', 'jet-engines']
  
          """
          collections = []
          for result in self._get_collections():
              collections.append(result['collection'])
  
          return collections
  
      def get_collection(self, collection, filter=None, fields=None,
              page_size=None):
          """
          Returns a specific collection from the asset service with
          the given collection endpoint.
  
          Supports passing through parameters such as...
          - filters such as "name=Vesuvius" following GEL spec
          - fields such as "uri,description" comma delimited
          - page_size such as "100" (the default)
  
          """
          params = {}
          if filter:
              params['filter'] = filter
          if fields:
              params['fields'] = fields
          if page_size:
              params['pageSize'] = page_size
  
          uri = self.uri + '/v1' + collection
          return self.service._get(uri, params=params)
  
      def create_guid(self, collection=None):
          """
          Returns a new guid for use in posting a new asset to a collection.
          """
          guid = str(uuid.uuid4())
          if collection:
              return str.join('/', [collection, guid])
          else:
              return guid
  
      def post_collection(self, collection, body):
          """
          Creates a new collection.  This is mostly just transport layer
          and passes collection and body along.  It presumes the body
          already has generated.
  
          The collection is *not* expected to have the id.
          """
          assert isinstance(body, (list)), "POST requires body to be a list"
          assert collection.startswith('/'), "Collections must start with /"
          uri = self.uri + '/v1' + collection
          return self.service._post(uri, body)
  
      def put_collection(self, collection, body):
          """
          Updates an existing collection.
  
          The collection being updated *is* expected to include the id.
          """
  
          uri = self.uri + '/v1' + collection
          return self.service._put(uri, body)
  
      def delete_collection(self, collection):
          """
          Deletes an existing collection.
  
          The collection being updated *is* expected to include the id.
          """
          uri = str.join('/', [self.uri, collection])
          return self.service._delete(uri)
  
      def patch_collection(self, collection, changes):
          """
          Will make specific updates to a record based on JSON Patch
          documentation.
  
              https://tools.ietf.org/html/rfc6902
  
          the format of changes is something like::
  
              [{
                  'op': 'add',
                  'path': '/newfield',
                  'value': 'just added'
              }]
  
          """
          uri = str.join('/', [self.uri, collection])
          return self.service._patch(uri, changes)
  
      def get_audit(self):
          """
          Return audit report for asset.  Disabled by default.
          """
          return self.service._get(self.uri + '/v1/system/audit')
  
      def get_audit_changes(self):
          """
          Return change log for audit.  Disabled by default.
          """
          return self.service._get(self.uri + '/v1/system/audit/changes')
  
      def get_audit_snapshots(self):
          """
          Return an audit snapshot.  Disabled by default.
          """
          return self.service._get(self.uri + '/v1/system/audit/snapshots')
  
      def get_scripts(self):
          """
          Return any configured scripts for asset service.
          """
          return self.service._get(self.uri + '/v1/system/scripts')
  
      def get_messages(self):
          """
          Return any system messages related to asset systems.
          """
          return self.service._get(self.uri + '/v1/system/messages')
  
      def get_configs(self):
          """
          Return the configuration for the asset service.
          """
          return self.service._get(self.uri + '/v1/system/configs')
  
      def get_triggers(self):
          """
          Return configured triggers in the asset system.
          """
          return self.service._get(self.uri + '/v1/system/triggers')
  
      def save(self, collection):
          """
          Save an asset collection to the service.
          """
          assert isinstance(collection, predix.data.asset.AssetCollection), "Expected AssetCollection"
          collection.validate()
          self.put_collection(collection.uri, collection.__dict__) # MAINT: no
  
  class AssetCollection(object):
      """
      User Defined Domain Objects are the customizable collections to represent
      data in the Asset Service.
  
      This is experimental to provide a base class for a sort of ORM between
      domain objects to marshall and unmarshall between Python and the REST
      endpoints.
      """
      def __init__(self, parent=None, guid=None, *args, **kwargs):
          super(AssetCollection, self).__init__(*args, **kwargs)
  
          # You have the right to a guid, if you cannot afford a guid...
          if not guid:
              guid = str(uuid.uuid4())
  
          # By naming collection after classname we get safe URI
          # naming rules as well.
          collection = self.get_collection()
  
          # There is a no more than 2 forward slash limitation for uri, so
          # collections cannot really be nested deeper than one level.
          self.uri = '/' + str.join('/', [collection, guid])
  
      def __repr__(self):
          return json.dumps(self.__dict__)
  
      def __str__(self):
          return json.dumps(self.__dict__)
  
      def get_collection(self):
          return type(self).__name__.lower()
  
      def validate(self):
          """
          If an asset collection wants any client-side validation the
          object can override this method and it is called anytime
          we're saving.
          """
          return
  