Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: use darglint to check if the docstrings match the actual implementation (DEV-2530) #453

Merged
merged 15 commits into from
Aug 14, 2023
Merged
4 changes: 4 additions & 0 deletions .darglint
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[darglint]
message_template={path}:{line} ({obj}): {msg_id} {msg}
ignore_regex=(make_resource|make_annotation|make_link|make_region|_stash_circular_references)
ignore=DAR402,DAR003
3 changes: 3 additions & 0 deletions .github/workflows/tests-on-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ jobs:

- name: Linting with black
run: poetry run black --check .

- name: Linting with darglint
run: poetry exec darglint


# Install programs for local processing (fast xmlupload)
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,9 @@ We use
- [black](https://pypi.org/project/black/) (configured in `pyproject.toml`)
- [mypy](https://pypi.org/project/mypy/) (configured in `pyproject.toml`)
- [pylint](https://pypi.org/project/pylint/) (configured in `pyproject.toml`)
- [darglint](https://pypi.org/project/darglint/) (configured in `.darglint`)

These 4 linters are integrated in the GitHub CI pipeline,
These linters are integrated in the GitHub CI pipeline,
so that every pull request is checked for code style violations.

In addition, there are [pre-commit hooks](#pre-commit-hooks)
Expand Down
2 changes: 1 addition & 1 deletion docs/developers/code-quality-tools/code-quality-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ DSP-TOOLS uses the ones listed on this page.

The decision to use this set of tools is based on the information in the following pages.


| Task | Tool | Configuration |
| --------------------------------------------------------------- | ------------------------------------------------------------------ | ------------------------------ |
| [General formatting](./general-formatting.md) | [EditorConfig](https://EditorConfig.org/) | `.editorconfig` |
| | [markdownlint](https://github.com/igorshubovych/markdownlint-cli/) | `.markdownlint.yml` |
| [Python formatting](./python-formatting.md) | [Black](https://pypi.org/project/black/) | `pyproject.toml` |
| [Python docstring formatting](./python-docstring-formatting.md) | [pydocstyle](https://pypi.org/project/pydocstyle/) * | |
| | [darglint](https://pypi.org/project/darglint/) | `.darglint` |
| [Python type checking](./python-type-checking.md) | [Mypy](https://pypi.org/project/mypy/) | `pyproject.toml` |
| [Python linting](./python-linting.md) | [Ruff](https://pypi.org/project/ruff/) * | |
| | [Pylint](https://pypi.org/project/pylint/) ** | `pyproject.toml` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,8 @@ Automatically formats docstrings to follow a subset of
the [PEP 257](http://www.python.org/dev/peps/pep-0257/) conventions.
Currently, only the style "sphinx" and "epytext" are recognized,
but "numpy" and "google" are future styles.

### [darglint](https://pypi.org/project/darglint/)

Docstring linter which checks whether a docstring's description matches the actual function/method implementation.
Supports the styles "sphinx", "google", and "numpy".
11 changes: 11 additions & 0 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ mypy = "^1.5.0"
pylint = "^2.17.5"
pytest = "^7.4.0"
pre-commit = "^3.3.3"
darglint = "^1.8.1"
types-requests = "^2.31.0.2"
types-lxml = "^2023.3.28"
types-jsonschema = "^4.17.0.10"
Expand All @@ -66,7 +67,13 @@ check-links = """
./docs \
-i \\.\\/assets\\/.+ \
-i .+github\\.com\\/dasch\\-swiss\\/dsp-tools\\/settings \
-i .+github\\.com\\/dasch\\-swiss\\/ops-deploy\\/.+
-i .+github\\.com\\/dasch\\-swiss\\/ops-deploy\\/.+\
"""
darglint = """
find . -name "*.py" \
-not -path "./src/dsp_tools/models/*" \
-not -path "./.git/*" \
| xargs poetry run darglint -v 2\
"""


Expand Down
7 changes: 6 additions & 1 deletion src/dsp_tools/dsp_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ def _make_parser(
root_user_pw: str,
) -> argparse.ArgumentParser:
"""
Create a parser for the command line arguments
Create a parser for the command line arguments.

Args:
default_dsp_api_url: URL of the DSP server (default value for localhost)
root_user_email: username (e-mail) used for authentication with the DSP-API (default value for localhost)
root_user_pw: password used for authentication with the DSP-API (default value for localhost)

Returns:
parser
Expand Down
34 changes: 21 additions & 13 deletions src/dsp_tools/excel2xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def make_xsd_id_compatible(string: str) -> str:
BaseError: if the input cannot be transformed to an xsd:ID

Returns:
an xsd:ID based on the input string
an xsd ID based on the input string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO not necessarily an improvement, as the colon here suggests namespacing... but if the linter (or you, for that matter 🙂 ) prefers it, sure

"""

if not isinstance(string, str) or not check_notna(string):
Expand Down Expand Up @@ -268,7 +268,7 @@ def make_root(

Args:
shortcode: The shortcode of this project as defined in the JSON project file
default ontology: one of the ontologies of the JSON project file
default_ontology: one of the ontologies of the JSON project file

Returns:
The root element <knora>.
Expand Down Expand Up @@ -1272,14 +1272,14 @@ def make_text_prop(
for val in values:
kwargs = {"permissions": val.permissions}
if check_notna(val.comment):
kwargs["comment"] = val.comment # type: ignore
kwargs["comment"] = val.comment # type: ignore[assignment]
if check_notna(val.encoding):
kwargs["encoding"] = val.encoding # type: ignore
kwargs["encoding"] = val.encoding # type: ignore[assignment]
else:
kwargs["encoding"] = "utf8"
value_ = etree.Element(
"{%s}text" % xml_namespace_map[None],
**kwargs, # type: ignore
**kwargs, # type: ignore[arg-type]
nsmap=xml_namespace_map,
)
if kwargs["encoding"] == "utf8":
Expand Down Expand Up @@ -1730,9 +1730,13 @@ def create_json_excel_list_mapping(

def _nested_dict_values_iterator(dicts: list[dict[str, Any]]) -> Iterable[str]:
"""
This function accepts a list of nested dictionaries as argument
and iterates over all values.
It yields the values iteratively.
Yield all values of a nested dictionary.

Args:
dicts: list of nested dictionaries

Yields:
values of the nested dictionaries
"""
# Credits: https://thispointer.com/python-iterate-loop-over-all-nested-dictionary-values/
for _dict in dicts:
Expand Down Expand Up @@ -1786,7 +1790,14 @@ def _name_label_mapper_iterator(
language_label: str,
) -> Iterable[tuple[str, str]]:
"""
returns (label, name) pairs of JSON project list entries
Go through list nodes of a JSON project and yield (label, name) pairs.

Args:
json_subset: list of DSP lists (a DSP list being a dictionary with the keys "name", "labels" and "nodes")
language_label: which language of the label to choose

Yields:
(label, name) pairs
"""
for node in json_subset:
# node is the json object containing the entire json-list
Expand All @@ -1805,17 +1816,14 @@ def write_xml(
filepath: str,
) -> None:
"""
Write the finished XML to a file
Write the finished XML to a file.

Args:
root: etree Element with the entire XML document
filepath: where to save the file

Raises:
Warning: if the XML is not valid according to the schema

Returns:
None
"""
etree.indent(root, space=" ")
xml_string = etree.tostring(
Expand Down
8 changes: 7 additions & 1 deletion src/dsp_tools/fast_xmlupload/process_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def _write_result_to_pkl_file(processed_files: list[tuple[Path, Optional[Path]]]
processed_files: the result of the file processing

Raises:
UserError if the file could not be written
UserError: if the file could not be written
"""
filename = Path(f"processing_result_{datetime.now().strftime('%Y-%m-%d_%H.%M.%S.%f')}.pkl")

Expand Down Expand Up @@ -326,6 +326,9 @@ def _convert_file_with_sipi(
e.g. tmp/in/te/internal_file_name.jp2 if the internal filename is "internal_file_name"
output_dir: the directory where the processed files are written to,
e.g. tmp/in/te/ if the internal filename is "internal_file_name"

Returns:
success status
"""
original_output_dir = output_dir.parent.parent
in_file_sipi_path = Path("processing-input") / in_file_local_path.relative_to(input_dir)
Expand Down Expand Up @@ -356,6 +359,9 @@ def _create_orig_file(
internal_file_name: the internal filename which should be used for the .orig file
out_dir: the directory where the .orig file should be written to,
e.g. tmp/in/te/ if the internal filename is "internal_file_name"

Returns:
success status
"""
orig_ext = PurePath(in_file).suffix
orig_file_full_path = Path(out_dir, f"{internal_file_name}{orig_ext}.orig")
Expand Down
3 changes: 1 addition & 2 deletions src/dsp_tools/fast_xmlupload/upload_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def _check_processed_dir(dir_with_processed_files: str) -> Path:
Checks the input parameter provided by the user and transforms it into a Path.

Args:
processed_dir: the directory where the processed files have been written to
dir_with_processed_files: the directory where the processed files have been written to

Raises:
UserError: if the directory does not exist
Expand Down Expand Up @@ -378,7 +378,6 @@ def upload_files(
Before using this method, the files must be processed by the processing step.

Args:
e.g. Path('multimedia/nested/subfolder/test.tif'), Path('tmp/0b/22/0b22570d-515f-4c3d-a6af-e42b458e7b2b.jp2').
dir_with_processed_files: path to the directory where the processed files are located
nthreads: number of threads to use for uploading (optimum depends on the number of CPUs on the server)
user: the user's e-mail for login into DSP
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_tools/utils/excel_to_json_lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ def validate_lists_section_with_schema(
lists_section: the "lists" section as Python object

Raises:
BaseError with a detailed error report if the validation fails
BaseError: if the validation fails

Returns:
True if the "lists" section passed validation
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_tools/utils/excel_to_json_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def excel2json(
path_to_output_file: path to the file where the output JSON file will be saved

Raises:
BaseError if something went wrong
BaseError: if something went wrong

Returns:
True if everything went well
Expand Down
6 changes: 3 additions & 3 deletions src/dsp_tools/utils/excel_to_json_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def _validate_properties(
excelfile: path to the Excel file containing the properties

Raises:
BaseError with a detailed error report if the validation fails
BaseError: if the validation fails

Returns:
True if the "properties" section passed validation
Expand Down Expand Up @@ -92,7 +92,7 @@ def _row2prop(
excelfile: name of the original Excel file

Raises:
BaseError if the row contains invalid data
BaseError: if the row contains invalid data

Returns:
dict object of the property
Expand Down Expand Up @@ -149,7 +149,7 @@ def excel2properties(
path_to_output_file: if provided, the output is written into this JSON file

Raises:
BaseError if something went wrong
BaseError: if something went wrong

Returns:
a tuple consisting of the "properties" section as Python list,
Expand Down
6 changes: 3 additions & 3 deletions src/dsp_tools/utils/excel_to_json_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def _validate_resources(
excelfile: path to the Excel file containing the resources

Raises:
BaseError with a detailed error report if the validation fails
BaseError: if the validation fails

Returns:
True if the "resources" section passed validation
Expand Down Expand Up @@ -104,7 +104,7 @@ def _row2resource(
excelfile: Excel file where the data comes from

Raises:
BaseError if the row or the details sheet contains invalid data
BaseError: if the row or the details sheet contains invalid data

Returns:
dict object of the resource
Expand Down Expand Up @@ -203,7 +203,7 @@ def excel2resources(
(otherwise, it's only returned as return value)

Raises:
BaseError if something went wrong
BaseError: if something went wrong

Returns:
a tuple consisting of the "resources" section as Python list,
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_tools/utils/id_to_iri.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def id_to_iri(
verbose: verbose feedback if set to True

Raises:
BaseError if one of the two input files is not a valid file
BaseError: if one of the two input files is not a valid file

Returns:
True if everything went well, False otherwise
Expand Down
16 changes: 10 additions & 6 deletions src/dsp_tools/utils/project_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ def _get_group_iris_for_user(
a tuple consisting of the group IRIs,
the system admin status (True if the user is sysadmin, False otherwise),
and the success status (True if everything went well)

Raises:
BaseError: if no groups can be retrieved from the DSP server, or if the retrieved group has no IRI
"""
success = True
username = json_user_definition["username"]
Expand Down Expand Up @@ -992,13 +995,14 @@ def create_project(

Raises:
UserError:
- if the project cannot be created
- if the login fails
- if an ontology cannot be created
- if the project cannot be created
- if the login fails
- if an ontology cannot be created

BaseError:
- if the input is invalid
- if an Excel file referenced in the "lists" section cannot be expanded
- if the validation doesn't pass
- if the input is invalid
- if an Excel file referenced in the "lists" section cannot be expanded
- if the validation doesn't pass

Returns:
True if everything went smoothly, False if a warning or error occurred
Expand Down
17 changes: 12 additions & 5 deletions src/dsp_tools/utils/project_create_lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ def _create_list_node(
i.e. ``{nodename: {"id": IRI, "nodes": {...}}}``.
The bool is True if all nodes could be created,
False if any node could not be created.

Raises:
BaseError: if the created node has no name
"""
new_node: ListNode = ListNode(
con=con,
Expand Down Expand Up @@ -84,6 +87,9 @@ def create_lists_on_server(
con: connection to the DSP server
project_remote: representation of the project on the DSP server

Raises:
BaseError: if one of the lists to be created already exists on the DSP server, but it has no name

Returns:
tuple consisting of the IRIs of the list nodes and the success status (True if everything went well)
"""
Expand Down Expand Up @@ -152,12 +158,13 @@ def create_lists(

Raises:
UserError:
- if the project cannot be read from the server
- if the connection to the DSP server cannot be established
- if the project cannot be read from the server
- if the connection to the DSP server cannot be established

BaseError:
- if the input is invalid
- if a problem occurred while trying to expand the Excel files
- if the JSON file is invalid according to the schema
- if the input is invalid
- if a problem occurred while trying to expand the Excel files
- if the JSON file is invalid according to the schema

Returns:
Returns a tuple consisting of a dict and a bool.
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_tools/utils/project_get.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def get_project(
verbose : verbose option for the command, if used more output is given to the user

Raises:
BaseError if something went wrong
BaseError: if something went wrong

Returns:
True if the process finishes without errors
Expand Down