Beispiel #1
0
def _build_accepted_media_types(media_types: Union[str, Sequence[str]]) -> str:
    """
    Builds the Accept header of media types as required by the GetObject transaction request.
    The qvalue is used to specify the desirability of a given media type with 1 being the most
    desirable, 0 being the least, and a range in between.
    See section 5.1 for the full definition:

    Accept    ::= type / subtype [; parameter] *(, type / subtype [; parameter])
    type      ::= * | <publicly defined type>
    subtype   ::= * | <publicly defined subtype>
    parameter ::= q = <qvalue scale from 0 to 1>

    A complete list of media types is available at http://www.iana.org/assignments/media-types.
    """
    if isinstance(media_types, str):
        return media_types

    elif not isinstance(media_types, Sequence):
        raise RetsClientError('Invalid media types argument')

    n = float(len(media_types))
    return ','.join(
        '%s;%.4f' % (types, 1 - i / n) for i, types in enumerate(media_types)
    )
Beispiel #2
0
def _build_entity_object_ids(
    entities: Union[str, Mapping[str, Any], Sequence[str]]
) -> str:
    """
    Builds the string of object ids as required by the GetObject transaction request. See
    section 5.3 for the full definition:

    ID              ::= resource-set *(, resource-set)
    resource-set    ::= resource-entity [: object-id-list]
    resource-entity ::= 1*ALPHANUM
    object-id-list  ::= * | object-id *(: object-id)
    object-id       ::= 1*5DIGIT
    """
    if isinstance(entities, str):
        return _build_entity_object_ids((entities,))

    elif isinstance(entities, Sequence):
        return _build_entity_object_ids({e: '*' for e in entities})

    elif not isinstance(entities, Mapping):
        raise RetsClientError('Invalid entities argument')

    def _build_object_ids(object_ids: Any) -> str:
        if object_ids in ('*', 0, '0'):
            return str(object_ids)

        elif isinstance(object_ids, Sequence):
            return ':'.join(str(o) for o in object_ids)

        else:
            raise RetsClientError('Invalid entities argument')

    return ','.join(
        '%s:%s' % (entity, _build_object_ids(object_ids))
        for entity, object_ids in entities.items()
    )
Beispiel #3
0
def _get_http_auth(username: str, password: str, auth_type: str) -> AuthBase:
    if auth_type == 'basic':
        return HTTPBasicAuth(username, password)
    if auth_type == 'digest':
        return HTTPDigestAuth(username, password)
    raise RetsClientError('unknown auth type %s' % auth_type)
Beispiel #4
0
 def _assert_fields(self, fields: Sequence[str]) -> None:
     permissible = self.table.fields
     invalid = tuple(f for f in fields if f not in permissible)
     if invalid:
         raise RetsClientError('invalid fields %s' % ','.join(invalid))
Beispiel #5
0
 def _url_for(self, transaction: str) -> str:
     try:
         url = self._capabilities[transaction]
     except KeyError:
         raise RetsClientError('No URL found for transaction %s' % transaction)
     return urljoin(self._base_url, url)
Beispiel #6
0
    def get_object(
        self,
        resource: str,
        object_type: str,
        resource_keys: Union[str, Mapping[str, Any], Sequence[str]],
        media_types: Union[str, Sequence[str]] = '*/*',
        location: bool = False,
    ) -> Sequence[Object]:
        """
        The GetObject transaction is used to retrieve structured information related to known
        system entities. It can be used to retrieve multimedia files and other key-related
        information. Objects requested and returned from this transaction are requested and
        returned as MIME media types. The message body for successful retrievals contains only
        the objects in the specified MIME media type. Error responses follow the normal response
        format (section 3.9).

        :param resource: A resource defined in the metadata dictionary (see Section 11.2.2). The
            resource from which the object should be retrieved is specified by this entry. For
            more information see 5.9. The resource must be a resource defined in the metadata
            (section 11.4.1).

        :param object_type: The object type as defined in the metadata (see Section 11.4.1). The
            grouping category to which the object belongs. The type must be an ObjectType defined
            in the Object metadata for this Resource. For more information see section 11.4.1.

        :param resource_keys: A single value or a list-like or dict-like container specifying the
            entities of the resource to retrieve objects for, where the entity is given by the
            KeyField of the resource. If the resource_ids is a value or is list-like, then all
            objects corresponding to the entities are returned by default. If resource_ids is
            dict-like, then it is a mapping from the resource entity to an object_id_list.

            The object_id_list can take the values: '*', 0, or an array of positive ids. If it is
            '*', then all objects are returns. If it is 0, then the preferred object is returned.
            Otherwise, the ids will refer to the sequential index of the objects beginning with 1.

        :param media_types: A single or list-like container of acceptable media types for the
            server to return. If media_types is like-like, then the ordering specifies the
            preference of the media types to return, with the first being the most desirable. If
            the server is unable to provide the requested media type, it should return a 406
            Not Acceptable status, or if no objects exist for any media type then the server
            should return a 404 Not Found.

        :param location: Flag to indicate whether the object or a URL to the object should be
            returned. If location is set to True, it is up to the server to support this
            functionality and the lifetime of the returned URL is not given by the RETS
            specification.
        """
        headers = {'Accept': _build_accepted_media_types(media_types)}
        payload = {
            'Resource': resource,
            'Type': object_type,
            'ID': _build_entity_object_ids(resource_keys),
            'Location': int(location),
            'Format': self.format_,
        }
        response = self._http_post(
            self._url_for('GetObject'), headers=headers, payload=payload
        )
        object_ = parse_object(response, self.parser)
        returned_object = []
        for obj in object_:
            if obj.content_id is not None:
                returned_object.append(obj)
                continue

            if len(resource_keys) == 1:
                returned_object.append(
                    obj._replace(content_id=list(resource_keys.keys())[0])
                )
            else:
                raise RetsClientError(
                    'The server\'s response does not contain content-id'
                )

        return returned_object