Skip to content

Commit 5f110d6

Browse files
committed
refactor: improve documentation and formatting
1 parent b85b7c3 commit 5f110d6

1 file changed

Lines changed: 52 additions & 51 deletions

File tree

kanboard.py

Lines changed: 52 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from urllib import request as http
3030

3131

32-
DEFAULT_AUTH_HEADER = 'Authorization'
32+
DEFAULT_AUTH_HEADER = "Authorization"
3333
ASYNC_FUNCNAME_MARKER = "_async"
3434

3535

@@ -39,43 +39,46 @@ class ClientError(Exception):
3939

4040
class Client:
4141
"""
42-
Kanboard API client
42+
Kanboard API client for interacting with the Kanboard JSON-RPC API.
4343
44-
Example:
44+
This client provides both synchronous and asynchronous access to all Kanboard API methods.
45+
Methods are dynamically resolved based on the Kanboard API method names, using snake_case for Python calls.
4546
47+
Example usage:
4648
from kanboard import Client
4749
4850
kb = Client(url="http://localhost/jsonrpc.php",
4951
username="jsonrpc",
5052
password="your_api_token")
5153
5254
project_id = kb.create_project(name="My project")
53-
5455
"""
5556

56-
def __init__(self,
57-
url: str,
58-
username: str,
59-
password: str,
60-
auth_header: str = DEFAULT_AUTH_HEADER,
61-
cafile: Optional[str] = None,
62-
insecure: bool = False,
63-
ignore_hostname_verification: bool = False,
64-
user_agent: str = 'Kanboard Python API Client',
65-
loop: Optional[asyncio.AbstractEventLoop] = None):
57+
def __init__(
58+
self,
59+
url: str,
60+
username: str,
61+
password: str,
62+
auth_header: str = DEFAULT_AUTH_HEADER,
63+
cafile: Optional[str] = None,
64+
insecure: bool = False,
65+
ignore_hostname_verification: bool = False,
66+
user_agent: str = "Kanboard Python API Client",
67+
loop: Optional[asyncio.AbstractEventLoop] = None,
68+
):
6669
"""
67-
Constructor
70+
Initialize a new Kanboard API client instance.
6871
6972
Args:
70-
url: API url endpoint
71-
username: API username or real username
72-
password: API token or user password
73-
auth_header: API HTTP header
74-
cafile: Path to a custom CA certificate
75-
insecure: Ignore SSL certificate errors and ignore hostname mismatches
76-
ignore_hostname_verification: Ignore SSL certificate hostname verification
77-
user_agent: Use a personalized user agent
78-
loop: An asyncio event loop. Default: asyncio.get_event_loop()
73+
url (str): The Kanboard JSON-RPC API endpoint URL (e.g., 'http://localhost/jsonrpc.php').
74+
username (str): Kanboard API username or real username.
75+
password (str): Kanboard API token or user password.
76+
auth_header (str, optional): HTTP header for authentication. Defaults to 'Authorization'.
77+
cafile (Optional[str], optional): Path to a custom CA certificate file. Defaults to None.
78+
insecure (bool, optional): If True, ignore SSL certificate errors and hostname mismatches. Defaults to False.
79+
ignore_hostname_verification (bool, optional): If True, skip SSL certificate hostname verification. Defaults to False.
80+
user_agent (str, optional): Custom User-Agent string for HTTP requests. Defaults to 'Kanboard Python API Client'.
81+
loop (Optional[asyncio.AbstractEventLoop], optional): Asyncio event loop to use. If None, uses the current event loop or creates a new one.
7982
"""
8083
self._url = url
8184
self._username = username
@@ -94,16 +97,21 @@ def __init__(self,
9497

9598
def __getattr__(self, name: str):
9699
if self.is_async_method_name(name):
100+
97101
async def function(*args, **kwargs):
98102
return await self._event_loop.run_in_executor(
99103
None,
100104
functools.partial(
101-
self.execute,
102-
method=self._to_camel_case(self.get_funcname_from_async_name(name)), **kwargs))
105+
self.execute, method=self._to_camel_case(self.get_funcname_from_async_name(name)), **kwargs
106+
),
107+
)
108+
103109
return function
104110
else:
111+
105112
def function(*args, **kwargs):
106113
return self.execute(method=self._to_camel_case(name), **kwargs)
114+
107115
return function
108116

