def request(self, url, method='GET'): nocache = False if method != 'GET': logger.debug(logf({ 'message': 'Deleting cache...', 'key': url, })) cache.delete(url) nocache = True else: logger.debug(logf({ 'message': 'Getting cache...', 'key': url, })) result = cache.get(url) if result is not None: logger.debug( logf({ 'message': 'Found in cache.', 'key': url, 'value': result, })) return result # override super to handle HTTP response error client = self._main_client._store url = self._url_gen(url) response = client['session'].request(method, url) if response.status_code >= 300: raise exceptions.ProxyException( 'Failed to fetch resource (%s, %s %s)' % ( url, method, response.status_code, )) serializer = slumber.serialize.Serializer(default=client['format']) result = serializer.loads(response.content) if not nocache: logger.debug( logf({ 'message': 'Setting cache...', 'url': url, 'value': result, })) cache.set(url, result) return result
def request(self, url, method='GET'): nocache = False if method != 'GET': logger.debug(logf({ 'message': 'Deleting cache...', 'key': url, })) cache.delete(url) nocache = True else: logger.debug(logf({ 'message': 'Getting cache...', 'key': url, })) result = cache.get(url) if result is not None: logger.debug(logf({ 'message': 'Found in cache.', 'key': url, 'value': result, })) return result # override super to handle HTTP response error client = self._main_client._store url = self._url_gen(url) response = client['session'].request(method, url) if response.status_code >= 300: raise exceptions.ProxyException('Failed to fetch resource (%s, %s %s)' % (url, method, response.status_code,)) serializer = slumber.serialize.Serializer(default=client['format']) result = serializer.loads(response.content) if not nocache: logger.debug(logf({ 'message': 'Setting cache...', 'url': url, 'value': result, })) cache.set(url, result) return result
def __init__(self, *args, **kwargs): if (self._meta.abstract or (models and isinstance(self, models.Model))): super(Proxy, self).__init__(*args, **kwargs) return if not self._meta.api_url: raise exceptions.ProxyException(_('"API_URL" not found in settings or ' '"api_url" not found in kwargs.')) self._client = self._meta.client.get(self._meta.api_url, version=self._meta.version, namespace=self._meta.namespace or '/'.join(self.__module__.split('.')[1:-1]), auth=self._meta.auth if self._meta.auth[0] is not None else None, proxy=self) try: class_name = self.__class__.__name__ self._resource = getattr(self._client, self._meta.resource_name or class_name, getattr(self._client, self._meta.resource_name or class_name.lower(), None)) except AttributeError, e: logger.debug(logf({ 'message': 'API seems not to have endpoint for the resource.', 'resource': class_name, }))
def __init__(self, *args, **kwargs): if (self._meta.abstract or (models and isinstance(self, models.Model))): super(Proxy, self).__init__(*args, **kwargs) return if not self._meta.api_url: raise exceptions.ProxyException( _('"API_URL" not found in settings or ' '"api_url" not found in kwargs.')) self._client = self._meta.client.get( self._meta.api_url, version=self._meta.version, namespace=self._meta.namespace or '/'.join(self.__module__.split('.')[1:-1]), auth=self._meta.auth if self._meta.auth[0] is not None else None, proxy=self) try: class_name = self.__class__.__name__ self._resource = getattr( self._client, self._meta.resource_name or class_name, getattr(self._client, self._meta.resource_name or class_name.lower(), None)) except AttributeError, e: logger.debug( logf({ 'message': 'API seems not to have endpoint for the resource.', 'resource': class_name, }))
def to_python(self, obj, name, value): field_type = obj._schema_store['fields'][name]['type'] new_value = value if type(value) in (str, ): if field_type == 'datetime': new_value = dateparser.parse(value) elif field_type == 'date': new_value = dateparser.parse(value).date() elif field_type in ( 'list', 'json', ): new_value = value if value != new_value: logger.debug( logf({ 'message': 'Converting to python...', 'field': name, 'type': field_type, 'from': value.__repr__(), 'to': new_value.__repr__(), })) obj._fields[name] = new_value
def dispatch(self, request_type, request, **kwargs): # this needs to be called before method check try: self.is_authenticated(request) response = super(ModelResource, self).dispatch(request_type, request, **kwargs) except Exception, e: logger.exception(logf({"message": "A fatal error has occurred during processing dispatch", "exception": e})) raise e
def _response(self): if self.__response: return self.__response serializer = slumber.serialize.Serializer( default=self.model._main_client._store['format']) if self._url is not None: logger.debug( logf({ 'message': 'Getting cache...', 'key': self._url, })) cached = cache.get(self._url) if cached: logger.debug( logf({ 'message': 'Found in cache.', 'key': self._url, 'value': cached, })) self.refresh(serializer.loads(cached)) return self.__response response = super(Response, self)._response if self._url is not None: if 'model' in response: del (response['model']) content = serializer.dumps(response) logger.debug( logf({ 'message': 'Setting cache...', 'key': self._url, 'value': content, })) cache.set(self._url, content) return response
def debug(self, request, response, log=logger.debug): info = log if log == logger.exception else logger.info data = { "message": "API called.", "user": request.user, "method": request.method, "status_code": response.status_code, "path_info": request.META.get("PATH_INFO"), "query_string": request.META.get("QUERY_STRING"), } info(logf(data)) if len(request.raw_post_data): data["post_data"] = request.raw_post_data.decode("utf-8") if len(response.content): data["response"] = response.content.decode("utf-8") log(logf(data))
def debug(self, request, response, log=logger.debug): info = log if log == logger.exception else logger.info data = { 'message': 'API called.', 'user': request.user, 'method': request.method, 'status_code': response.status_code, 'path_info': request.META.get('PATH_INFO'), 'query_string': request.META.get('QUERY_STRING'), } info(logf(data)) if len(request.raw_post_data): data['post_data'] = request.raw_post_data.decode('utf-8') if len(response.content): data['response'] = response.content.decode('utf-8') log(logf(data))
def metadata(self): try: meta = getattr(import_module(self.__module__), self.meta_type_display) except Exception, e: logger.exception(logf({ 'message': 'No metadata model found.', 'meta_type': self.meta_type_display, 'exception': e, })) raise exceptions.ProxyException('No metadata model for ' '%s found.' % self.meta_type_display)
def _response(self): if self.__response: return self.__response serializer = slumber.serialize.Serializer(default=self.model._main_client._store['format']) if self._url is not None: logger.debug(logf({ 'message': 'Getting cache...', 'key': self._url, })) cached = cache.get(self._url) if cached: logger.debug(logf({ 'message': 'Found in cache.', 'key': self._url, 'value': cached, })) self.refresh(serializer.loads(cached)) return self.__response response = super(Response, self)._response if self._url is not None: if 'model' in response: del(response['model']) content = serializer.dumps(response) logger.debug(logf({ 'message': 'Setting cache...', 'key': self._url, 'value': content, })) cache.set(self._url, content) return response
def metadata(self): try: meta = getattr(import_module(self.__module__), self.meta_type_display) except Exception, e: logger.exception( logf({ 'message': 'No metadata model found.', 'meta_type': self.meta_type_display, 'exception': e, })) raise exceptions.ProxyException('No metadata model for ' '%s found.' % self.meta_type_display)
def dispatch(self, request_type, request, **kwargs): # this needs to be called before method check try: self.is_authenticated(request) response = super(ModelResource, self).dispatch(request_type, request, **kwargs) except Exception, e: logger.exception( logf({ 'message': 'A fatal error has occurred during processing dispatch', 'exception': e, })) raise e
def to_serializable(self, obj, name): field_type = obj._schema_store['fields'][name]['type'] value = new_value = obj._fields[name] if field_type == 'date' and type(value) not in (str,): new_value = value.isoformat() if value != new_value: logger.debug(logf({ 'message': 'Serializing from python...', 'field': name, 'type': field_type, 'from': value.__repr__(), 'to': new_value.__repr__() })) return new_value raise exceptions.ProxyException(_('Raise to call super.'))
def schema(self, model_name=None): path = '.'.join(self._base_url.replace(self._api_url, '').split('/')[:-1]) if model_name is None: model_name = path url = self._base_url else: url = self._url_gen('%s/schema/' % model_name) if model_name not in ProxyClient._schemas: try: self._schema_store[model_name] = self.request(url) ProxyClient._schemas[model_name] = self._schema_store[model_name] except Exception, e: logger.debug(logf({ 'message': 'Couldn\'t fetch the schema definition for some reason.', 'schema': model_name, }))
def to_serializable(self, obj, name): field_type = obj._schema_store['fields'][name]['type'] value = new_value = obj._fields[name] if field_type == 'date' and type(value) not in (str, ): new_value = value.isoformat() if value != new_value: logger.debug( logf({ 'message': 'Serializing from python...', 'field': name, 'type': field_type, 'from': value.__repr__(), 'to': new_value.__repr__() })) return new_value raise exceptions.ProxyException(_('Raise to call super.'))
def schema(self, model_name=None): path = '.'.join( self._base_url.replace(self._api_url, '').split('/')[:-1]) if model_name is None: model_name = path url = self._base_url else: url = self._url_gen('%s/schema/' % model_name) if model_name not in ProxyClient._schemas: try: self._schema_store[model_name] = self.request(url) ProxyClient._schemas[model_name] = self._schema_store[ model_name] except Exception, e: logger.debug( logf({ 'message': 'Couldn\'t fetch the schema definition for some reason.', 'schema': model_name, }))
def is_authenticated(self, request): super(ModelResource, self).is_authenticated(request) # allow superuser all operations dynamically if request.user.is_superuser: logger.debug( logf( { "message": "Hello superuser you can do anything with this resource.", "resource": request.META["PATH_INFO"], } ) ) self._meta.list_allowed_methods = ALL_METHODS self._meta.detail_allowed_methods = ALL_METHODS for field in self._meta.excludes: self.fields[field] = fields.CharField(attribute=field, blank=True, null=True, readonly=True) self._meta.excludes = []
def to_python(self, obj, name, value): field_type = obj._schema_store['fields'][name]['type'] new_value = value if type(value) in (str,): if field_type == 'datetime': new_value = dateparser.parse(value) elif field_type == 'date': new_value = dateparser.parse(value).date() elif field_type in ('list', 'json',): new_value = value if value != new_value: logger.debug(logf({ 'message': 'Converting to python...', 'field': name, 'type': field_type, 'from': value.__repr__(), 'to': new_value.__repr__(), })) obj._fields[name] = new_value
def is_authenticated(self, request): super(ModelResource, self).is_authenticated(request) # allow superuser all operations dynamically if request.user.is_superuser: logger.debug( logf({ 'message': 'Hello superuser you can do anything with this resource.', 'resource': request.META['PATH_INFO'], })) self._meta.list_allowed_methods = ALL_METHODS self._meta.detail_allowed_methods = ALL_METHODS for field in self._meta.excludes: self.fields[field] = fields.CharField(attribute=field, blank=True, null=True, readonly=True) self._meta.excludes = []
# strip <id> or ``schema`` part and extract resource_name paths.pop() resource_name = paths.pop() if version in paths: paths.remove(version) namespace = '/'.join(paths) logger.debug( logf({ 'message': 'Need namespace schema.', 'attribute': name, 'resource_uri': self._response[name], 'client_key': ProxyClient.build_client_key( base_client._api_url, **{ 'version': base_client._version, 'namespace': namespace, 'auth': base_client._auth, }), })) proxy_client = ProxyClient.get(base_client._api_url, version=base_client._version, namespace=namespace, auth=base_client._auth) proxy_client.schema() model = proxy_client._model_gen(resource_name)
version = base_client._version paths = filter(None, schema_uri.replace( base_client._api_path, '').split('/')) # strip <id> or ``schema`` part and extract resource_name paths.pop() resource_name = paths.pop() if version in paths: paths.remove(version) namespace = '/'.join(paths) logger.debug(logf({ 'message': 'Need namespace schema.', 'attribute': name, 'resource_uri': self._response[name], 'client_key': ProxyClient.build_client_key(base_client._api_url, **{ 'version': base_client._version, 'namespace': namespace, 'auth': base_client._auth, }), })) proxy_client = ProxyClient.get(base_client._api_url, version=base_client._version, namespace=namespace, auth=base_client._auth) proxy_client.schema() model = proxy_client._model_gen(resource_name) # set manager alias if name is not resource_name:
class Response(client.Response): def __init__(self, model, response=None, url=None, **kwargs): # implement proxy mixin model_name = model._model_name.lower() if model_name in ProxyClient._proxies: proxy = ProxyClient._proxies[model_name].__class__ extend(self, proxy, proxy.__dict__.copy()) self.__init_proxy__() super(Response, self).__init__(model, response, url, **kwargs) # the magic dir(self) def __repr__(self): if hasattr(self, 'resource_uri'): return self.resource_uri return '<%s: None>' % self.model._model_name.title() def __getattr__(self, name): """ Overrides to support api namespace and to_one class diversity. """ try: if name not in self._response: raise AttributeError(name) elif 'related_type' not in self._schema['fields'][name]: return self.__getitem__(name) except AttributeError, e: if name in PK_ID: return get_pk(self) return getattr(self.model, name) # resolves foreign key references in another api namespace # expects to be called with detail url like /api/v1/<resource>/<id>|schema/ # # CAVEAT: resource_uri of referred resource has to have the same version base_client = self.model._base_client if name in self._schema['fields']: schema = self._schema['fields'][name] if ('related_type' in schema and schema['related_type'] in ( 'to_one', 'to_many', )): if schema.get('schema'): schema_uri = schema.get('schema') else: try: schema_uri = self._response[name] schema_uri = schema_uri[0] if (isinstance( schema_uri, list)) else schema_uri schema_uri = schema_uri['resource_uri'] if (isinstance( schema_uri, dict)) else schema_uri logger.debug( logf({ 'message': 'Trying to guess schema info from ' 'schema_uri.', 'schema_uri': schema_uri, })) except Exception, e: raise exceptions.ProxyException( _('Couldn\'t identify related ' 'field schema (%s).') % name)