diff options
author | Victor Näslund <victor@sunet.se> | 2022-11-02 15:31:23 +0100 |
---|---|---|
committer | Victor Näslund <victor@sunet.se> | 2022-11-02 15:31:23 +0100 |
commit | 8baecf339e8061160bee519e87ffe837d1525c18 (patch) | |
tree | 22664c10f22382b1d4647b5f2e96bcea4220d879 /src/couch | |
parent | ffb26f4a81a9ca61c4105df037f7e1beb8dc5fb0 (diff) |
more freshup
Diffstat (limited to 'src/couch')
-rw-r--r-- | src/couch/__init__.py | 2 | ||||
-rw-r--r-- | src/couch/client.py | 82 | ||||
-rw-r--r-- | src/couch/feedreader.py | 8 | ||||
-rw-r--r-- | src/couch/resource.py | 60 | ||||
-rw-r--r-- | src/couch/utils.py | 6 |
5 files changed, 92 insertions, 66 deletions
diff --git a/src/couch/__init__.py b/src/couch/__init__.py index a7537bc..64e0252 100644 --- a/src/couch/__init__.py +++ b/src/couch/__init__.py @@ -8,4 +8,4 @@ __email__ = "rinat.sabitov@gmail.com" __status__ = "Development" -from couch.client import Server # noqa: F401 +from .client import Server # noqa: F401 diff --git a/src/couch/client.py b/src/couch/client.py index 52477be..96dc78a 100644 --- a/src/couch/client.py +++ b/src/couch/client.py @@ -8,10 +8,24 @@ import copy import mimetypes import warnings -from couch import utils -from couch import feedreader -from couch import exceptions as exp -from couch.resource import Resource +from .utils import ( + force_bytes, + force_text, + encode_view_options, + extract_credentials, +) +from .feedreader import ( + SimpleFeedReader, + BaseFeedReader, +) + +from .exceptions import ( + Conflict, + NotFound, + FeedReaderExited, + UnexpectedError, +) +from .resource import Resource DEFAULT_BASE_URL = os.environ.get('COUCHDB_URL', 'http://localhost:5984/') @@ -25,16 +39,16 @@ def _id_to_path(_id: str) -> str: def _listen_feed(object, node, feed_reader, **kwargs): if not callable(feed_reader): - raise exp.UnexpectedError("feed_reader must be callable or class") + raise UnexpectedError("feed_reader must be callable or class") - if isinstance(feed_reader, feedreader.BaseFeedReader): + if isinstance(feed_reader, BaseFeedReader): reader = feed_reader(object) else: - reader = feedreader.SimpleFeedReader()(object, feed_reader) + reader = SimpleFeedReader()(object, feed_reader) # Possible options: "continuous", "longpoll" kwargs.setdefault("feed", "continuous") - data = utils.force_bytes(json.dumps(kwargs.pop('data', {}))) + data = force_bytes(json.dumps(kwargs.pop('data', {}))) (resp, result) = object.resource(node).post( params=kwargs, data=data, stream=True) @@ -44,8 +58,8 @@ def _listen_feed(object, node, feed_reader, **kwargs): if not line: reader.on_heartbeat() else: - reader.on_message(json.loads(utils.force_text(line))) - except exp.FeedReaderExited: + reader.on_message(json.loads(force_text(line))) + except FeedReaderExited: reader.on_close() @@ -100,7 +114,7 @@ class Server(object): def __init__(self, base_url=DEFAULT_BASE_URL, full_commit=True, authmethod="basic", verify=False): - self.base_url, credentials = utils.extract_credentials(base_url) + self.base_url, credentials = extract_credentials(base_url) self.resource = Resource(self.base_url, full_commit, credentials=credentials, authmethod=authmethod, @@ -112,7 +126,7 @@ class Server(object): def __contains__(self, name): try: self.resource.head(name) - except exp.NotFound: + except NotFound: return False else: return True @@ -158,7 +172,7 @@ class Server(object): """ (r, result) = self.resource.head(name) if r.status_code == 404: - raise exp.NotFound("Database '{0}' does not exists".format(name)) + raise NotFound("Database '{0}' does not exists".format(name)) db = Database(self.resource(name), name) return db @@ -206,7 +220,7 @@ class Server(object): data = {'source': source, 'target': target} data.update(kwargs) - data = utils.force_bytes(json.dumps(data)) + data = force_bytes(json.dumps(data)) (resp, result) = self.resource.post('_replicate', data=data) return result @@ -244,7 +258,7 @@ class Database(object): try: (resp, result) = self.resource.head(_id_to_path(doc_id)) return resp.status_code < 206 - except exp.NotFound: + except NotFound: return False def config(self): @@ -308,14 +322,14 @@ class Database(object): if "_deleted" not in doc: doc["_deleted"] = True - data = utils.force_bytes(json.dumps({"docs": _docs})) + data = force_bytes(json.dumps({"docs": _docs})) params = {"all_or_nothing": "true" if transaction else "false"} (resp, results) = self.resource.post( "_bulk_docs", data=data, params=params) for result, doc in zip(results, _docs): if "error" in result: - raise exp.Conflict("one or more docs are not saved") + raise Conflict("one or more docs are not saved") return results @@ -370,7 +384,7 @@ class Database(object): else: params = {} - data = utils.force_bytes(json.dumps(_doc)) + data = force_bytes(json.dumps(_doc)) print("gg1", flush=True) print(data, flush=True) @@ -390,7 +404,7 @@ class Database(object): print("vv2", flush=True) if resp.status_code == 409: - raise exp.Conflict(result['reason']) + raise Conflict(result['reason']) if "rev" in result and result["rev"] is not None: _doc["_rev"] = result["rev"] @@ -420,7 +434,7 @@ class Database(object): if "_id" not in doc: doc["_id"] = uuid.uuid4().hex - data = utils.force_bytes(json.dumps({"docs": _docs})) + data = orce_bytes(json.dumps({"docs": _docs})) params = {"all_or_nothing": "true" if transaction else "false"} (resp, results) = self.resource.post("_bulk_docs", data=data, @@ -456,9 +470,9 @@ class Database(object): if "keys" in params: data = {"keys": params.pop("keys")} - data = utils.force_bytes(json.dumps(data)) + data = force_bytes(json.dumps(data)) - params = utils.encode_view_options(params) + params = encode_view_options(params) if data: (resp, result) = self.resource.post( "_all_docs", params=params, data=data) @@ -538,7 +552,7 @@ class Database(object): resource = self.resource(doc_id) (resp, result) = resource.get(params=params) if resp.status_code == 404: - raise exp.NotFound("Document id `{0}` not found".format(doc_id)) + raise NotFound("Document id `{0}` not found".format(doc_id)) for rev in result['_revs_info']: if status and rev['status'] == status: @@ -566,10 +580,10 @@ class Database(object): (resp, result) = resource.delete( filename, params={'rev': _doc['_rev']}) if resp.status_code == 404: - raise exp.NotFound("filename {0} not found".format(filename)) + raise NotFound("filename {0} not found".format(filename)) if resp.status_code > 205: - raise exp.Conflict(result['reason']) + raise Conflict(result['reason']) _doc['_rev'] = result['rev'] try: @@ -645,7 +659,7 @@ class Database(object): if resp.status_code < 206: return self.get(doc["_id"]) - raise exp.Conflict(result['reason']) + raise Conflict(result['reason']) def one(self, name, flat=None, wrapper=None, **kwargs): """ @@ -665,16 +679,16 @@ class Database(object): params = {"limit": 1} params.update(kwargs) - path = utils._path_from_name(name, '_view') + path = _path_from_name(name, '_view') data = None if "keys" in params: data = {"keys": params.pop('keys')} if data: - data = utils.force_bytes(json.dumps(data)) + data = force_bytes(json.dumps(data)) - params = utils.encode_view_options(params) + params = encode_view_options(params) result = list(self._query(self.resource(*path), wrapper=wrapper, flat=flat, params=params, data=data)) @@ -716,16 +730,16 @@ class Database(object): :returns: generator object """ params = copy.copy(kwargs) - path = utils._path_from_name(name, '_view') + path = _path_from_name(name, '_view') data = None if "keys" in params: data = {"keys": params.pop('keys')} if data: - data = utils.force_bytes(json.dumps(data)) + data = force_bytes(json.dumps(data)) - params = utils.encode_view_options(params) + params = encode_view_options(params) result = self._query(self.resource(*path), wrapper=wrapper, flat=flat, params=params, data=data) @@ -768,7 +782,7 @@ class Database(object): """ path = '_find' - data = utils.force_bytes(json.dumps(selector)) + data = force_bytes(json.dumps(selector)) (resp, result) = self.resource.post(path, data=data, params=kwargs) @@ -780,7 +794,7 @@ class Database(object): def index(self, index_doc, **kwargs): path = '_index' - data = utils.force_bytes(json.dumps(index_doc)) + data = force_bytes(json.dumps(index_doc)) (resp, result) = self.resource.post(path, data=data, params=kwargs) diff --git a/src/couch/feedreader.py b/src/couch/feedreader.py index 98401ab..aac51d3 100644 --- a/src/couch/feedreader.py +++ b/src/couch/feedreader.py @@ -11,7 +11,7 @@ class BaseFeedReader: self.db = db return self - def on_message(self, message): + def on_message(self, message: str) -> None: """ Callback method that is called when change message is received from couchdb. @@ -22,14 +22,14 @@ class BaseFeedReader: raise NotImplementedError() - def on_close(self): + def on_close(self) -> None: """ Callback method that is received when connection is closed with a server. By default, does nothing. """ pass - def on_heartbeat(self): + def on_heartbeat(self) -> None: """ Callback method invoked when a hearbeat (empty line) is received from the _changes stream. Override this to purge the reader's internal @@ -48,5 +48,5 @@ class SimpleFeedReader(BaseFeedReader): self.callback = callback return super(SimpleFeedReader, self).__call__(db) - def on_message(self, message) -> None: + def on_message(self, message: str) -> None: self.callback(message, db=self.db) diff --git a/src/couch/resource.py b/src/couch/resource.py index 364bff4..f110c8d 100644 --- a/src/couch/resource.py +++ b/src/couch/resource.py @@ -1,17 +1,25 @@ # -*- coding: utf-8 -*- # Based on py-couchdb (https://github.com/histrio/py-couchdb) - +from __future__ import annotations from __future__ import unicode_literals -from typing import Union, Tuple +from typing import Union, Tuple, Dict, Any import json import requests - - -from couch import utils -from couch import exceptions +from .utils import ( + urljoin, + as_json, + force_bytes, +) +from .exceptions import ( + GenericError, + NotFound, + BadRequest, + Conflict, + AuthenticationFailed, +) class Resource: @@ -40,12 +48,11 @@ class Resource: if method == "session": data = {"name": credentials[0], "password": credentials[1]} - data = utils.force_bytes(json.dumps(data)) - post_url = utils.urljoin(self.base_url, "_session") - r = self.session.post(post_url, data=data) - if r.status_code != 200: - raise exceptions.AuthenticationFailed() + post_url = urljoin(self.base_url, "_session") + r = self.session.post(post_url, data=force_bytes(json.dumps(data))) + if r and r.status_code != 200: + raise AuthenticationFailed() elif method == "basic": self.session.auth = credentials @@ -53,8 +60,8 @@ class Resource: else: raise RuntimeError("Invalid authentication method") - def __call__(self, *path: str): - base_url = utils.urljoin(self.base_url, *path) + def __call__(self, *path: str) -> Resource: + base_url = urljoin(self.base_url, *path) return self.__class__(base_url, session=self.session) def _check_result(self, response, result) -> None: @@ -68,17 +75,18 @@ class Resource: # This is here because couchdb can return http 201 # but containing a list of conflict errors if error == 'conflict' or error == "file_exists": - raise exceptions.Conflict(reason or "Conflict") + raise Conflict(reason or "Conflict") if response.status_code > 205: if response.status_code == 404 or error == 'not_found': - raise exceptions.NotFound(reason or 'Not found') + raise NotFound(reason or 'Not found') elif error == 'bad_request': - raise exceptions.BadRequest(reason or "Bad request") - raise exceptions.GenericError(result) + raise BadRequest(reason or "Bad request") + raise GenericError(result) - def request(self, method, path: str, params=None, data=None, - headers=None, stream=False, **kwargs): + + def request(self, method, path: Union[str, None], params=None, data=None, + headers=None, stream=False, **kwargs) -> Tuple[requests.models.Response, Union[Dict[str, Any], None]]: if headers is None: headers = {} @@ -88,7 +96,7 @@ class Resource: if path: if not isinstance(path, (list, tuple)): path = [path] - url = utils.urljoin(self.base_url, *path) + url = urljoin(self.base_url, *path) else: url = self.base_url @@ -102,7 +110,7 @@ class Resource: result = None self._check_result(response, result) else: - result = utils.as_json(response) + result = as_json(response) if result is None: return response, result @@ -115,17 +123,17 @@ class Resource: return response, result - def get(self, path: Union[str, None] = None, **kwargs): + def get(self, path: Union[str, None] = None, **kwargs: Any) -> Tuple[requests.models.Response, Union[Dict[str, Any], None]]: return self.request("GET", path, **kwargs) - def put(self, path: Union[str, None] = None, **kwargs): + def put(self, path: Union[str, None] = None, **kwargs: Any) -> Tuple[requests.models.Response, Union[Dict[str, Any], None]]: return self.request("PUT", path, **kwargs) - def post(self, path: Union[str, None] = None, **kwargs): + def post(self, path: Union[str, None] = None, **kwargs: Any) -> Tuple[requests.models.Response, Union[Dict[str, Any], None]]: return self.request("POST", path, **kwargs) - def delete(self, path: Union[str, None] = None, **kwargs): + def delete(self, path: Union[str, None] = None, **kwargs: Any) -> Tuple[requests.models.Response, Union[Dict[str, Any], None]]: return self.request("DELETE", path, **kwargs) - def head(self, path: Union[str, None] = None, **kwargs): + def head(self, path: Union[str, None] = None, **kwargs: Any) -> Tuple[requests.models.Response, Union[Dict[str, Any], None]]: return self.request("HEAD", path, **kwargs) diff --git a/src/couch/utils.py b/src/couch/utils.py index f0883a6..b3e5aa3 100644 --- a/src/couch/utils.py +++ b/src/couch/utils.py @@ -78,13 +78,17 @@ def urljoin(base: str, *path: str) -> str: return reduce(_join, path, base) # Probably bugs here -def as_json(response: requests.models.Response) -> Union[Dict[str, Any], None]: +def as_json(response: requests.models.Response) -> Union[Dict[str, Any], None, str]: if "application/json" in response.headers['content-type']: response_src = response.content.decode('utf-8') + print(response.content) if response.content != b'': ret: Dict[str, Any] = json.loads(response_src) return ret else: + print("fff") + print("fff") + print(type(response_src)) return response_src return None |