109117
@staticmethod
@@ -112,31 +120,29 @@ def is_async_method_name(funcname: str) -> bool:
112120

113121
@staticmethod
114122
def get_funcname_from_async_name(funcname: str) -> str:
115-
return funcname[:len(funcname) - len(ASYNC_FUNCNAME_MARKER)]
123+
return funcname[: len(funcname) - len(ASYNC_FUNCNAME_MARKER)]
116124

117125
@staticmethod
118126
def _to_camel_case(snake_str: str) -> str:
119-
components = snake_str.split('_')
120-
return components[0] + ''.join(x.title() for x in components[1:])
127+
components = snake_str.split("_")
128+
return components[0] + "".join(x.title() for x in components[1:])
121129

122130
@staticmethod
123131
def _parse_response(response: bytes):
124132
try:
125-
body = json.loads(response.decode(errors='ignore'))
133+
body = json.loads(response.decode(errors="ignore"))
126134

127-
if 'error' in body:
128-
message = body.get('error').get('message')
135+
if "error" in body:
136+
message = body.get("error").get("message")
129137
raise ClientError(message)
130138

131-
return body.get('result')
139+
return body.get("result")
132140
except ValueError:
133141
return None
134142

135143
def _do_request(self, headers: Dict[str, str], body: Dict):
136144
try:
137-
request = http.Request(self._url,
138-
headers=headers,
139-
data=json.dumps(body).encode())
145+
request = http.Request(self._url, headers=headers, data=json.dumps(body).encode())
140146

141147
ssl_context = ssl.create_default_context(cafile=self._cafile)
142148
if self._insecure:
@@ -153,31 +159,26 @@ def _do_request(self, headers: Dict[str, str], body: Dict):
153159

154160
def execute(self, method: str, **kwargs):
155161
"""
156-
Call remote API procedure
162+
Call a remote Kanboard API procedure.
157163
158164
Args:
159-
method: Procedure name
160-
kwargs: Procedure named arguments
165+
method (str): The Kanboard API method name in camelCase (e.g., 'createProject').
166+
**kwargs: Named arguments to pass to the API method.
161167
162168
Returns:
163-
Procedure result
169+
The result returned by the Kanboard API for the requested method.
164170
165171
Raises:
166-
urllib.error.HTTPError: Any HTTP error (Python 3)
172+
ClientError: If the API returns an error or if a network/HTTP error occurs.
167173
"""
168-
payload = {
169-
'id': 1,
170-
'jsonrpc': '2.0',
171-
'method': method,
172-
'params': kwargs
173-
}
174+
payload = {"id": 1, "jsonrpc": "2.0", "method": method, "params": kwargs}
174175

175-
credentials = base64.b64encode('{}:{}'.format(self._username, self._password).encode())
176-
auth_header_prefix = 'Basic ' if self._auth_header == DEFAULT_AUTH_HEADER else ''
176+
credentials = base64.b64encode("{}:{}".format(self._username, self._password).encode())
177+
auth_header_prefix = "Basic " if self._auth_header == DEFAULT_AUTH_HEADER else ""
177178
headers = {
178179
self._auth_header: auth_header_prefix + credentials.decode(),
179-
'Content-Type': 'application/json',
180-
'User-Agent': self._user_agent,
180+
"Content-Type": "application/json",
181+
"User-Agent": self._user_agent,
181182
}
182183

183184
return self._do_request(headers, payload)

0 commit comments

Comments
 (0)