Docstring update (#58)

* migrate docstrings from reST to google format

* add raises note

Also change behaviour of the `from_option` method to fallback to
disabled instead of raising exception on unknown option

* fix part of warnings for sphinx

* make identation a bit more readable

* review fixes

* add verbose description for properties to make them parsed by sphinx extenstion

* add demo sphinx generator
This commit is contained in:
2022-04-17 20:25:28 +03:00
committed by GitHub
parent 06bd29b78d
commit 4daff81d5f
203 changed files with 5246 additions and 1636 deletions

View File

@@ -38,7 +38,10 @@ class BaseView(View):
@property
def configuration(self) -> Configuration:
"""
:return: configuration instance
get configuration instance
Returns:
Configuration: configuration instance
"""
configuration: Configuration = self.request.app["configuration"]
return configuration
@@ -46,7 +49,10 @@ class BaseView(View):
@property
def database(self) -> SQLite:
"""
:return: database instance
get database instance
Returns:
SQLite: database instance
"""
database: SQLite = self.request.app["database"]
return database
@@ -54,7 +60,10 @@ class BaseView(View):
@property
def service(self) -> Watcher:
"""
:return: build status watcher instance
get status watcher instance
Returns:
Watcher: build status watcher instance
"""
watcher: Watcher = self.request.app["watcher"]
return watcher
@@ -62,7 +71,10 @@ class BaseView(View):
@property
def spawner(self) -> Spawn:
"""
:return: external process spawner instance
get process spawner instance
Returns:
Spawn: external process spawner instance
"""
spawner: Spawn = self.request.app["spawn"]
return spawner
@@ -70,7 +82,10 @@ class BaseView(View):
@property
def validator(self) -> Auth:
"""
:return: authorization service instance
get authorization instance
Returns:
Auth: authorization service instance
"""
validator: Auth = self.request.app["validator"]
return validator
@@ -79,8 +94,12 @@ class BaseView(View):
async def get_permission(cls: Type[BaseView], request: Request) -> UserAccess:
"""
retrieve user permission from the request
:param request: request object
:return: extracted permission
Args:
request(Request): request object
Returns:
UserAccess: extracted permission
"""
permission: UserAccess = getattr(cls, f"{request.method.upper()}_PERMISSION", UserAccess.Write)
return permission
@@ -88,8 +107,13 @@ class BaseView(View):
async def extract_data(self, list_keys: Optional[List[str]] = None) -> Dict[str, Any]:
"""
extract json data from either json or form data
:param list_keys: optional list of keys which must be forced to list from form data
:return: raw json object or form data converted to json
Args:
list_keys(Optional[List[str]], optional): optional list of keys which must be forced to list from form data
(Default value = None)
Returns:
Dict[str, Any]: raw json object or form data converted to json
"""
try:
json: Dict[str, Any] = await self.request.json()
@@ -100,8 +124,13 @@ class BaseView(View):
async def data_as_json(self, list_keys: List[str]) -> Dict[str, Any]:
"""
extract form data and convert it to json object
:param list_keys: list of keys which must be forced to list from form data
:return: form data converted to json. In case if a key is found multiple times it will be returned as list
Args:
list_keys(List[str]): list of keys which must be forced to list from form data
Returns:
Dict[str, Any]: form data converted to json. In case if a key is found multiple times
it will be returned as list
"""
raw = await self.request.post()
json: Dict[str, Any] = {}

View File

@@ -31,35 +31,37 @@ from ahriman.web.views.base import BaseView
class IndexView(BaseView):
"""
root view
:cvar GET_PERMISSION: get permissions of self
:cvar HEAD_PERMISSION: head permissions of self
It uses jinja2 templates for report generation, the following variables are allowed:
architecture - repository architecture, string, required
auth - authorization descriptor, required
* authenticated - alias to check if user can see the page, boolean, required
* control - HTML to insert for login control, HTML string, required
* enabled - whether authorization is enabled by configuration or not, boolean, required
* username - authenticated username if any, string, null means not authenticated
index_url - url to the repository index, string, optional
packages - sorted list of packages properties, required
* base, string
* depends, sorted list of strings
* groups, sorted list of strings
* licenses, sorted list of strings
* packages, sorted list of strings
* status, string based on enum value
* status_color, string based on enum value
* timestamp, pretty printed datetime, string
* version, string
* web_url, string
repository - repository name, string, required
service - service status properties, required
* status, string based on enum value
* status_color, string based on enum value
* timestamp, pretty printed datetime, string
version - ahriman version, string, required
* architecture - repository architecture, string, required
* auth - authorization descriptor, required
* authenticated - alias to check if user can see the page, boolean, required
* control - HTML to insert for login control, HTML string, required
* enabled - whether authorization is enabled by configuration or not, boolean, required
* username - authenticated username if any, string, null means not authenticated
* index_url - url to the repository index, string, optional
* packages - sorted list of packages properties, required
* base, string
* depends, sorted list of strings
* groups, sorted list of strings
* licenses, sorted list of strings
* packages, sorted list of strings
* status, string based on enum value
* status_color, string based on enum value
* timestamp, pretty printed datetime, string
* version, string
* web_url, string
* repository - repository name, string, required
* service - service status properties, required
* status, string based on enum value
* status_color, string based on enum value
* timestamp, pretty printed datetime, string
* version - ahriman version, string, required
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
"""
GET_PERMISSION = HEAD_PERMISSION = UserAccess.Safe
@@ -68,7 +70,9 @@ class IndexView(BaseView):
async def get(self) -> Dict[str, Any]:
"""
process get request. No parameters supported here
:return: parameters for jinja template
Returns:
Dict[str, Any]: parameters for jinja template
"""
# some magic to make it jinja-friendly
packages = [

View File

@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from aiohttp.web import HTTPBadRequest, HTTPFound, Response
from aiohttp.web import HTTPBadRequest, HTTPFound
from ahriman.models.user_access import UserAccess
from ahriman.web.views.base import BaseView
@@ -26,21 +26,26 @@ from ahriman.web.views.base import BaseView
class AddView(BaseView):
"""
add package web view
:cvar POST_PERMISSION: post permissions of self
Attributes:
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
POST_PERMISSION = UserAccess.Write
async def post(self) -> Response:
async def post(self) -> None:
"""
add new package
JSON body must be supplied, the following model is used:
{
"packages": "ahriman" # either list of packages or package name as in AUR
}
:return: redirect to main page on success
>>> {
>>> "packages": "ahriman" # either list of packages or package name as in AUR
>>> }
Raises:
HTTPBadRequest: if bad data is supplied
HTTPFound: in case of success response
"""
try:
data = await self.extract_data(["packages"])

View File

@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from aiohttp.web import HTTPBadRequest, HTTPFound, Response
from aiohttp.web import HTTPBadRequest, HTTPFound
from ahriman.models.user_access import UserAccess
from ahriman.web.views.base import BaseView
@@ -26,21 +26,26 @@ from ahriman.web.views.base import BaseView
class RemoveView(BaseView):
"""
remove package web view
:cvar POST_PERMISSION: post permissions of self
Attributes:
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
POST_PERMISSION = UserAccess.Write
async def post(self) -> Response:
async def post(self) -> None:
"""
remove existing packages
JSON body must be supplied, the following model is used:
{
"packages": "ahriman", # either list of packages or package name
}
:return: redirect to main page on success
>>> {
>>> "packages": "ahriman", # either list of packages or package name
>>> }
Raises:
HTTPBadRequest: if bad data is supplied
HTTPFound: in case of success response
"""
try:
data = await self.extract_data(["packages"])

View File

@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from aiohttp.web import HTTPBadRequest, HTTPFound, Response
from aiohttp.web import HTTPBadRequest, HTTPFound
from ahriman.models.user_access import UserAccess
from ahriman.web.views.base import BaseView
@@ -26,21 +26,26 @@ from ahriman.web.views.base import BaseView
class RequestView(BaseView):
"""
request package web view. It is actually the same as AddView, but without now
:cvar POST_PERMISSION: post permissions of self
Attributes:
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
POST_PERMISSION = UserAccess.Read
async def post(self) -> Response:
async def post(self) -> None:
"""
request to add new package
JSON body must be supplied, the following model is used:
{
"packages": "ahriman" # either list of packages or package name as in AUR
}
:return: redirect to main page on success
>>> {
>>> "packages": "ahriman" # either list of packages or package name as in AUR
>>> }
Raises:
HTTPBadRequest: if bad data is supplied
HTTPFound: in case of success response
"""
try:
data = await self.extract_data(["packages"])

View File

@@ -29,8 +29,10 @@ from ahriman.web.views.base import BaseView
class SearchView(BaseView):
"""
AUR search web view
:cvar GET_PERMISSION: get permissions of self
:cvar HEAD_PERMISSION: head permissions of self
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
"""
GET_PERMISSION = HEAD_PERMISSION = UserAccess.Read
@@ -41,7 +43,11 @@ class SearchView(BaseView):
search string (non empty) must be supplied as `for` parameter
:return: 200 with found package bases and descriptions sorted by base
Returns:
Response: 200 with found package bases and descriptions sorted by base
Raises:
HTTPNotFound: if no packages found
"""
search: List[str] = self.request.query.getall("for", default=[])
packages = AUR.multisearch(*search)

View File

@@ -27,9 +27,11 @@ from ahriman.web.views.base import BaseView
class AhrimanView(BaseView):
"""
service status web view
:cvar GET_PERMISSION: get permissions of self
:cvar HEAD_PERMISSION: head permissions of self
:cvar POST_PERMISSION: post permissions of self
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
GET_PERMISSION = HEAD_PERMISSION = UserAccess.Read
@@ -38,20 +40,25 @@ class AhrimanView(BaseView):
async def get(self) -> Response:
"""
get current service status
:return: 200 with service status object
Returns:
Response: 200 with service status object
"""
return json_response(self.service.status.view())
async def post(self) -> Response:
async def post(self) -> None:
"""
update service status
JSON body must be supplied, the following model is used:
{
"status": "unknown", # service status string, must be valid `BuildStatusEnum`
}
:return: 204 on success
>>> {
>>> "status": "unknown", # service status string, must be valid `BuildStatusEnum`
>>> }
Raises:
HTTPBadRequest: if bad data is supplied
HTTPNoContent: in case of success response
"""
try:
data = await self.extract_data()

View File

@@ -29,10 +29,12 @@ from ahriman.web.views.base import BaseView
class PackageView(BaseView):
"""
package base specific web view
:cvar DELETE_PERMISSION: delete permissions of self
:cvar GET_PERMISSION: get permissions of self
:cvar HEAD_PERMISSION: head permissions of self
:cvar POST_PERMISSION: post permissions of self
Attributes:
DELETE_PERMISSION(UserAccess): (class attribute) delete permissions of self
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
DELETE_PERMISSION = POST_PERMISSION = UserAccess.Write
@@ -41,7 +43,12 @@ class PackageView(BaseView):
async def get(self) -> Response:
"""
get current package base status
:return: 200 with package description on success
Returns:
Response: 200 with package description on success
Raises:
HTTPNotFound: if no package was found
"""
base = self.request.match_info["package"]
@@ -58,28 +65,33 @@ class PackageView(BaseView):
]
return json_response(response)
async def delete(self) -> Response:
async def delete(self) -> None:
"""
delete package base from status page
:return: 204 on success
Raises:
HTTPNoContent: on success response
"""
base = self.request.match_info["package"]
self.service.remove(base)
raise HTTPNoContent()
async def post(self) -> Response:
async def post(self) -> None:
"""
update package build status
JSON body must be supplied, the following model is used:
{
"status": "unknown", # package build status string, must be valid `BuildStatusEnum`
"package": {} # package body (use `dataclasses.asdict` to generate one), optional.
# Must be supplied in case if package base is unknown
}
:return: 204 on success
>>> {
>>> "status": "unknown", # package build status string, must be valid `BuildStatusEnum`
>>> "package": {} # package body (use `dataclasses.asdict` to generate one), optional.
>>> # Must be supplied in case if package base is unknown
>>> }
Raises:
HTTPBadRequest: if bad data is supplied
HTTPNoContent: in case of success response
"""
base = self.request.match_info["package"]
data = await self.extract_data()

View File

@@ -26,9 +26,11 @@ from ahriman.web.views.base import BaseView
class PackagesView(BaseView):
"""
global watcher view
:cvar GET_PERMISSION: get permissions of self
:cvar HEAD_PERMISSION: head permissions of self
:cvar POST_PERMISSION: post permissions of self
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
GET_PERMISSION = HEAD_PERMISSION = UserAccess.Read
@@ -37,7 +39,9 @@ class PackagesView(BaseView):
async def get(self) -> Response:
"""
get current packages status
:return: 200 with package description on success
Returns:
Response: 200 with package description on success
"""
response = [
{
@@ -47,10 +51,12 @@ class PackagesView(BaseView):
]
return json_response(response)
async def post(self) -> Response:
async def post(self) -> None:
"""
reload all packages from repository. No parameters supported here
:return: 204 on success
Raises:
HTTPNoContent: on success response
"""
self.service.load()

View File

@@ -29,8 +29,10 @@ from ahriman.web.views.base import BaseView
class StatusView(BaseView):
"""
web service status web view
:cvar GET_PERMISSION: get permissions of self
:cvar HEAD_PERMISSION: head permissions of self
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
"""
GET_PERMISSION = HEAD_PERMISSION = UserAccess.Read
@@ -38,7 +40,9 @@ class StatusView(BaseView):
async def get(self) -> Response:
"""
get current service status
:return: 200 with service status object
Returns:
Response: 200 with service status object
"""
counters = Counters.from_packages(self.service.packages)
status = InternalStatus(

View File

@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from aiohttp.web import HTTPFound, HTTPMethodNotAllowed, HTTPUnauthorized, Response
from aiohttp.web import HTTPFound, HTTPMethodNotAllowed, HTTPUnauthorized
from ahriman.core.auth.helpers import remember
from ahriman.models.user_access import UserAccess
@@ -28,20 +28,25 @@ from ahriman.web.views.base import BaseView
class LoginView(BaseView):
"""
login endpoint view
:cvar GET_PERMISSION: get permissions of self
:cvar POST_PERMISSION: post permissions of self
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
GET_PERMISSION = POST_PERMISSION = UserAccess.Safe
async def get(self) -> Response:
async def get(self) -> None:
"""
OAuth2 response handler
In case if code provided it will do a request to get user email. In case if no code provided it will redirect
to authorization url provided by OAuth client
:return: redirect to main page
Raises:
HTTPFound: on success response
HTTPMethodNotAllowed: in case if method is used, but OAuth is disabled
HTTPUnauthorized: if case of authorization error
"""
from ahriman.core.auth.oauth import OAuth
@@ -62,17 +67,20 @@ class LoginView(BaseView):
raise HTTPUnauthorized()
async def post(self) -> Response:
async def post(self) -> None:
"""
login user to service
either JSON body or form data must be supplied the following fields are required:
{
"username": "username" # username to use for login
"password": "pa55w0rd" # password to use for login
}
:return: redirect to main page
>>> {
>>> "username": "username" # username to use for login
>>> "password": "pa55w0rd" # password to use for login
>>> }
Raises:
HTTPFound: on success response
HTTPUnauthorized: if case of authorization error
"""
data = await self.extract_data()
username = data.get("username")

View File

@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from aiohttp.web import HTTPFound, Response
from aiohttp.web import HTTPFound
from ahriman.core.auth.helpers import check_authorized, forget
from ahriman.models.user_access import UserAccess
@@ -27,15 +27,19 @@ from ahriman.web.views.base import BaseView
class LogoutView(BaseView):
"""
logout endpoint view
:cvar POST_PERMISSION: post permissions of self
Attributes:
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
POST_PERMISSION = UserAccess.Safe
async def post(self) -> Response:
async def post(self) -> None:
"""
logout user from the service. No parameters supported here
:return: redirect to main page
Raises:
HTTPFound: on success response
"""
await check_authorized(self.request)
await forget(self.request, HTTPFound("/"))