diff --git a/acacore/database/base.py b/acacore/database/base.py index dac7b02..1b9ffc7 100644 --- a/acacore/database/base.py +++ b/acacore/database/base.py @@ -42,10 +42,10 @@ def __init__( """ A wrapper class for an SQLite cursor that returns its results as dicts (or objects). - Args: - cursor: An SQLite cursor from a select transaction. - columns: A list of columns to use to convert the tuples returned by the cursor. - table: Optionally, the Table from which on which the select transaction was executed. + :param cursor: An SQLite cursor from a select transaction. + :param columns: A list of columns to use to convert the tuples returned by the cursor. + :param table: Optionally, the Table from which on which the select transaction was executed, defaults to + None. """ self.cursor: SQLiteCursor = cursor self.columns: list[Column | SelectColumn] = columns @@ -61,8 +61,7 @@ def fetchalltuples(self) -> Generator[tuple, None, None]: """ Fetch all the results from the cursor as tuples and convert the data using the given columns. - Returns: - Generator: A generator for the tuples in the cursor. + :return: A generator for the tuples in the cursor. """ return (tuple(c.from_entry(v) for c, v in zip(self.columns, vs)) for vs in self.cursor.fetchall()) @@ -70,8 +69,7 @@ def fetchonetuple(self) -> tuple | None: """ Fetch one result from the cursor as tuples and convert the data using the given columns. - Returns: - tuple: A single tuple from the cursor. + :return: A single tuple from the cursor. """ vs: tuple = self.cursor.fetchone() @@ -89,11 +87,8 @@ def fetchall(self, model: Type[M] | None = None) -> Generator[dict[str, Any] | M """ Fetch all results from the cursor and return them as dicts, with the columns' names/aliases used as keys. - Args: - model: Optionally, a pydantic.BaseModel class to use instead of a dict. - - Returns: - Generator: A generator for converted dicts (or models). + :param model: Optionally, a pydantic.BaseModel class to use instead of a dict, defaults to None. + :return: A generator for converted dicts (or models). """ select_columns: list[SelectColumn] = [SelectColumn.from_column(c) for c in self.columns] @@ -119,12 +114,9 @@ def fetchmany(self, size: int, model: Type[M] | None = None) -> Generator[dict[s """ Fetch `size` results from the cursor and return them as dicts, with the columns' names/aliases used as keys. - Args: - size: The amount of results to fetch. - model: Optionally, a pydantic.BaseModel class to use instead of a dict. - - Returns: - Generator: A generator for converted dicts (or models). + :param size: The amount of results to fetch. + :param model: Optionally, a pydantic.BaseModel class to use instead of a dict, defaults to None. + :return: A generator for converted dicts (or models). """ select_columns: list[SelectColumn] = [SelectColumn.from_column(c) for c in self.columns] @@ -153,11 +145,8 @@ def fetchone(self, model: Type[M] | None = None) -> dict[str, Any] | M | None: """ Fetch one result from the cursor and return it as a dict, with the columns' names/aliases used as keys. - Args: - model: Optionally, a pydantic.BaseModel class to use instead of a dict. - - Returns: - dict: A single dict (or model) if the cursor is not exhausted, otherwise None. + :param model: Optionally, a pydantic.BaseModel class to use instead of a dict, defaults to None. + :return: A single dict (or model) if the cursor is not exhausted, otherwise None. """ select_columns: list[SelectColumn] = [SelectColumn.from_column(c) for c in self.columns] vs: tuple = self.cursor.fetchone() @@ -180,10 +169,10 @@ def __init__( """ A wrapper class for an SQLite cursor that returns its results as model objects. - Args: - cursor: An SQLite cursor from a select transaction. - model: A model representing the objects in the cursor. - table: Optionally, the Table from which on which the select transaction was executed. + :param cursor: An SQLite cursor from a select transaction. + :param model: A model representing the objects in the cursor. + :param table: Optionally, the Table from which on which the select transaction was executed, defaults to + None. """ super().__init__(cursor, model_to_columns(model), table) self.model: Type[M] = model @@ -198,11 +187,9 @@ def fetchall(self, model: Type[M] | None = None) -> Generator[M, None, None]: """ Fetch all results from the cursor and return them as model objects. - Args: - model: Optionally, a different pydantic.BaseModel class to use instead of the one in the ModelCursor. - - Returns: - Generator: A generator for converted objects. + :param model: Optionally, a different pydantic.BaseModel class to use instead of the one in the ModelCursor, + defaults to None. + :return: A generator for converted objects. """ return super().fetchall(model or self.model) @@ -210,12 +197,10 @@ def fetchmany(self, size: int, model: Type[M] | None = None) -> Generator[dict[s """ Fetch `size` results from the cursor and return them as model objects. - Args: - size: The amount of results to fetch. - model: Optionally, a different pydantic.BaseModel class to use instead of the one in the ModelCursor. - - Returns: - Generator: A generator for converted objects. + :param size: The amount of results to fetch. + :param model: Optionally, a different pydantic.BaseModel class to use instead of the one in the ModelCursor, + defaults to None. + :return: A generator for converted objects. """ return super().fetchmany(size, model or self.model) @@ -223,11 +208,9 @@ def fetchone(self, model: Type[M] | None = None) -> M | None: """ Fetch one result from the cursor and return it as model object. - Args: - model: Optionally, a different pydantic.BaseModel class to use instead of the one in the ModelCursor. - - Returns: - object: A single object if the cursor is not exhausted, otherwise None. + :param model: Optionally, a different pydantic.BaseModel class to use instead of the one in the ModelCursor, + defaults to None. + :return: A single object if the cursor is not exhausted, otherwise None. """ return super().fetchone(model or self.model) @@ -244,11 +227,10 @@ def __init__( """ A class that holds information about a table. - Args: - connection: A FileDBBase object connected to the database the table belongs to. - name: The name of the table. - columns: The columns of the table. - indices: The indices to create in the table. + :param connection: A FileDBBase object connected to the database the table belongs to. + :param name: The name of the table. + :param columns: The columns of the table. + :param indices: The indices to create in the table, defaults to None. """ self.connection: "FileDBBase" = connection self.name: str = name @@ -269,8 +251,7 @@ def keys(self) -> list[Column]: """ The list of PRIMARY KEY columns in the table. - Returns: - A list of Column objects whose `primary_key` field is set to True. + :return: A list of Column objects whose `primary_key` field is set to True. """ return [c for c in self.columns if c.primary_key] @@ -278,11 +259,8 @@ def create_statement(self, exist_ok: bool = True) -> str: """ Generate the expression that creates the table. - Args: - exist_ok: True if existing tables with the same name should be ignored. - - Returns: - A CREATE TABLE expression. + :param exist_ok: True if existing tables with the same name should be ignored, defaults to True. + :return: A CREATE TABLE expression. """ elements: list[str] = ["create table"] @@ -317,16 +295,14 @@ def select( """ Select entries from the table. - Args: - columns: A list of columns to be selected, defaults to all the existing columns in the table. - where: A WHERE expression. - order_by: A list tuples containing one column (either as Column or string) - and a sorting direction ("ASC", or "DESC"). - limit: The number of rows to limit the results to. - parameters: Values to substitute in the SELECT expression, both in the `where` and SelectColumn statements. - - Returns: - Cursor: A Cursor object wrapping the SQLite cursor returned by the SELECT transaction. + :param columns: A list of columns to be selected, defaults to None. + :param where: A WHERE expression, defaults to None. + :param order_by: A list tuples containing one column (either as Column or string) and a sorting direction + ("ASC", or "DESC"), defaults to None. + :param limit: The number of rows to limit the results to, defaults to None. + :param parameters: Values to substitute in the SELECT expression, both in the `where` and SelectColumn + statements, defaults to None. + :return: A Cursor object wrapping the SQLite cursor returned by the SELECT transaction. """ columns = columns or self.columns parameters = parameters or [] @@ -355,11 +331,12 @@ def insert(self, entry: dict[str, Any], exist_ok: bool = False, replace: bool = """ Insert a row in the table. Existing rows with matching keys can be ignored or replaced. - Args: - entry: The row to be inserted as a dict with keys matching the names of the columns. - The values need not be converted beforehand. - exist_ok: True if existing rows with the same keys should be ignored, False otherwise - replace: True if existing rows with the same keys should be replaced, False otherwise. + :param entry: The row to be inserted as a dict with keys matching the names of the columns. + The values need not be converted beforehand. + :param exist_ok: True if existing rows with the same keys should be ignored, False otherwise, defaults to + False. + :param replace: True if existing rows with the same keys should be replaced, False otherwise, defaults to + False. """ values: list[SQLValue] = [ c.to_entry(entry[c.name]) if c.name in entry else c.default_value() for c in self.columns @@ -388,11 +365,12 @@ def insert_many( """ Insert multiple rows in the table. Existing rows with matching keys can be ignored or replaced. - Args: - entries: The rows to be inserted as a list (or iterator) of dicts with keys matching the names of - the columns. The values need not be converted beforehand. - exist_ok: True if existing rows with the same keys should be ignored, False otherwise - replace: True if existing rows with the same keys should be replaced, False otherwise. + :param entries: The rows to be inserted as a list (or iterator) of dicts with keys matching the names of the + columns. The values need not be converted beforehand. + :param exist_ok: True if existing rows with the same keys should be ignored, False otherwise, defaults to + False. + :param replace: True if existing rows with the same keys should be replaced, False otherwise, defaults to + False. """ for entry in entries: self.insert(entry, exist_ok, replace) @@ -401,18 +379,15 @@ def update(self, entry: dict[str, Any], where: dict[str, Any] | None = None): """ Update a row. - If ``where`` is provided, then the WHERE clause is computed with those, otherwise the table's keys and values - in ``entry`` are used. + If ``where`` is provided, then the WHERE clause is computed with those, otherwise the table's keys and values in + ``entry`` are used. - Raises: - OperationalError: If ``where`` is not provided and the table has no keys. - KeyError: If ``where`` is not provided and one of the table's keys is missing from ``entry``. - - Args: - entry: The values of the row to be updated as a dict with keys matching the names of the columns. - The values need not be converted beforehand. - where: Optionally, the columns and values to use in the WHERE statement. The values need not be converted - beforehand. + :param entry: The values of the row to be updated as a dict with keys matching the names of the columns. + The values need not be converted beforehand. + :param where: Optionally, the columns and values to use in the WHERE statement. The values need not be + converted beforehand, defaults to None. + :raises OperationalError: If ``where`` is not provided and the table has no keys. + :raises KeyError: If ``where`` is not provided and one of the table's keys is missing from ``entry``. """ values: list[tuple[str, SQLValue]] = [ (c.name, c.to_entry(entry[c.name])) for c in self.columns if c.name in entry @@ -444,11 +419,10 @@ def __init__( """ A class that holds information about a table using a model. - Args: - connection: A FileDBBase object connected to the database the table belongs to. - name: The name of the table. - model: The model representing the table. - indices: The indices to create in the table. + :param connection: A FileDBBase object connected to the database the table belongs to. + :param name: The name of the table. + :param model: The model representing the table. + :param indices: The indices to create in the table, defaults to None. """ super().__init__(connection, name, model_to_columns(model), indices) self.model: Type[M] = model @@ -470,16 +444,14 @@ def select( """ Select entries from the table. - Args: - model: A model with the fields to be selected, defaults to the table's model. - where: A WHERE expression. - order_by: A list tuples containing one column (either as Column or string) - and a sorting direction ("ASC", or "DESC"). - limit: The number of rows to limit the results to. - parameters: Values to substitute in the SELECT expression, both in the `where` and SelectColumn statements. - - Returns: - Cursor: A Cursor object wrapping the SQLite cursor returned by the SELECT transaction. + :param model: A model with the fields to be selected, defaults to None. + :param where: A WHERE expression, defaults to None. + :param order_by: A list tuples containing one column (either as Column or string) and a sorting direction + ("ASC", or "DESC"), defaults to None. + :param limit: The number of rows to limit the results to, defaults to None. + :param parameters: Values to substitute in the SELECT expression, both in the `where` and SelectColumn + statements, defaults to None. + :return: A Cursor object wrapping the SQLite cursor returned by the SELECT transaction. """ return ModelCursor[M]( super() @@ -499,10 +471,11 @@ def insert(self, entry: M, exist_ok: bool = False, replace: bool = False): """ Insert a row in the table. Existing rows with matching keys can be ignored or replaced. - Args: - entry: The row to be inserted as a model object with attributes matching the names of the columns. - exist_ok: True if existing rows with the same keys should be ignored, False otherwise - replace: True if existing rows with the same keys should be replaced, False otherwise. + :param entry: The row to be inserted as a model object with attributes matching the names of the columns. + :param exist_ok: True if existing rows with the same keys should be ignored, False otherwise, defaults to + False. + :param replace: True if existing rows with the same keys should be replaced, False otherwise, defaults to + False. """ super().insert(entry.model_dump(), exist_ok, replace) @@ -515,11 +488,12 @@ def insert_many( """ Insert multiple rows in the table. Existing rows with matching keys can be ignored or replaced. - Args: - entries: The rows to be inserted as a list (or iterator) of model objects with attributes matching - the names of the columns. - exist_ok: True if existing rows with the same keys should be ignored, False otherwise - replace: True if existing rows with the same keys should be replaced, False otherwise. + :param entries: The rows to be inserted as a list (or iterator) of model objects with attributes matching + the names of the columns. + :param exist_ok: True if existing rows with the same keys should be ignored, False otherwise, defaults to + False. + :param replace: True if existing rows with the same keys should be replaced, False otherwise, defaults to + False. """ for entry in entries: self.insert(entry, exist_ok, replace) @@ -528,18 +502,15 @@ def update(self, entry: M | dict[str, Any], where: dict[str, Any] | None = None) """ Update a row. - If ``where`` is provided, then the WHERE clause is computed with those, otherwise the table's keys and values - in ``entry`` are used. + If ``where`` is provided, then the WHERE clause is computed with those, otherwise the table's keys and values in + ``entry`` are used. - Raises: - OperationalError: If ``where`` is not provided and the table has no keys. - KeyError: If ``where`` is not provided and one of the table's keys is missing from ``entry``. - - Args: - entry: The row to be inserted as a model object with attributes matching the names of the columns. - Alternatively, a dict with keys matching the names of the columns. - where: Optionally, the columns and values to use in the WHERE statement. The values need not be converted - beforehand. + :param entry: The row to be inserted as a model object with attributes matching the names of the columns. + Alternatively, a dict with keys matching the names of the columns. + :param where: Optionally, the columns and values to use in the WHERE statement. The values need not be + converted beforehand, defaults to None. + :raises OperationalError: If ``where`` is not provided and the table has no keys. + :raises KeyError: If ``where`` is not provided and one of the table's keys is missing from ``entry``. """ super().update(entry if isinstance(entry, dict) else entry.model_dump(), where) @@ -550,10 +521,9 @@ def __init__(self, connection: "FileDBBase", name: str, keys: list[Column]) -> N """ A class that holds information about a key-value pairs table. - Args: - connection: A FileDBBase object connected to the database the table belongs to. - name: The name of the table. - keys: The keys of the table. + :param connection: A FileDBBase object connected to the database the table belongs to. + :param name: The name of the table. + :param keys: The keys of the table. """ self.keys: list[Column] = keys self.connection: "FileDBBase" = connection @@ -576,11 +546,8 @@ def create_statement(self, exist_ok: bool = True) -> str: """ Generate the expression that creates the table. - Args: - exist_ok: True if existing tables with the same name should be ignored. - - Returns: - A CREATE TABLE expression. + :param exist_ok: True if existing tables with the same name should be ignored, defaults to True. + :return: A CREATE TABLE expression. """ return Table(self.connection, self.name, self.columns).create_statement(exist_ok) @@ -588,7 +555,6 @@ def create(self, exist_ok: bool = True): self.connection.execute(self.create_statement(exist_ok)) def select(self) -> dict[str, Any] | None: - """Return the data in the table as a dictionary.""" data = dict(self.connection.execute(f"select KEY, VALUE from {self.name}").fetchall()) return {c.name: c.from_entry(data[c.name]) for c in self.keys} if data else None @@ -598,8 +564,7 @@ def update(self, entry: dict[str, Any]): Existing key-value pairs are replaced if the new entry contains an existing key. - Args: - entry: A dictionary with string keys. + :param entry: A dictionary with string keys. """ entry = {k.lower(): v for k, v in entry.items()} entry = {c.name: c.to_entry(entry[c.name.lower()]) if c.name in entry else c.default_value() for c in self.keys} @@ -613,10 +578,9 @@ def __init__(self, connection: "FileDBBase", name: str, model: Type[M]) -> None: """ A class that holds information about a key-value pairs table using a BaseModel for validation and parsing. - Args: - connection: A FileDBBase object connected to the database the table belongs to. - name: The name of the table. - model: The model of the table. + :param connection: A FileDBBase object connected to the database the table belongs to. + :param name: The name of the table. + :param model: The model of the table. """ self.model: Type[M] = model super().__init__(connection, name, model_to_columns(model)) @@ -625,7 +589,6 @@ def __repr__(self) -> str: return f'{self.__class__.__name__}[{self.model.__name__}]("{self.name}")' def select(self) -> M | None: - """Return the data in the table using the BaseModel object stored in the object.""" data = super().select() return self.model.model_validate(data) if data else None @@ -635,8 +598,7 @@ def update(self, entry: M): Existing key-value pairs are replaced if the new entry contains an existing key. - Args: - entry: A BaseModel object. + :param entry: A BaseModel object. """ assert issubclass(type(entry), self.model), f"{type(entry).__name__} is not a subclass of {self.model.__name__}" super().update(entry.model_dump()) @@ -659,17 +621,16 @@ def __init__( """ A subclass of Table to handle views. - Args: - connection: A FileDBBase object connected to the database the view belongs to. - name: The name of the table. - on: The table the view is based on. - columns: The columns of the view. - where: A WHERE expression for the view. - group_by: A GROUP BY expression for the view. - order_by: A list tuples containing one column (either as Column or string) - and a sorting direction ("ASC", or "DESC"). - limit: The number of rows to limit the results to. - joins: Join operations to apply to the view. + :param connection: A FileDBBase object connected to the database the view belongs to. + :param name: The name of the table. + :param on: The table the view is based on. + :param columns: The columns of the view. + :param where: A WHERE expression for the view, defaults to None. + :param group_by: A GROUP BY expression for the view, defaults to None. + :param order_by: A list tuples containing one column (either as Column or string) and a sorting direction + ("ASC", or "DESC"), defaults to None. + :param limit: The number of rows to limit the results to, defaults to None. + :param joins: Join operations to apply to the view, defaults to None. """ assert columns, "Views must have columns" super().__init__(connection, name, columns) @@ -687,11 +648,8 @@ def create_statement(self, exist_ok: bool = True) -> str: """ Generate the expression that creates the view. - Args: - exist_ok: True if existing views with the same name should be ignored. - - Returns: - A CREATE VIEW expression. + :param exist_ok: True if existing views with the same name should be ignored, defaults to True. + :return: A CREATE VIEW expression. """ on_table: str = self.on.name if isinstance(self.on, Table) else self.on elements: list[str] = ["CREATE VIEW"] @@ -749,16 +707,14 @@ def select( """ Select entries from the view. - Args: - columns: A list of columns to be selected, defaults to all the existing columns in the view. - where: A WHERE expression. - order_by: A list tuples containing one column (either as Column or string) - and a sorting direction ("ASC", or "DESC"). - limit: The number of rows to limit the results to. - parameters: Values to substitute in the SELECT expression, both in the `where` and SelectColumn statements. - - Returns: - Cursor: A Cursor object wrapping the SQLite cursor returned by the SELECT transaction. + :param columns: A list of columns to be selected, defaults to None. + :param where: A WHERE expression, defaults to None. + :param order_by: A list tuples containing one column (either as Column or string) and a sorting direction + ("ASC", or "DESC"), defaults to None. + :param limit: The number of rows to limit the results to, defaults to None. + :param parameters: Values to substitute in the SELECT expression, both in the `where` and SelectColumn + statements, defaults to None. + :return: A Cursor object wrapping the SQLite cursor returned by the SELECT transaction. """ columns = columns or [ Column( @@ -778,16 +734,18 @@ def select( def insert(self, *_args, **_kwargs): """ - Raises: - OperationalError: Insert transactions are not allowed on views. - """ # noqa: D205 + Insert function. + + :raises OperationalError: Insert transactions are not allowed on views. + """ raise OperationalError("Cannot insert into view") def insert_many(self, *_args, **_kwargs): """ - Raises: - OperationalError: Insert transactions are not allowed on views. - """ # noqa: D205 + Insert many. + + :raises OperationalError: Insert transactions are not allowed on views. + """ raise OperationalError("Cannot insert into view") @@ -808,18 +766,17 @@ def __init__( """ A subclass of Table to handle views with models. - Args: - connection: A FileDBBase object connected to the database the view belongs to. - name: The name of the table. - on: The table the view is based on. - model: A BaseModel subclass. - columns: Optionally, the columns of the view if the model is too limited. - where: A WHERE expression for the view. - group_by: A GROUP BY expression for the view. - order_by: A list tuples containing one column (either as Column or string) - and a sorting direction ("ASC", or "DESC"). - limit: The number of rows to limit the results to. - joins: Join operations to apply to the view. + :param connection: A FileDBBase object connected to the database the view belongs to. + :param name: The name of the table. + :param on: The table the view is based on. + :param model: A BaseModel subclass. + :param columns: Optionally, the columns of the view if the model is too limited, defaults to None. + :param where: A WHERE expression for the view, defaults to None. + :param group_by: A GROUP BY expression for the view, defaults to None. + :param order_by: A list tuples containing one column (either as Column or string) and a sorting direction + ("ASC", or "DESC"), defaults to None. + :param limit: The number of rows to limit the results to, defaults to None. + :param joins: Join operations to apply to the view, defaults to None. """ super().__init__( connection, @@ -876,21 +833,21 @@ def __init__( """ A wrapper class for an SQLite connection. - Args: - database: The path or URI to the database. - timeout: How many seconds the connection should wait before raising an OperationalError - when a table is locked. - detect_types: Control whether and how data types not natively supported by SQLite are looked up to be - converted to Python types. - isolation_level: The isolation_level of the connection, controlling whether - and how transactions are implicitly opened. - check_same_thread: If True (default), ProgrammingError will be raised if the database connection - is used by a thread other than the one that created it. - factory: A custom subclass of Connection to create the connection with, - if not the default Connection class. - cached_statements: The number of statements that sqlite3 should internally cache for this connection, - to avoid parsing overhead. - uri: If set to True, database is interpreted as a URI with a file path and an optional query string. + :param database: The path or URI to the database. + :param timeout: How many seconds the connection should wait before raising an OperationalError when a table + is locked, defaults to 5.0. + :param detect_types: Control whether and how data types not natively supported by SQLite are looked up to be + converted to Python types, defaults to 0. + :param isolation_level: The isolation_level of the connection, controlling whether and how transactions are + implicitly opened, defaults to "DEFERRED". + :param check_same_thread: If True (default), ProgrammingError will be raised if the database connection is + used by a thread other than the one that created it, defaults to True. + :param factory: A custom subclass of Connection to create the connection with, if not the default Connection + class, defaults to Connection. + :param cached_statements: The number of statements that sqlite3 should internally cache for this connection, + to avoid parsing overhead, defaults to 100. + :param uri: If set to True, database is interpreted as a URI with a file path and an optional query string, + defaults to False. """ super().__init__( database, @@ -942,14 +899,14 @@ def create_table( columns: Type[M] | list[Column], indices: list[Index] | None = None, ) -> Table | ModelTable[M]: - """Create a table in the database. + """ + Create a table in the database. When the `columns` argument is a subclass of BadeModel, a ModelTable object is returned. - Args: - name: The name of the table. - columns: A BaseModel subclass or the columns of the table. - indices: The indices to create in the table. + :param name: The name of the table. + :param columns: A BaseModel subclass or the columns of the table. + :param indices: The indices to create in the table, defaults to None. """ if issubclass(columns, BaseModel): return ModelTable[M](self, name, columns, model_to_indices(columns) if indices is None else indices) @@ -970,9 +927,8 @@ def create_keys_table(self, name: str, columns: Type[M] | list[Column]) -> KeysT When the `columns` argument is a subclass of BaseModel, a ModelTable object is returned. - Args: - name: The name of the table. - columns: A BaseModel subclass or the columns of the table. + :param name: The name of the table. + :param columns: A BaseModel subclass or the columns of the table. """ if issubclass(columns, BaseModel): return ModelKeysTable[M](self, name, columns) @@ -1022,21 +978,22 @@ def create_view( *, select_columns: list[Column | SelectColumn] | None = None, ) -> View | ModelView[M]: - """Create a view in the database. + """ + Create a view in the database. When the `columns` argument is a subclass of BadeModel, a ModelView object is returned. - Args: - name: The name of the table. - on: The table the view is based on. - columns: A BaseModel subclass or the columns of the view. - where: A WHERE expression for the view. - group_by: A GROUP BY expression for the view. - order_by: A list tuples containing one column (either as Column or string) - and a sorting direction ("ASC", or "DESC"). - limit: The number of rows to limit the results to. - select_columns: Optionally, the columns of the view if a model is given and is too limited. - joins: Join operations to apply to the view. + :param name: The name of the table. + :param on: The table the view is based on. + :param columns: A BaseModel subclass or the columns of the view. + :param where: A WHERE expression for the view, defaults to None. + :param group_by: A GROUP BY expression for the view, defaults to None. + :param order_by: A list tuples containing one column (either as Column or string) and a sorting direction + ("ASC", or "DESC"), defaults to None. + :param limit: The number of rows to limit the results to, defaults to None. + :param select_columns: Optionally, the columns of the view if a model is given and is too limited, defaults + to None. + :param joins: Join operations to apply to the view, defaults to None. """ if issubclass(columns, BaseModel): return ModelView[M](self, name, on, columns, select_columns, where, group_by, order_by, limit, joins) diff --git a/acacore/database/column.py b/acacore/database/column.py index 60a9cb3..486c610 100644 --- a/acacore/database/column.py +++ b/acacore/database/column.py @@ -258,20 +258,19 @@ def __init__( """ A class that stores information regarding a table column. - Args: - name: The name of the column. - sql_type: The SQL type to use when creating a table. - to_entry: A function that returns a type supported by SQLite - (str, bytes, int, float, bool, datetime, or None). - from_entry: A function that takes a type returned by SQLite (str, bytes, int, float, or None) - and returns another object. - unique: True if the column should be set as UNIQUE. - primary_key: True if the column is a PRIMARY KEY. - not_null: True if the column is NOT NULL. - check: A string containing a CHECK expression, {name} substrings will be substituted - with the name of the column. - default: The column's DEFAULT value, which will be converted using `to_entry`. - Note that None is considered a valid default value; to set it to empty use Ellipsis (...). + :param name: The name of the column. + :param sql_type: The SQL type to use when creating a table. + :param to_entry: A function that returns a type supported by SQLite + (str, bytes, int, float, bool, datetime, or None). + :param from_entry: A function that takes a type returned by SQLite (str, bytes, int, float, or None) and + returns another object. + :param unique: True if the column should be set as UNIQUE, defaults to False. + :param primary_key: True if the column is a PRIMARY KEY, defaults to False. + :param not_null: True if the column is NOT NULL, defaults to False. + :param check: A string containing a CHECK expression, {name} substrings will be substituted with the name of + the column, defaults to None. + :param default: The column's DEFAULT value, which will be converted using `to_entry`. + Note that None is considered a valid default value; to set it to empty use Ellipsis (...), defaults to .... """ self.name: str = name self.sql_type: str = sql_type @@ -311,11 +310,8 @@ def default_value(self) -> V: """ Get the default value of the column formatted as an SQL parameter. - Returns: - An object of the return type of the column's to_entry function. - - Raises: - ValueError: If the column does not have a set default value. + :raises ValueError: If the column does not have a set default value. + :return: An object of the return type of the column's to_entry function. """ if self.default is Ellipsis: raise ValueError("Column does not have a default value") @@ -325,8 +321,7 @@ def create_statement(self) -> str: """ Generate the statement that creates the column. - Returns: - A column statement for a CREATE TABLE expression. + :return: A column statement for a CREATE TABLE expression. """ elements: list[str] = [self.name, self.sql_type] if self.unique: @@ -351,12 +346,11 @@ def __init__( """ A subclass of Column for SELECT expressions that need complex statements and/or an alias. - Args: - name: The name or select statement for the select expression (e.g., count(*)). - from_entry: A function that takes a type returned by SQLite (str, bytes, int, float, or None) - and returns another object. - alias: An alternative name for the select statement, it will be used with the AS keyword - and as a key by Cursor. + :param name: The name or select statement for the select expression (e.g., count(*)). + :param from_entry: A function that takes a type returned by SQLite (str, bytes, int, float, or None) and + returns another object. + :param alias: An alternative name for the select statement, it will be used with the AS keyword and as a key + by Cursor, defaults to None. """ super().__init__(name, "", lambda x: x, from_entry) self.alias: str | None = alias @@ -366,13 +360,10 @@ def from_column(cls, column: Column, alias: str | None = None) -> "SelectColumn" """ Take a Column object and create a SelectColumn with the given alias. - Args: - column: The Column object to be converted. - alias: An alternative name for the select statement, it will be used with the AS keyword - and as a key by Cursor. - - Returns: - SelectColumn: A SelectColumn object. + :param column: The Column object to be converted. + :param alias: An alternative name for the select statement, it will be used with the AS keyword and as a key + by Cursor, defaults to None. + :return: A SelectColumn object. """ select_column = SelectColumn(column.name, column.from_entry, alias) select_column.sql_type = column.sql_type @@ -393,10 +384,9 @@ def __init__(self, name: str, columns: Sequence[Column], unique: bool = False) - """ A class that stores information regarding an index. - Args: - name: The name of the index - columns: The list of columns that the index applies to. - unique: Whether the index is unique or not. + :param name: The name of the index. + :param columns: The list of columns that the index applies to. + :param unique: Whether the index is unique or not, defaults to False. """ self.name: str = name self.columns: list[Column] = list(columns) @@ -415,12 +405,9 @@ def create_statement(self, table: str, exist_ok: bool = True): """ Generate the expression that creates the index. - Args: - table: The name of the table. - exist_ok: True if existing tables with the same name should be ignored. - - Returns: - A CREATE TABLE expression. + :param table: The name of the table. + :param exist_ok: True if existing tables with the same name should be ignored, defaults to True. + :return: A CREATE TABLE expression. """ return ( f"create {'unique' if self.unique else ''} index {'if not exists' if exist_ok else ''} {self.name}" diff --git a/acacore/database/files_db.py b/acacore/database/files_db.py index 0c7f9d2..e646a6d 100644 --- a/acacore/database/files_db.py +++ b/acacore/database/files_db.py @@ -23,16 +23,12 @@ class HistoryEntryPath(HistoryEntry): class SignatureCount(ACABase): - """Signature count datamodel.""" - puid: str | None signature: str | None count: int | None class ChecksumCount(ACABase): - """Signature count datamodel.""" - checksum: str count: int @@ -58,21 +54,21 @@ def __init__( """ A class that handles the SQLite database used by AArhus City Archives to process data archives. - Args: - database: The path or URI to the database. - timeout: How many seconds the connection should wait before raising an OperationalError - when a table is locked. - detect_types: Control whether and how data types not natively supported by SQLite are looked up to be - converted to Python types. - isolation_level: The isolation_level of the connection, controlling whether - and how transactions are implicitly opened. - check_same_thread: If True (default), ProgrammingError will be raised if the database connection - is used by a thread other than the one that created it. - factory: A custom subclass of Connection to create the connection with, - if not the default Connection class. - cached_statements: The number of statements that sqlite3 should internally cache for this connection, - to avoid parsing overhead. - uri: If set to True, database is interpreted as a URI with a file path and an optional query string. + :param database: The path or URI to the database. + :param timeout: How many seconds the connection should wait before raising an OperationalError when a table + is locked, defaults to 5.0. + :param detect_types: Control whether and how data types not natively supported by SQLite are looked up to be + converted to Python types, defaults to 0. + :param isolation_level: The isolation_level of the connection, controlling whether and how transactions are + implicitly opened, defaults to "DEFERRED". + :param check_same_thread: If True (default), ProgrammingError will be raised if the database connection is + used by a thread other than the one that created it, defaults to True. + :param factory: A custom subclass of Connection to create the connection with, if not the default Connection + class, defaults to Connection. + :param cached_statements: The number of statements that sqlite3 should internally cache for this connection, + to avoid parsing overhead, defaults to 100. + :param uri: If set to True, database is interpreted as a URI with a file path and an optional query string, + defaults to False. """ super().__init__( database, @@ -204,7 +200,6 @@ def __init__( ) def init(self): - """Create the default tables and views.""" self.files.create(True) self.history.create(True) self.metadata.create(True) diff --git a/acacore/exceptions/base.py b/acacore/exceptions/base.py index 10787ff..2f2e43f 100644 --- a/acacore/exceptions/base.py +++ b/acacore/exceptions/base.py @@ -1,2 +1,2 @@ class ACAException(Exception): - pass + """Base class for acacore exceptions.""" diff --git a/acacore/models/base.py b/acacore/models/base.py index a81a789..5c97dc7 100644 --- a/acacore/models/base.py +++ b/acacore/models/base.py @@ -5,10 +5,9 @@ class ACABase(BaseModel): - """Base model with reusable methods & settings.""" - def dump(self, to_file: Path) -> None: to_file.write_text(super().model_dump_json(), encoding="utf-8") def encode(self) -> Any: # noqa: ANN401 + """Encode function.""" return super().model_dump(mode="json") diff --git a/acacore/models/file.py b/acacore/models/file.py index f2b420d..93a0111 100644 --- a/acacore/models/file.py +++ b/acacore/models/file.py @@ -60,19 +60,18 @@ class File(ACABase): """ File model containing all information used by the rest of the archival suite of tools. - Attributes: - uuid (UUID4): The UUID of the file. - checksum (str): The checksum of the file. - puid (str | None): The PUID (PRONOM Unique Identifier) of the file. - relative_path (Path): The relative path to the file. - is_binary (bool): Indicates whether the file is binary. - size (int): The size of the file. - signature (str | None): The signature of the file. - warning (str | None): Any warning associated with the file PUID. - action (str | None): The name of the main action for the file's PUID, if one exists. - action_data (ActionData | None): The data for the action for the file's PUID, if one exists. - processed (bool): True if the file has been processed, false otherwise. - root (Path | None): The root directory for the file. + :ivar uuid: The UUID of the file. + :ivar checksum: The checksum of the file. + :ivar puid: The PUID (PRONOM Unique Identifier) of the file. + :ivar relative_path: The relative path to the file. + :ivar is_binary: Indicates whether the file is binary. + :ivar size: The size of the file. + :ivar signature: The signature of the file. + :ivar warning: Any warning associated with the file PUID. + :ivar action: The name of the main action for the file's PUID, if one exists. + :ivar action_data: The data for the action for the file's PUID, if one exists. + :ivar processed: True if the file has been processed, false otherwise. + :ivar root: The root directory for the file. """ uuid: UUID4 = DBField(default_factory=uuid4, index=["idx_uuid"]) @@ -109,17 +108,14 @@ def from_file( Given a list of CustomSignatures, the file identification will be refined. - Args: - path: The path to the file. - root: Optionally, the root to be used to compute the relative path to the file. - siegfried: A Siegfried class object to identify the file. - actions: A dictionary with PUID keys and Action values to assign an action. - custom_signatures: A list of CustomSignature objects to refine the identification. - uuid: Optionally, a specific UUID to use for the file. - processed: Optionally, the value to be used for the processed property. - - Returns: - File: A File object. + :param path: The path to the file. + :param root: Optionally, the root to be used to compute the relative path to the file, defaults to None. + :param siegfried: A Siegfried class object to identify the file, defaults to None. + :param actions: A dictionary with PUID keys and Action values to assign an action, defaults to None. + :param custom_signatures: A list of CustomSignature objects to refine the identification, defaults to None. + :param uuid: Optionally, a specific UUID to use for the file, defaults to None. + :param processed: Optionally, the value to be used for the processed property, defaults to False. + :return: A File object. """ file = cls( uuid=uuid or uuid4(), @@ -175,12 +171,9 @@ def identify(self, sf: Siegfried, *, set_match: bool = False) -> SiegfriedFile: """ Identify the file using `siegfried`. - Args: - sf (Siegfried): A Siegfried class object - set_match (bool): Set results of Siegfried match if True - - Returns: - SiegfriedFile: A dataclass object containing the results from the identification + :param sf: A Siegfried class object. + :param set_match: Set results of Siegfried match if True, defaults to False. + :return: A dataclass object containing the results from the identification. """ result = sf.identify(self.get_absolute_path(self.root)).files[0] match = result.best_match() @@ -199,12 +192,11 @@ def identify_custom( """ Uses the BOF and EOF to try to determine a ACAUID for the file. - The custom_sigs list should be found on the `reference_files` repo. - If no match can be found, the method does nothing. + The custom_sigs list should be found on the `reference_files` repo. If no match can be found, the method does + nothing. - Args: - custom_signatures: A list of the custom_signatures that the file should be checked against - set_match (bool): Set results of match if True + :param custom_signatures: A list of the custom_signatures that the file should be checked against. + :param set_match: Set results of match if True, defaults to False. """ bof = get_bof(self.get_absolute_path(self.root)).hex() eof = get_eof(self.get_absolute_path(self.root)).hex() @@ -282,8 +274,7 @@ def name(self) -> str: """ Get file name. - Returns: - str: File name. + :return: File name. """ return self.relative_path.name @@ -296,8 +287,7 @@ def suffix(self) -> str: """ Get file suffix. - Returns: - str: File extension. + :return: File extension. """ return self.relative_path.suffix.lower() diff --git a/acacore/models/history.py b/acacore/models/history.py index 28cb1a1..8fac80d 100644 --- a/acacore/models/history.py +++ b/acacore/models/history.py @@ -32,18 +32,15 @@ def command_history( """ Create a HistoryEntry for a command. - Args: - ctx: The context object representing the current command execution. - operation: The name of the operation for which the command history entry is being created. - uuid: Optional. The UUID associated with the command history entry. Default is None. - data: Optional. Additional data or parameters associated with the command history entry. - It defaults to the params property of the context, if it is a click.Context object, otherwise None. - reason: Optional. The reason for the command execution. Default is None. - time: Optional. The timestamp of the command execution. Default is None. - add_params_to_data: If true, add context parameters to data - - Returns: - HistoryEntry: A `HistoryEntry` instance representing the command history entry. + :param ctx: The context object representing the current command execution. + :param operation: The name of the operation for which the command history entry is being created. + :param uuid: Optional. The UUID associated with the command history entry, defaults to None. + :param data: Optional. Additional data or parameters associated with the command history entry. + It Context object, otherwise None, defaults to None. + :param reason: Optional. The reason for the command execution, defaults to None. + :param time: Optional. The timestamp of the command execution, defaults to None. + :param add_params_to_data: If true, add context parameters to data, defaults to False. + :return: A `HistoryEntry` instance representing the command history entry. """ command: str current: Context = ctx diff --git a/acacore/models/identification.py b/acacore/models/identification.py index d8a139b..0f098f4 100644 --- a/acacore/models/identification.py +++ b/acacore/models/identification.py @@ -6,8 +6,6 @@ class Identification(ACABase): - """File identification datamodel.""" - puid: str | None signature: str | None warning: str | None @@ -17,7 +15,6 @@ class Identification(ACABase): @model_validator(mode="before") @classmethod def check_puid_sig(cls, data: dict[Any, Any]) -> dict[Any, Any]: - """Validate that a PUID cannot have an empty signature or vice versa.""" puid, signature = data.get("puid"), data.get("signature") if puid is not None and signature is None: diff --git a/acacore/models/reference_files.py b/acacore/models/reference_files.py index 3f9f3ac..f08556d 100644 --- a/acacore/models/reference_files.py +++ b/acacore/models/reference_files.py @@ -29,8 +29,6 @@ class CustomSignature(BaseModel): - """Data model for the `custom_signatures` from reference_files.""" - bof: str | None = None eof: str | None = None operator: str | None = None @@ -43,9 +41,8 @@ class ConvertAction(BaseModel): """ Class representing an action to convert a file to a different format. - Attributes: - converter (str): The converter to use for the conversion. - outputs (list[str]): The list of file types to convert to. + :ivar converter: The converter to use for the conversion. + :ivar outputs: The list of file types to convert to. """ converter: str @@ -57,10 +54,9 @@ class ExtractAction(BaseModel): """ Class representing an action to extract data from a file. - Attributes: - tool (str): The name of the tool used for extraction. - extension (str | None): The suffix that the file should have. Defaults to None. - dir_suffix (str): The output directory where the extracted data will be saved. + :ivar tool: The name of the tool used for extraction. + :ivar extension: The suffix that the file should have. Defaults to None. + :ivar dir_suffix: The output directory where the extracted data will be saved. """ tool: str @@ -72,10 +68,8 @@ class ReplaceAction(BaseModel): """ Class representing a replacement action. - Attributes: - template (str): The replacement template. - template_text (str | None): Optional. Text to use instead of the default template, - if template is set to "text". + :ivar template: The replacement template. + :ivar template_text: Optional. Text to use instead of the default template, if template is set to "text". """ template: TReplaceTemplate @@ -86,9 +80,8 @@ class ManualAction(BaseModel): """ Class representing a manual action in a workflow. - Attributes: - reason (str): The reason behind the manual action. - process (str): The process for performing the manual action. + :ivar reason: The reason behind the manual action. + :ivar process: The process for performing the manual action. """ reason: str @@ -101,13 +94,12 @@ class IgnoreIfAction(BaseModel): The pixel counts and sizes are considered as the minimum allowed value. - Attributes: - pixel_total (int | None): Total amount of pixels (width times height) for images. - pixel_width (int | None): Width for images. - pixel_height (int | None): Height for images. - size (int | None): Size for all files. - binary_size (int | None): Size for binary files. - reason (int | None): A reason for the specific condition. + :ivar pixel_total: Total amount of pixels (width times height) for images. + :ivar pixel_width: Width for images. + :ivar pixel_height: Height for images. + :ivar size: Size for all files. + :ivar binary_size: Size for binary files. + :ivar reason: A reason for the specific condition. """ pixel_total: int | None = Field(None, gt=0) @@ -122,9 +114,8 @@ class IgnoreAction(BaseModel): """ Class representing an action to ignore a specific file based on the given reason. - Attributes: - reason (str): The reason for ignoring the file. - ignore_if (list[IgnoreIfAction]): An optional list of ignore conditions. + :ivar reason: The reason for ignoring the file. + :ivar ignore_if: An optional list of ignore conditions. """ reason: str | None = None @@ -135,8 +126,7 @@ class ReIdentifyAction(BaseModel): """ Class representing an action to ignore a specific file based on the given reason. - Attributes: - reason (str): The reason for ignoring the file. + :ivar reason: The reason for ignoring the file. """ reason: str @@ -147,8 +137,7 @@ class RenameAction(BaseModel): """ Class representing an action to change file's extension. - Attributes: - extension (str): A string representing the new extension for the file. + :ivar extension: A string representing the new extension for the file. """ extension: str @@ -162,21 +151,20 @@ class ActionData(BaseModel): Separate from Action to avoid duplicating information in the File object. - Attributes: - convert (list[ConvertAction | None]): A list of ConvertAction objects representing the conversion - actions to be performed. Defaults to None. - extract (ExtractAction | None): An ExtractAction object representing the extraction action to be - performed. Defaults to None. - replace (ReplaceAction | None): A ReplaceAction object representing the replacement action to be - performed. Defaults to None. - manual (ManualAction | None): A ManualAction object representing the manual action to be - performed. Defaults to None. - rename (RenameAction | None): A RenameAction object representing the renaming action to be - performed. Defaults to None. - ignore (IgnoreAction | None): An IgnoreAction object representing the ignore action to be - performed. Defaults to None. - reidentify (ReIdentifyAction | None): A ReIdentifyAction object representing the re-identification - action to be performed. Defaults to None. + :ivar convert: A list of ConvertAction objects representing the conversion actions to be performed. + Defaults to None. + :ivar extract: An ExtractAction object representing the extraction action to be performed. + Defaults to None. + :ivar replace: A ReplaceAction object representing the replacement action to be performed. + Defaults to None. + :ivar manual: A ManualAction object representing the manual action to be performed. + Defaults to None. + :ivar rename: A RenameAction object representing the renaming action to be performed. + Defaults to None. + :ivar ignore: An IgnoreAction object representing the ignore action to be performed. + Defaults to None. + :ivar reidentify: A ReIdentifyAction object representing the re-identification action to be performed. + Defaults to None. """ convert: list[ConvertAction | None] = None @@ -192,16 +180,14 @@ class Action(ActionData): """ Class representing an Action. - Follows the format as outlined in the reference files repository. - Subclasses ActionData to avoid duplicated properties in the File object. + Follows the format as outlined in the reference files repository. Subclasses ActionData to avoid duplicated + properties in the File object. See Also: https://github.com/aarhusstadsarkiv/reference-files/blob/main/fileformats.schema.json - - Attributes: - name (str): The name of the action. - description (str | None): The description of the action. - action (TActionType | None): The type of action. + :ivar name: The name of the action. + :ivar description: The description of the action. + :ivar action: The type of action. """ name: str @@ -213,8 +199,7 @@ def action_data(self) -> ActionData: """ Return only the ActionData portion of the object. - Returns: - ActionData: The action data. + :return: The action data. """ return ActionData( convert=self.convert, diff --git a/acacore/reference_files/get.py b/acacore/reference_files/get.py index 114ccfb..68d4774 100644 --- a/acacore/reference_files/get.py +++ b/acacore/reference_files/get.py @@ -39,17 +39,9 @@ def get_actions(use_cache: bool = True) -> dict[str, Action]: The data is fetched from the repository with a cached web request. - Args: - use_cache (bool): Use cached data if True, otherwise fetch data regardless of cache status. - - Returns: - dict[str, Action]: A dictionary with PUID keys and Action values. - - Raises: - urllib.error.HTTPError: If there is an issue with the request. - - See Also: - https://github.com/aarhusstadsarkiv/reference-files/blob/main/actions.yml + :param use_cache: Use cached data if True, otherwise fetch data regardless of cache status, defaults to True. + :raises See Also: https://github.com/aarhusstadsarkiv/reference-files/blob/main/actions.yml. + :return: A dictionary with PUID keys and Action values. """ return ( _get_actions(f"{download_url.rstrip('/')}/{actions_file.lstrip('/')}") @@ -64,17 +56,9 @@ def get_custom_signatures(use_cache: bool = True) -> list[CustomSignature]: The data is fetched from the repository with a cached web request. - Args: - use_cache (bool): Use cached data if True, otherwise fetch data regardless of cache status - - Returns: - list[CustomSignature]: A list of CustomSignature objects. - - Raises: - urllib.error.HTTPError: If there is an issue with the request. - - See Also: - https://github.com/aarhusstadsarkiv/reference-files/blob/main/custom_signatures.json + :param use_cache: Use cached data if True, otherwise fetch data regardless of cache status, defaults to True. + :raises See Also: https://github.com/aarhusstadsarkiv/reference-files/blob/main/custom_signatures.json. + :return: A list of CustomSignature objects. """ return ( _get_custom_signatures(f"{download_url.rstrip('/')}/{custom_signatures_file.lstrip('/')}") diff --git a/acacore/siegfried/siegfried.py b/acacore/siegfried/siegfried.py index 11b884a..bcb28d8 100644 --- a/acacore/siegfried/siegfried.py +++ b/acacore/siegfried/siegfried.py @@ -45,8 +45,7 @@ def _check_process(process: CompletedProcess) -> CompletedProcess: """ Check process and raise exception if it failed. - Raises: - IdentificationError: if the process ends with a return code other than 0. + :raises IdentificationError: If the process ends with a return code other than 0. """ if process.returncode != 0: raise IdentificationError(process.stderr or process.stdout or f"Unknown error code {process.returncode}") @@ -58,9 +57,8 @@ class SiegfriedIdentifier(BaseModel): """ A class representing an identifiers used by the Siegfried identification tool. - Attributes: - name (str): The name of the Siegfried identifier. - details (str): Additional details or description of the identifier. + :ivar name: The name of the Siegfried identifier. + :ivar details: Additional details or description of the identifier. """ name: str @@ -71,17 +69,16 @@ class SiegfriedMatch(BaseModel): """ A class representing a match generated by the Siegfried identification tool. - Attributes: - ns (str): The namespace of the match. - id (str, optional): The identifier of the match. - format (str): The format of the match. - version (str, optional): The version of the match. - mime (str): The MIME type of the match. - match_class (str, optional): The class of the match. - basis (list[str]): The basis of the match. - warning (list[str]): The warning messages of the match. - URI (AnyUrl, optional): The URI of the match. - permalink (HttpUrl, optional): The permalink of the match. + :ivar ns: The namespace of the match. + :ivar id: The identifier of the match. + :ivar format: The format of the match. + :ivar version: The version of the match. + :ivar mime: The MIME type of the match. + :ivar match_class: The class of the match. + :ivar basis: The basis of the match. + :ivar warning: The warning messages of the match. + :ivar URI: The URI of the match. + :ivar permalink: The permalink of the match. """ ns: str @@ -99,8 +96,7 @@ def byte_match(self) -> int | None: """ Get the length of the byte match, if any, or None. - Returns: - The length of the byte match or None, if the match was not on the basis of bytes. + :return: The length of the byte match or None, if the match was not on the basis of bytes. """ for basis in self.basis: match = _byte_match_regexp_single.match(basis) or _byte_match_regexp_multi.match(basis) @@ -112,8 +108,7 @@ def extension_match(self) -> str | None: """ Get the matched extension. - Returns: - The matched extension or None, if the match was not on the basis of the extension. + :return: The matched extension or None, if the match was not on the basis of the extension. """ for basis in self.basis: match = _extension_match.match(basis) @@ -125,8 +120,7 @@ def extension_mismatch(self) -> bool: """ Check whether the match has an extension mismatch warning. - Returns: - True if the match has an extension mismatch warning, False otherwise + :return: True if the match has an extension mismatch warning, False otherwise """ return "extension mismatch" in self.warning @@ -134,8 +128,7 @@ def filename_mismatch(self) -> bool: """ Check whether the match has a filename mismatch warning. - Returns: - True if the match has a filename mismatch warning, False otherwise + :return: True if the match has a filename mismatch warning, False otherwise """ return "filename mismatch" in self.warning @@ -145,8 +138,7 @@ def sort_tuple(self) -> tuple[int, int, int, int, int]: The fields used for the tuple are: byte match, extension match, format, version, and mime. - Returns: - A tuple of 5 integers. + :return: A tuple of 5 integers. """ return ( self.byte_match() or 0, @@ -175,15 +167,14 @@ class SiegfriedFile(BaseModel): """ The SiegfriedFile class represents a file that has been analyzed by Siegfried. - It contains information about the file's name, size, modification date, matching results, and any - errors encountered during analysis. + It contains information about the file's name, size, modification date, matching results, and any errors encountered + during analysis. - Attributes: - filename (str): The name of the file. - filesize (int): The size of the file in bytes. - modified (datetime): The modification date of the file. - errors (str): Any errors encountered during analysis. - matches (list[SiegfriedMatch]): The list of matches found for the file. + :ivar filename: The name of the file. + :ivar filesize: The size of the file in bytes. + :ivar modified: The modification date of the file. + :ivar errors: Any errors encountered during analysis. + :ivar matches: The list of matches found for the file. """ filename: str @@ -196,8 +187,7 @@ def best_match(self) -> SiegfriedMatch | None: """ Get the best match for the file. - Returns: - A SiegfriedMatch object or None if there are no known matches. + :return: A SiegfriedMatch object or None if there are no known matches. """ matches: list[SiegfriedMatch] = [m for m in self.matches if m.id] matches.sort(key=lambda m: m.sort_tuple()) @@ -207,8 +197,7 @@ def best_matches(self) -> list[SiegfriedMatch]: """ Get the matches for the file sorted by how good they are; best are first. - Returns: - A list of SiegfriedMatch objects. + :return: A list of SiegfriedMatch objects. """ return sorted([m for m in self.matches if m.id], key=lambda m: m.sort_tuple(), reverse=True) @@ -217,13 +206,12 @@ class SiegfriedResult(BaseModel): """ Represents the result of a Siegfried signature scan. - Attributes: - siegfried (str): The version of Siegfried used for the scan. - scandate (datetime): The date and time when the scan was performed. - signature (str): The digital signature used for the scan. - created (datetime): The date and time when the signature file was created. - identifiers (List[SiegfriedIdentifier]): A list of identifiers used for file identification. - files (List[SiegfriedFile]): A list of files that were scanned. + :ivar siegfried: The version of Siegfried used for the scan. + :ivar scandate: The date and time when the scan was performed. + :ivar signature: The digital signature used for the scan. + :ivar created: The date and time when the signature file was created. + :ivar identifiers: A list of identifiers used for file identification. + :ivar files: A list of files that were scanned. """ siegfried: str @@ -239,12 +227,7 @@ class Siegfried: """ A class for interacting with the Siegfried file identification tool. - Attributes: - binary (str): The path to the Siegfried binary or the program name if it is included in the PATH variable. - signature (str): The signature file to use with Siegfried. - - See Also: - https://github.com/richardlehane/siegfried + :ivar See Also: https://github.com/richardlehane/siegfried. """ def __init__( @@ -256,10 +239,9 @@ def __init__( """ Initializes a new instance of the Siegfried class. - Args: - binary: The path or name of the Siegfried binary. Defaults to "sf". - signature: The name of the signature file to use. Defaults to "default.sig". - home: The location of the Siegfried home folder. Defaults to $HOME/siegfried. + :param binary: The path or name of the Siegfried binary, defaults to "sf". + :param signature: The name of the signature file to use. sig", defaults to "default.sig". + :param home: The location of the Siegfried home folder, defaults to None. """ self.binary: str = str(binary) self.signature: str = signature @@ -269,14 +251,9 @@ def run(self, *args: str) -> CompletedProcess: """ Run the Siegfried command. - Args: - *args: The arguments to be given to Siegfried (excluding the binary path/name). - - Returns: - A subprocess.CompletedProcess object. - - Raises: - IdentificationError: If Siegfried exits with a non-zero status code. + :param *args: The arguments to be given to Siegfried (excluding the binary path/name). + :raises IdentificationError: If Siegfried exits with a non-zero status code. + :return: A subprocess.CompletedProcess object. """ if self.home: args = ("-home", str(self.home), *args) @@ -286,13 +263,12 @@ def update(self, signature: TSignature | None = None, *, set_signature: bool = T """ Update or fetch signature files. - Args: - signature: The name of signatures provider; one of: "pronom", "loc", "tika", "freedesktop", - "pronom-tika-loc", "deluxe", "archivematica". - set_signature: Set to True to automatically change the signature to the newly updated one. - - Raises: - IdentificationError: If Siegfried exits with a non-zero status code. + :param signature: The name of signatures provider; one of: "pronom", "loc", "tika", "freedesktop",, defaults + to None. + :param "pronom-tika-loc", "deluxe", "archivematica".: + :param set_signature: Set to True to automatically change the signature to the newly updated one, defaults + to True. + :raises IdentificationError: If Siegfried exits with a non-zero status code. """ signature = signature.lower() if signature else self.signature.removesuffix(".sig") signature_file = f"{signature}.sig" if signature else self.signature @@ -306,14 +282,9 @@ def identify(self, path: str | PathLike) -> SiegfriedResult: """ Identify a file. - Args: - path: The path to the file - - Returns: - A SiegfriedResult object - - Raises: - IdentificationError: If there is an error calling Siegfried or processing its results + :param path: The path to the file. + :raises IdentificationError: If there is an error calling Siegfried or processing its results. + :return: A SiegfriedResult object """ process: CompletedProcess = self.run("-sig", self.signature, "-json", "-multi", "1024", str(path)) try: @@ -325,14 +296,9 @@ def identify_many(self, paths: list[Path]) -> tuple[tuple[Path, SiegfriedFile]]: """ Identify multiple files. - Args: - paths: The paths to the files - - Returns: - A tuple of tuples joining the paths with their SiegfriedFile result - - Raises: - IdentificationError: If there is an error calling Siegfried or processing its results + :param paths: The paths to the files. + :raises IdentificationError: If there is an error calling Siegfried or processing its results. + :return: A tuple of tuples joining the paths with their SiegfriedFile result """ process: CompletedProcess = self.run("-sig", self.signature, "-json", "-multi", "1024", *map(str, paths)) try: diff --git a/acacore/utils/functions.py b/acacore/utils/functions.py index 25722c0..9b75d32 100644 --- a/acacore/utils/functions.py +++ b/acacore/utils/functions.py @@ -13,15 +13,13 @@ def or_none(func: Callable[[T], R]) -> Callable[[T], R | None]: - """Create a lambda function of arity one that will return None if its argument is None. + """ + Create a lambda function of arity one that will return None if its argument is None. Otherwise, will call func on the object. - Args: - func: A function of type (T) -> R that will handle the object if it is not none. - - Returns: - object: A function of type (T) -> R | None. + :param func: A function of type (T) -> R that will handle the object if it is not none. + :return: A function of type (T) -> R | None. """ return lambda x: None if x is None else func(x) @@ -30,8 +28,7 @@ def rm_tree(path: Path): """ Remove a directory and all the files and other folders it contains. - Args: - path (Path): The path to the directory. + :param path: The path to the directory. """ if not path.is_dir(): path.unlink(missing_ok=True) @@ -49,12 +46,9 @@ def find_files(path: Path, exclude: list[Path] | None = None) -> Generator[Path, Paths in the exclude argument will be ignored, including their children if they are folders. - Args: - path (Path): The path to search for files. - exclude (list[Path] | None): A list of files or directories to exclude from the search. Defaults to None. - - Returns: - Generator[Path, None, None]: A generator that yields paths of found files. + :param path: The path to search for files. + :param exclude: A list of files or directories to exclude from the search, defaults to None. + :return: A generator that yields paths of found files. """ if exclude and path in exclude: return @@ -71,11 +65,8 @@ def file_checksum(path: Path) -> str: """ Calculate the checksum of a file using the SHA256 hash algorithm. - Args: - path (Path): The path to the file. - - Returns: - str: The SHA256 checksum of the file in hex digest form. + :param path: The path to the file. + :return: The SHA256 checksum of the file in hex digest form. """ file_hash = sha256() with path.open("rb") as f: @@ -90,12 +81,9 @@ def is_binary(path: Path, chunk_size: int = 1024): """ Check if a file is a binary or plain text. - Args: - path (Path): The path to the file to be checked. - chunk_size (int): The size of the chunk to be read from the file in bytes. Default is 1024. - - Returns: - bool: True if the file is binary, False if it is not. + :param path: The path to the file to be checked. + :param chunk_size: The size of the chunk to be read from the file in bytes, defaults to 1024. + :return: True if the file is binary, False if it is not. """ with path.open("rb") as f: return bool(f.read(chunk_size).translate(None, _text_bytes)) @@ -105,12 +93,9 @@ def get_bof(path: Path, chunk_size: int = 1024) -> bytes: """ Get the beginning chunk of a file in bytes. - Args: - path (Path): The path of the file to read. - chunk_size (int): The size of each chunk to read from the file. Defaults to 1024. - - Returns: - bytes: The contents of the first chunk of the file as a bytes object. + :param path: The path of the file to read. + :param chunk_size: The size of each chunk to read from the file, defaults to 1024. + :return: The contents of the first chunk of the file as a bytes object. """ with path.open("rb") as f: return f.read(chunk_size) @@ -120,12 +105,9 @@ def get_eof(path: Path, chunk_size: int = 1024) -> bytes: """ Get the ending chunk of a file in bytes. - Args: - path (Path): The path of the file to read. - chunk_size (int): The size of each chunk to read from the file. Defaults to 1024. - - Returns: - bytes: The contents of the last chunk of the file as a bytes object. + :param path: The path of the file to read. + :param chunk_size: The size of each chunk to read from the file, defaults to 1024. + :return: The contents of the last chunk of the file as a bytes object. """ with path.open("rb") as f: file_size: int = path.stat().st_size @@ -137,16 +119,11 @@ def image_size(path: Path) -> tuple[int, int]: """ Calculate the size of an image. - Args: - path (Path): The path to the image file. - - Returns: - tuple[int, int]: A tuple representing the width and height of the image. - - Raises: - FileNotFoundError: If the provided path does not exist. - IsADirectoryError: If the provided path points to a directory instead of a file. - PIL.UnidentifiedImageError: If the provided file is not a valid image file. + :param path: The path to the image file. + :raises FileNotFoundError: If the provided path does not exist. + :raises IsADirectoryError: If the provided path points to a directory instead of a file. + :raises PIL.UnidentifiedImageError: If the provided file is not a valid image file. + :return: A tuple representing the width and height of the image. """ with Image.open(path) as i: return i.size diff --git a/acacore/utils/helpers.py b/acacore/utils/helpers.py index 5c69c1b..ed21462 100644 --- a/acacore/utils/helpers.py +++ b/acacore/utils/helpers.py @@ -7,17 +7,15 @@ class ExceptionManager: """ A context manager class that catches specified exceptions and stores the exception and traceback for later use. - Exceptions whose class is explicitly declared in the 'catch' argument are always caught, - even if they subclass from classes passed int the 'allow' argument. - - Args: - *catch (Type[BaseException]): Exception types that should be caught and not allowed to rise. - - Attributes: - exception (BaseException | None): The exception that was raised within the context, if any. - traceback (TracebackType | None): The traceback associated with the exception, if any. - catch (tuple[Type[BaseException], ...]): Tuple of exceptions that should be caught instead of letting them rise. - allow (tuple[Type[BaseException], ...]): Tuple of exceptions that should be allowed to rise. + Exceptions whose class is explicitly declared in the 'catch' argument are always caught, even if they subclass from + classes passed int the 'allow' argument. + + :param allow: Defaults to None. + :param *catch: Exception types that should be caught and not allowed to rise. + :ivar exception: The exception that was raised within the context, if any. + :ivar traceback: The traceback associated with the exception, if any. + :ivar catch: Tuple of exceptions that should be caught instead of letting them rise. + :ivar allow: Tuple of exceptions that should be allowed to rise. """ __slots__ = ("exception", "traceback", "catch", "allow") diff --git a/acacore/utils/io.py b/acacore/utils/io.py index 7eb0f78..8aaf420 100644 --- a/acacore/utils/io.py +++ b/acacore/utils/io.py @@ -5,16 +5,10 @@ def size_fmt(size: float) -> str: """ - Formats a file size in binary multiples to a human readable string. + Formats a file size in binary multiples to a human-readable string. - Parameters - ---------- - size: - The file size in bytes. - - Returns: - ------- - Human readable string representing size in binary multiples. + :param size: The file size in bytes. + :return: Human-readable string representing size in binary multiples. """ unit: int = int(log2(size) // 10) unit = unit if unit < len(binary_units) else len(binary_units) - 1 diff --git a/acacore/utils/log.py b/acacore/utils/log.py index b5bc985..c2eba26 100644 --- a/acacore/utils/log.py +++ b/acacore/utils/log.py @@ -23,16 +23,11 @@ def setup_logger(log_name: str, *, files: list[Path] | None = None, streams: lis """ Set up a logger that prints to files and/or streams. - Args: - log_name: The name of the logger. - files: A list of Path objects representing the log files. - streams: A list of IO objects representing the log streams. - - Returns: - The configured Logger object. - - Raises: - AssertionError: If neither files nor streams are given. + :param log_name: The name of the logger. + :param files: A list of Path objects representing the log files, defaults to None. + :param streams: A list of IO objects representing the log streams, defaults to None. + :raises AssertionError: If neither files nor streams are given. + :return: The configured Logger object. """ assert files or streams, "At least one file or stream must be set."