Module couchdb3.utils
Expand source code
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import base64
from collections.abc import Generator
from enum import Enum
import mimetypes
import re
import requests
from typing import Any, Dict, Optional, Set, Type
from urllib import parse
from urllib3.util import Url, parse_url
from . import exceptions
__all__ = [
"basic_auth",
"build_query",
"build_url",
"user_name_to_id",
"validate_auth_method",
"validate_db_name",
"validate_proxy",
"validate_user_id",
"check_response",
"extract_url_data",
"partitioned_db_resource_parser",
"COUCHDB_USERS_DB_NAME",
"COUCHDB_REPLICATOR_DB_NAME",
"COUCHDB_GLOBAL_CHANGES_DB_NAME",
"COUCH_DB_RESERVED_DB_NAMES",
"DEFAULT_AUTH_METHOD",
"DEFAULT_TIMEOUT",
"MimeTypeEnum",
"PATTERN_DB_NAME",
"PATTERN_USER_ID",
"VALID_AUTH_METHODS",
"VALID_SCHEMES",
]
COUCHDB_USERS_DB_NAME: str = "_users"
"""Reserved CouchDB users database name."""
COUCHDB_REPLICATOR_DB_NAME: str = "_replicator"
"""Reserved CouchDB replicator database name."""
COUCHDB_GLOBAL_CHANGES_DB_NAME: str = "_global_changes"
"""Reserved CouchDB global changes database name."""
COUCH_DB_RESERVED_DB_NAMES: Set[str] = {
COUCHDB_USERS_DB_NAME,
COUCHDB_REPLICATOR_DB_NAME,
COUCHDB_GLOBAL_CHANGES_DB_NAME
}
"""Reserved CouchDB database names."""
DEFAULT_AUTH_METHOD: str = "cookie"
"""The default authentication method - values to `\"cookie\"`."""
DEFAULT_TIMEOUT: int = 300
"""The default timeout set in requests - values to `300`."""
MimeTypeEnum: Type[Enum] = Enum(
'MimeTypeEnum',
{'mime_type_' + k.removeprefix('.'): v for k, v in mimetypes.types_map.items()}
)
"""An Enum containing all existing mime types."""
PATTERN_DB_NAME: re.Pattern = re.compile(r"^[a-z][a-z0-9_$()+/-]*$")
"""The pattern for valid database names."""
PATTERN_USER_ID: re.Pattern = re.compile(r"^org\.couchdb\.user:.*")
"""The pattern for valid user IDs."""
VALID_AUTH_METHODS: Set[str] = {"basic", "cookie"}
"""The valid auth method arguments. Possible values are `\"basic\"` or `\"cookie\"`."""
VALID_SCHEMES: Set[str] = {"http", "https", "socks5"}
"""The valid TCP schemes. Possible values are `\"http\"` or `\"https\"` or `\"socks5\"`."""
def _handler(x: Any) -> str:
if isinstance(x, (Generator, map, list, set, tuple)):
return "[%s]" % ",".join(f"\"{_handler(_)}\"" for _ in x)
elif isinstance(x, dict):
return str({key: _handler(val) for key, val in x.items()})
elif isinstance(x, bool):
return str(x).lower()
return str(x)
def basic_auth(
user: str,
password: str
) -> str:
"""
Create basic authentication headers value.
Parameters
----------
user : str
A CouchDB user name.
password : str
A corresponding CouchDB user password.
Returns
-------
str : The credentials concatenated with a colon and base64 encoded.
"""
return base64.b64encode(f"{user}:{password}".encode()).decode()
def build_query(
**kwargs,
) -> Optional[str]:
"""
Parameters
----------
kwargs
Arbitrary keyword-args to be passed as query-params in a URL.
Returns
-------
str : A string containing the keyword-args encoded as URL query-params.
"""
return parse.urlencode({key: _handler(val) for key, val in kwargs.items() if val is not None})
def build_url(
*,
scheme: str,
host: str,
path: str = None,
port: int = None,
**kwargs,
) -> Url:
"""
Build a URL using the provided scheme, host, path & kwargs.
Parameters
----------
scheme : str
The URL scheme (e.g `http`).
host : str
The URL host (e.g. `example.com`).
path : str
The URL path (e.g. `/api/data`). Default `None`.
port : int
The port to connect to (e.g. `5984`). Default `None`.
kwargs
Arbitrary keyword-args to be passed as query-params in a URL.
Returns
-------
Url : An instance of `Url`.
"""
return Url(
scheme=scheme,
host=host,
port=port,
path=path,
query=build_query(**kwargs),
)
def validate_db_name(name: str) -> bool:
"""
Checks a name for CouchDB name-compliance.
Parameters
----------
name : str
A prospective database name.
Returns
-------
bool : `True` if the provided name is CouchDB compliant.
"""
return name in COUCH_DB_RESERVED_DB_NAMES or bool(PATTERN_DB_NAME.fullmatch(name))
def validate_auth_method(auth_method: str) -> bool:
"""
Checks if the provided authentication method is valid.
Parameters
----------
auth_method : str
Returns
-------
bool: `True` if `auth_method` is in `VALID_AUTH_METHODS`.
"""
return auth_method in VALID_AUTH_METHODS
def validate_proxy(proxy: str) -> bool:
"""
Check a proxy scheme for CouchDB proxy-scheme-compliance
Parameters
----------
proxy : str
A prospective proxy.
Returns
-------
bool : `True` if the provided proxy is CouchDB compliant.
"""
return parse_url(proxy).scheme in VALID_SCHEMES
def validate_user_id(user_id: str) -> bool:
"""
Checks a user ID for CouchDB user-id-compliance.
Parameters
----------
user_id : str
A prospective user ID.
Returns
-------
bool : `True` if the provided user ID is CouchDB compliant.
"""
return bool(PATTERN_USER_ID.fullmatch(user_id))
def user_name_to_id(name: str) -> str:
"""
Convert a name into a valid CouchDB user ID.
Parameters
----------
name : str
A user name.
Returns
-------
str : A valid CouchDB ID, i.e. of the form `org.couchdb.user:{name}`.
"""
return f"org.couchdb.user:{name}"
def check_response(response: requests.Response) -> None:
"""
Check if a request yields a successful response.
Parameters
----------
response : requests.Response
A `requests.Response` object.
Returns
-------
None
Raises
------
One of the following exceptions:
- couchdb3.error.CouchDBError
- ConnectionError
- TimeoutError
- requests.exceptions.ConnectionError
- requests.exceptions.HTTPError
"""
try:
response.raise_for_status()
except (
ConnectionError,
TimeoutError,
requests.exceptions.ConnectionError,
requests.exceptions.HTTPError,
) as err:
if response.status_code in exceptions.STATUS_CODE_ERROR_MAPPING:
_ = exceptions.STATUS_CODE_ERROR_MAPPING[response.status_code]
if _:
raise _(response.text)
else:
return None
raise err
def extract_url_data(url: str) -> Dict:
"""
Extract scheme, credentials, host, port & path from a URL.
Parameters
----------
url : str
A URL string.
Returns
-------
Dict : A dictionary containing with the following items.
- scheme
- user
- password
- host
- port
- path
"""
if not any(url.startswith(_) for _ in VALID_SCHEMES):
url = f"http://{url}"
parsed = parse_url(url)
return {
"scheme": parsed.scheme,
"user": parsed.auth.split(":")[0] if hasattr(parsed.auth, "split") else None,
"password": parsed.auth.split(":")[1] if hasattr(parsed.auth, "split") else None,
"host": parsed.host,
"port": parsed.port,
"path": parsed.path
}
def partitioned_db_resource_parser(
resource: str = None,
partition: str = None,
) -> Optional[str]:
"""
Build resource path with optional partition ID.
Parameters
----------
resource : str
The resource to fetch (relative to the host). Default `None`.
partition: str
An optional partition ID. Only valid for partitioned databases. (Default `None`.)
Returns
----------
The (relative) path of the resource.
"""
return f"_partition/{partition}/{resource}" if partition else resource
Global variables
var COUCHDB_GLOBAL_CHANGES_DB_NAME : str
-
Reserved CouchDB global changes database name.
var COUCHDB_REPLICATOR_DB_NAME : str
-
Reserved CouchDB replicator database name.
var COUCHDB_USERS_DB_NAME : str
-
Reserved CouchDB users database name.
var COUCH_DB_RESERVED_DB_NAMES : Set[str]
-
Reserved CouchDB database names.
var DEFAULT_AUTH_METHOD : str
-
The default authentication method - values to
"cookie"
. var DEFAULT_TIMEOUT : int
-
The default timeout set in requests - values to
300
. var PATTERN_DB_NAME : re.Pattern
-
The pattern for valid database names.
var PATTERN_USER_ID : re.Pattern
-
The pattern for valid user IDs.
var VALID_AUTH_METHODS : Set[str]
-
The valid auth method arguments. Possible values are
"basic"
or"cookie"
. var VALID_SCHEMES : Set[str]
-
The valid TCP schemes. Possible values are
"http"
or"https"
or"socks5"
.
Functions
def basic_auth(user: str, password: str) ‑> str
-
Create basic authentication headers value.
Parameters
user
:str
- A CouchDB user name.
password
:str
- A corresponding CouchDB user password.
Returns
str : The credentials concatenated with a colon and base64 encoded.
Expand source code
def basic_auth( user: str, password: str ) -> str: """ Create basic authentication headers value. Parameters ---------- user : str A CouchDB user name. password : str A corresponding CouchDB user password. Returns ------- str : The credentials concatenated with a colon and base64 encoded. """ return base64.b64encode(f"{user}:{password}".encode()).decode()
def build_query(**kwargs) ‑> Optional[str]
-
Parameters
kwargs
- Arbitrary keyword-args to be passed as query-params in a URL.
Returns
str : A string containing the keyword-args encoded as URL query-params.
Expand source code
def build_query( **kwargs, ) -> Optional[str]: """ Parameters ---------- kwargs Arbitrary keyword-args to be passed as query-params in a URL. Returns ------- str : A string containing the keyword-args encoded as URL query-params. """ return parse.urlencode({key: _handler(val) for key, val in kwargs.items() if val is not None})
def build_url(*, scheme: str, host: str, path: str = None, port: int = None, **kwargs) ‑> urllib3.util.url.Url
-
Build a URL using the provided scheme, host, path & kwargs.
Parameters
scheme
:str
- The URL scheme (e.g
http
). host
:str
- The URL host (e.g.
example.com
). path
:str
- The URL path (e.g.
/api/data
). DefaultNone
. port
:int
- The port to connect to (e.g.
5984
). DefaultNone
. kwargs
- Arbitrary keyword-args to be passed as query-params in a URL.
Returns
Url : An instance of
Url
.Expand source code
def build_url( *, scheme: str, host: str, path: str = None, port: int = None, **kwargs, ) -> Url: """ Build a URL using the provided scheme, host, path & kwargs. Parameters ---------- scheme : str The URL scheme (e.g `http`). host : str The URL host (e.g. `example.com`). path : str The URL path (e.g. `/api/data`). Default `None`. port : int The port to connect to (e.g. `5984`). Default `None`. kwargs Arbitrary keyword-args to be passed as query-params in a URL. Returns ------- Url : An instance of `Url`. """ return Url( scheme=scheme, host=host, port=port, path=path, query=build_query(**kwargs), )
def check_response(response: requests.models.Response) ‑> None
-
Check if a request yields a successful response.
Parameters
response
:requests.Response
- A
requests.Response
object.
Returns
None
Raises
One
ofthe following exceptions:
- couchdb3.error.CouchDBError
- ConnectionError
- TimeoutError
- requests.exceptions.ConnectionError
- requests.exceptions.HTTPError
Expand source code
def check_response(response: requests.Response) -> None: """ Check if a request yields a successful response. Parameters ---------- response : requests.Response A `requests.Response` object. Returns ------- None Raises ------ One of the following exceptions: - couchdb3.error.CouchDBError - ConnectionError - TimeoutError - requests.exceptions.ConnectionError - requests.exceptions.HTTPError """ try: response.raise_for_status() except ( ConnectionError, TimeoutError, requests.exceptions.ConnectionError, requests.exceptions.HTTPError, ) as err: if response.status_code in exceptions.STATUS_CODE_ERROR_MAPPING: _ = exceptions.STATUS_CODE_ERROR_MAPPING[response.status_code] if _: raise _(response.text) else: return None raise err
def extract_url_data(url: str) ‑> Dict
-
Extract scheme, credentials, host, port & path from a URL.
Parameters
url
:str
- A URL string.
Returns
Dict : A dictionary containing with the following items.
- scheme
- user
- password
- host
- port
- path
Expand source code
def extract_url_data(url: str) -> Dict: """ Extract scheme, credentials, host, port & path from a URL. Parameters ---------- url : str A URL string. Returns ------- Dict : A dictionary containing with the following items. - scheme - user - password - host - port - path """ if not any(url.startswith(_) for _ in VALID_SCHEMES): url = f"http://{url}" parsed = parse_url(url) return { "scheme": parsed.scheme, "user": parsed.auth.split(":")[0] if hasattr(parsed.auth, "split") else None, "password": parsed.auth.split(":")[1] if hasattr(parsed.auth, "split") else None, "host": parsed.host, "port": parsed.port, "path": parsed.path }
def partitioned_db_resource_parser(resource: str = None, partition: str = None) ‑> Optional[str]
-
Build resource path with optional partition ID.
Parameters
resource
:str
- The resource to fetch (relative to the host). Default
None
. partition
:str
- An optional partition ID. Only valid for partitioned databases. (Default
None
.)
Returns
The (relative) path of the resource.
Expand source code
def partitioned_db_resource_parser( resource: str = None, partition: str = None, ) -> Optional[str]: """ Build resource path with optional partition ID. Parameters ---------- resource : str The resource to fetch (relative to the host). Default `None`. partition: str An optional partition ID. Only valid for partitioned databases. (Default `None`.) Returns ---------- The (relative) path of the resource. """ return f"_partition/{partition}/{resource}" if partition else resource
def user_name_to_id(name: str) ‑> str
-
Convert a name into a valid CouchDB user ID.
Parameters
name
:str
- A user name.
Returns
str : A valid CouchDB ID, i.e. of the form
org.couchdb.user:{name}
.Expand source code
def user_name_to_id(name: str) -> str: """ Convert a name into a valid CouchDB user ID. Parameters ---------- name : str A user name. Returns ------- str : A valid CouchDB ID, i.e. of the form `org.couchdb.user:{name}`. """ return f"org.couchdb.user:{name}"
def validate_auth_method(auth_method: str) ‑> bool
-
Checks if the provided authentication method is valid.
Parameters
auth_method
:str
Returns
bool:
True
ifauth_method
is inVALID_AUTH_METHODS
.Expand source code
def validate_auth_method(auth_method: str) -> bool: """ Checks if the provided authentication method is valid. Parameters ---------- auth_method : str Returns ------- bool: `True` if `auth_method` is in `VALID_AUTH_METHODS`. """ return auth_method in VALID_AUTH_METHODS
def validate_db_name(name: str) ‑> bool
-
Checks a name for CouchDB name-compliance.
Parameters
name
:str
- A prospective database name.
Returns
bool :
True
if the provided name is CouchDB compliant.Expand source code
def validate_db_name(name: str) -> bool: """ Checks a name for CouchDB name-compliance. Parameters ---------- name : str A prospective database name. Returns ------- bool : `True` if the provided name is CouchDB compliant. """ return name in COUCH_DB_RESERVED_DB_NAMES or bool(PATTERN_DB_NAME.fullmatch(name))
def validate_proxy(proxy: str) ‑> bool
-
Check a proxy scheme for CouchDB proxy-scheme-compliance
Parameters
proxy
:str
- A prospective proxy.
Returns
bool :
True
if the provided proxy is CouchDB compliant.Expand source code
def validate_proxy(proxy: str) -> bool: """ Check a proxy scheme for CouchDB proxy-scheme-compliance Parameters ---------- proxy : str A prospective proxy. Returns ------- bool : `True` if the provided proxy is CouchDB compliant. """ return parse_url(proxy).scheme in VALID_SCHEMES
def validate_user_id(user_id: str) ‑> bool
-
Checks a user ID for CouchDB user-id-compliance.
Parameters
user_id
:str
- A prospective user ID.
Returns
bool :
True
if the provided user ID is CouchDB compliant.Expand source code
def validate_user_id(user_id: str) -> bool: """ Checks a user ID for CouchDB user-id-compliance. Parameters ---------- user_id : str A prospective user ID. Returns ------- bool : `True` if the provided user ID is CouchDB compliant. """ return bool(PATTERN_USER_ID.fullmatch(user_id))
Classes
class MimeTypeEnum (*args, **kwds)
-
Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3
Access them by:
- attribute access:
Color.RED
- value lookup:
Color(1)
- name lookup:
Color['RED']
Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3
>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]
Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Ancestors
- enum.Enum
Class variables
var mime_type_3g2
var mime_type_3gp
var mime_type_3gpp
var mime_type_3gpp2
var mime_type_a
var mime_type_aac
var mime_type_adts
var mime_type_ai
var mime_type_aif
var mime_type_aifc
var mime_type_aiff
var mime_type_ass
var mime_type_au
var mime_type_avi
var mime_type_avif
var mime_type_bat
var mime_type_bcpio
var mime_type_bin
var mime_type_bmp
var mime_type_c
var mime_type_cdf
var mime_type_cpio
var mime_type_csh
var mime_type_css
var mime_type_csv
var mime_type_dll
var mime_type_doc
var mime_type_dot
var mime_type_dvi
var mime_type_eml
var mime_type_eps
var mime_type_etx
var mime_type_exe
var mime_type_gif
var mime_type_gtar
var mime_type_h
var mime_type_h5
var mime_type_hdf
var mime_type_heic
var mime_type_heif
var mime_type_htm
var mime_type_html
var mime_type_ico
var mime_type_ief
var mime_type_jpe
var mime_type_jpeg
var mime_type_jpg
var mime_type_js
var mime_type_json
var mime_type_ksh
var mime_type_latex
var mime_type_loas
var mime_type_m1v
var mime_type_m3u
var mime_type_m3u8
var mime_type_man
var mime_type_me
var mime_type_mht
var mime_type_mhtml
var mime_type_mif
var mime_type_mjs
var mime_type_mov
var mime_type_movie
var mime_type_mp2
var mime_type_mp3
var mime_type_mp4
var mime_type_mpa
var mime_type_mpe
var mime_type_mpeg
var mime_type_mpg
var mime_type_ms
var mime_type_n3
var mime_type_nc
var mime_type_nq
var mime_type_nt
var mime_type_nws
var mime_type_o
var mime_type_obj
var mime_type_oda
var mime_type_opus
var mime_type_p12
var mime_type_p7c
var mime_type_pbm
var mime_type_pdf
var mime_type_pfx
var mime_type_pgm
var mime_type_pl
var mime_type_png
var mime_type_pnm
var mime_type_pot
var mime_type_ppa
var mime_type_ppm
var mime_type_pps
var mime_type_ppt
var mime_type_ps
var mime_type_pwz
var mime_type_py
var mime_type_pyc
var mime_type_pyo
var mime_type_qt
var mime_type_ra
var mime_type_ram
var mime_type_ras
var mime_type_rdf
var mime_type_rgb
var mime_type_roff
var mime_type_rtx
var mime_type_sgm
var mime_type_sgml
var mime_type_sh
var mime_type_shar
var mime_type_snd
var mime_type_so
var mime_type_src
var mime_type_srt
var mime_type_sv4cpio
var mime_type_sv4crc
var mime_type_svg
var mime_type_swf
var mime_type_t
var mime_type_tar
var mime_type_tcl
var mime_type_tex
var mime_type_texi
var mime_type_texinfo
var mime_type_tif
var mime_type_tiff
var mime_type_tr
var mime_type_trig
var mime_type_tsv
var mime_type_txt
var mime_type_ustar
var mime_type_vcf
var mime_type_vtt
var mime_type_wasm
var mime_type_wav
var mime_type_webm
var mime_type_webmanifest
var mime_type_wiz
var mime_type_wsdl
var mime_type_xbm
var mime_type_xlb
var mime_type_xls
var mime_type_xml
var mime_type_xpdl
var mime_type_xpm
var mime_type_xsl
var mime_type_xwd
var mime_type_zip