From 51ea136022d2e19ad8ab46201472766ff6343a0e Mon Sep 17 00:00:00 2001 From: Daniel Cummins Date: Tue, 1 Oct 2024 13:50:19 +0100 Subject: [PATCH 1/7] Replaced isort, black and flake8 with ruff --- poetry.lock | 138 ++++++++++--------------------------------------- pyproject.toml | 4 +- 2 files changed, 29 insertions(+), 113 deletions(-) diff --git a/poetry.lock b/poetry.lock index ba0b263..4b7bdb1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -19,52 +19,6 @@ docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphi tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] -[[package]] -name = "black" -version = "23.12.1" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-23.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2"}, - {file = "black-23.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba"}, - {file = "black-23.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0"}, - {file = "black-23.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3"}, - {file = "black-23.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba"}, - {file = "black-23.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b"}, - {file = "black-23.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59"}, - {file = "black-23.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50"}, - {file = "black-23.12.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e"}, - {file = "black-23.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec"}, - {file = "black-23.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e"}, - {file = "black-23.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9"}, - {file = "black-23.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f"}, - {file = "black-23.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d"}, - {file = "black-23.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a"}, - {file = "black-23.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e"}, - {file = "black-23.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055"}, - {file = "black-23.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54"}, - {file = "black-23.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea"}, - {file = "black-23.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2"}, - {file = "black-23.12.1-py3-none-any.whl", hash = "sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e"}, - {file = "black-23.12.1.tar.gz", hash = "sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "bump2version" version = "1.0.1" @@ -350,22 +304,6 @@ docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2. testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] typing = ["typing-extensions (>=4.12.2)"] -[[package]] -name = "flake8" -version = "4.0.1" -description = "the modular source code checker: pep8 pyflakes and co" -optional = false -python-versions = ">=3.6" -files = [ - {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, - {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, -] - -[package.dependencies] -mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.8.0,<2.9.0" -pyflakes = ">=2.4.0,<2.5.0" - [[package]] name = "ghp-import" version = "2.1.0" @@ -459,20 +397,6 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[[package]] -name = "isort" -version = "5.13.2" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, - {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, -] - -[package.extras] -colors = ["colorama (>=0.4.6)"] - [[package]] name = "jinja2" version = "3.1.4" @@ -577,17 +501,6 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] -[[package]] -name = "mccabe" -version = "0.6.1" -description = "McCabe checker, plugin for flake8" -optional = false -python-versions = "*" -files = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, -] - [[package]] name = "mergedeep" version = "1.3.4" @@ -1047,28 +960,6 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" -[[package]] -name = "pycodestyle" -version = "2.8.0" -description = "Python style guide checker" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, - {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, -] - -[[package]] -name = "pyflakes" -version = "2.4.0" -description = "passive checker of Python programs" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, - {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, -] - [[package]] name = "pygments" version = "2.18.0" @@ -1300,6 +1191,33 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "ruff" +version = "0.6.8" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.6.8-py3-none-linux_armv6l.whl", hash = "sha256:77944bca110ff0a43b768f05a529fecd0706aac7bcce36d7f1eeb4cbfca5f0f2"}, + {file = "ruff-0.6.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:27b87e1801e786cd6ede4ada3faa5e254ce774de835e6723fd94551464c56b8c"}, + {file = "ruff-0.6.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:cd48f945da2a6334f1793d7f701725a76ba93bf3d73c36f6b21fb04d5338dcf5"}, + {file = "ruff-0.6.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:677e03c00f37c66cea033274295a983c7c546edea5043d0c798833adf4cf4c6f"}, + {file = "ruff-0.6.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9f1476236b3eacfacfc0f66aa9e6cd39f2a624cb73ea99189556015f27c0bdeb"}, + {file = "ruff-0.6.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f5a2f17c7d32991169195d52a04c95b256378bbf0de8cb98478351eb70d526f"}, + {file = "ruff-0.6.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5fd0d4b7b1457c49e435ee1e437900ced9b35cb8dc5178921dfb7d98d65a08d0"}, + {file = "ruff-0.6.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8034b19b993e9601f2ddf2c517451e17a6ab5cdb1c13fdff50c1442a7171d87"}, + {file = "ruff-0.6.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6cfb227b932ba8ef6e56c9f875d987973cd5e35bc5d05f5abf045af78ad8e098"}, + {file = "ruff-0.6.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef0411eccfc3909269fed47c61ffebdcb84a04504bafa6b6df9b85c27e813b0"}, + {file = "ruff-0.6.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:007dee844738c3d2e6c24ab5bc7d43c99ba3e1943bd2d95d598582e9c1b27750"}, + {file = "ruff-0.6.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ce60058d3cdd8490e5e5471ef086b3f1e90ab872b548814e35930e21d848c9ce"}, + {file = "ruff-0.6.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1085c455d1b3fdb8021ad534379c60353b81ba079712bce7a900e834859182fa"}, + {file = "ruff-0.6.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:70edf6a93b19481affd287d696d9e311388d808671bc209fb8907b46a8c3af44"}, + {file = "ruff-0.6.8-py3-none-win32.whl", hash = "sha256:792213f7be25316f9b46b854df80a77e0da87ec66691e8f012f887b4a671ab5a"}, + {file = "ruff-0.6.8-py3-none-win_amd64.whl", hash = "sha256:ec0517dc0f37cad14a5319ba7bba6e7e339d03fbf967a6d69b0907d61be7a263"}, + {file = "ruff-0.6.8-py3-none-win_arm64.whl", hash = "sha256:8d3bb2e3fbb9875172119021a13eed38849e762499e3cfde9588e4b4d70968dc"}, + {file = "ruff-0.6.8.tar.gz", hash = "sha256:a5bf44b1aa0adaf6d9d20f86162b34f7c593bfedabc51239953e446aefc8ce18"}, +] + [[package]] name = "six" version = "1.16.0" @@ -1456,4 +1374,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "27623a749bb883c01bebf8bec0b913c9254cd4279808f3ee6afddbc1e095c02f" +content-hash = "b0446d787719bdd9d5e2eb5c7589cee89dda137be65b03d969a9c8640313bcfe" diff --git a/pyproject.toml b/pyproject.toml index 7d0ff4f..bdb5d1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,15 +35,13 @@ pytest = "^7.2" pytest-cov = "^3.0.0" pytest-mypy = "^0.9.1" pytest-mock = "^3.7.0" -isort = "^5.10.1" pre-commit = "^2.18.1" -black = "^23.3.0" numpy = "^1.24.2" pandas = "^2.0.0" -flake8 = "^4.0.1" types-PyYAML = "^6.0.7" bump2version = "^1.0.1" coverage = "^7.1.0" +ruff = "^0.6.8" [tool.poetry.group.docs] optional = true From a8c4b3f9abad480aad02772094c4edd09280d0e9 Mon Sep 17 00:00:00 2001 From: Daniel Cummins Date: Tue, 1 Oct 2024 12:54:49 +0100 Subject: [PATCH 2/7] Replaced isort, black and flake8 pre-commit hooks with ruff --- .pre-commit-config.yaml | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a9bf045..d6e80e9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,19 +4,14 @@ repos: hooks: - id: check-merge-conflict - id: debug-statements - - repo: https://github.com/PyCQA/isort - rev: "5.12.0" + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.6.8 hooks: - - id: isort - additional_dependencies: [toml] - - repo: https://github.com/psf/black - rev: "23.1.0" - hooks: - - id: black - # - repo: https://github.com/PyCQA/flake8 - # rev: 6.0.0 - # hooks: - # - id: flake8 + - id: ruff + types_or: [python] + args: [--fix] + - id: ruff-format + types_or: [python] - repo: https://github.com/pre-commit/mirrors-mypy rev: "v0.991" hooks: From 3016a0ecba3958c1e0487da6443aa7b9f286aeb3 Mon Sep 17 00:00:00 2001 From: Daniel Cummins Date: Tue, 1 Oct 2024 13:53:51 +0100 Subject: [PATCH 3/7] Satisfy ruff-format --- csvy/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/csvy/__init__.py b/csvy/__init__.py index adb2a2b..c20172d 100644 --- a/csvy/__init__.py +++ b/csvy/__init__.py @@ -1,6 +1,7 @@ """ Python reader/writer for CSV files with YAML header information. """ + __version__ = "0.2.2" from .readers import ( # noqa: F401 read_header, From 0e76d8aa517e2709857f1c08704a8245084568c0 Mon Sep 17 00:00:00 2001 From: Daniel Cummins Date: Tue, 1 Oct 2024 13:57:45 +0100 Subject: [PATCH 4/7] Added ruff config --- pyproject.toml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index bdb5d1d..aa5d7c8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,18 @@ mkdocs-gen-files = "^0.4.0" mkdocs-literate-nav = "^0.5.0" mkdocs-section-index = "^0.3.4" +[tool.ruff] +target-version = "py312" +lint.select = [ + "D", # pydocstyle + "E", # pycodestyle + "F", # Pyflakes + "I", # isort + "UP", # pyupgrade + "RUF", # ruff +] +lint.pydocstyle.convention = "google" + [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" From def16f4f9f7d8501e446de93f874fa7c89e50e61 Mon Sep 17 00:00:00 2001 From: Daniel Cummins Date: Tue, 1 Oct 2024 14:07:25 +0100 Subject: [PATCH 5/7] Added missing docstrings --- csvy/__init__.py | 4 +--- csvy/readers.py | 38 +++++++++++++++++++------------------ csvy/writers.py | 49 +++++++++++++++++++++++++++++------------------- 3 files changed, 51 insertions(+), 40 deletions(-) diff --git a/csvy/__init__.py b/csvy/__init__.py index c20172d..9955d89 100644 --- a/csvy/__init__.py +++ b/csvy/__init__.py @@ -1,6 +1,4 @@ -""" -Python reader/writer for CSV files with YAML header information. -""" +"""Python reader/writer for CSV files with YAML header information.""" __version__ = "0.2.2" from .readers import ( # noqa: F401 diff --git a/csvy/readers.py b/csvy/readers.py index e51bcd9..ba9803e 100644 --- a/csvy/readers.py +++ b/csvy/readers.py @@ -1,6 +1,8 @@ +"""A collection of functions for parsing CSVY files.""" + import logging from pathlib import Path -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Any import yaml @@ -45,8 +47,8 @@ def get_comment(line: str, marker: str = "---") -> str: def read_header( - filename: Union[Path, str], marker: str = "---", **kwargs: Any -) -> Tuple[Dict[str, Any], int, str]: + filename: Path | str, marker: str = "---", **kwargs: Any +) -> tuple[dict[str, Any], int, str]: """Read the yaml-formatted header from a file. Args: @@ -80,8 +82,8 @@ def read_header( def read_metadata( - filename: Union[Path, str], marker: str = "---", **kwargs: Any -) -> Dict[str, Any]: + filename: Path | str, marker: str = "---", **kwargs: Any +) -> dict[str, Any]: """Read the yaml-formatted metadata from a file. Args: @@ -96,11 +98,11 @@ def read_metadata( def read_to_array( - filename: Union[Path, str], + filename: Path | str, marker: str = "---", - csv_options: Optional[Dict[str, Any]] = None, - yaml_options: Optional[Dict[str, Any]] = None, -) -> Tuple[NDArray, Dict[str, Any]]: + csv_options: dict[str, Any] | None = None, + yaml_options: dict[str, Any] | None = None, +) -> tuple[NDArray, dict[str, Any]]: """Reads a CSVY file into dict with the header and array with the data. Args: @@ -131,11 +133,11 @@ def read_to_array( def read_to_dataframe( - filename: Union[Path, str], + filename: Path | str, marker: str = "---", - csv_options: Optional[Dict[str, Any]] = None, - yaml_options: Optional[Dict[str, Any]] = None, -) -> Tuple[DataFrame, Dict[str, Any]]: + csv_options: dict[str, Any] | None = None, + yaml_options: dict[str, Any] | None = None, +) -> tuple[DataFrame, dict[str, Any]]: """Reads a CSVY file into dict with the header and a DataFrame with the data. Possible 'skiprows' and 'comment' argument provided in the 'csv_options' dictionary @@ -169,11 +171,11 @@ def read_to_dataframe( def read_to_list( - filename: Union[Path, str], + filename: Path | str, marker: str = "---", - csv_options: Optional[Dict[str, Any]] = None, - yaml_options: Optional[Dict[str, Any]] = None, -) -> Tuple[List[List], Dict[str, Any]]: + csv_options: dict[str, Any] | None = None, + yaml_options: dict[str, Any] | None = None, +) -> tuple[list[list], dict[str, Any]]: """Reads a CSVY file into a list with the header and a nested list with the data. Args: @@ -196,7 +198,7 @@ def read_to_list( options = csv_options.copy() if csv_options is not None else {} data = [] - with open(filename, "r", newline="") as csvfile: + with open(filename, newline="") as csvfile: csvreader = csv.reader(csvfile, **options) for _ in range(nlines): diff --git a/csvy/writers.py b/csvy/writers.py index 68234cd..60584ec 100644 --- a/csvy/writers.py +++ b/csvy/writers.py @@ -1,29 +1,40 @@ +"""A collection of functions for writing CSVY files.""" + from __future__ import annotations import csv import logging +from collections.abc import Callable, Iterable from io import TextIOBase from pathlib import Path -from typing import Any, Callable, Dict, Iterable, List, Optional, Union +from typing import Any import yaml -KNOWN_WRITERS: List[Callable[[Union[Path, str], Any, str], bool]] = [] +KNOWN_WRITERS: list[Callable[[Path | str, Any, str], bool]] = [] + +def register_writer(fun: Callable[[Path | str, Any, str], bool]) -> Callable: + """Register a file writer. + + Args: + fun (Callable): The writer function. -def register_writer(fun: Callable[[Union[Path, str], Any, str], bool]) -> Callable: + Returns: + Callable: the writer function. + """ if fun not in KNOWN_WRITERS: KNOWN_WRITERS.append(fun) return fun def write( - filename: Union[Path, str], + filename: Path | str, data: Any, - header: Dict[str, Any], + header: dict[str, Any], comment: str = "", - csv_options: Optional[Dict[str, Any]] = None, - yaml_options: Optional[Dict[str, Any]] = None, + csv_options: dict[str, Any] | None = None, + yaml_options: dict[str, Any] | None = None, ) -> None: """Writes the data and header in a CSV file, formating the header as yaml. @@ -54,11 +65,11 @@ class Writer: def __init__( self, - filename: Union[Path, str], - header: Dict[str, Any], + filename: Path | str, + header: dict[str, Any], comment: str = "", - csv_options: Optional[Dict[str, Any]] = None, - yaml_options: Optional[Dict[str, Any]] = None, + csv_options: dict[str, Any] | None = None, + yaml_options: dict[str, Any] | None = None, line_buffering: bool = False, ) -> None: """Create a new Writer. @@ -72,7 +83,6 @@ def __init__( writing the header. line_buffering: Line buffering instead of chunk buffering (default False). """ - if not csv_options: csv_options = {} if not yaml_options: @@ -88,9 +98,11 @@ def __init__( self._writer = csv.writer(self._file, **csv_options) def __enter__(self) -> Writer: + """Enter the context manager.""" return self def __exit__(self, *_: Any) -> None: + """Exit the context manager.""" self._file.close() def close(self) -> None: @@ -107,8 +119,8 @@ def writerows(self, rows: Iterable[Iterable[Any]]) -> None: def write_header( - file: Union[Path, str, TextIOBase], - header: Dict[str, Any], + file: Path | str | TextIOBase, + header: dict[str, Any], comment: str = "", **kwargs: Any, ) -> None: @@ -137,7 +149,7 @@ def write_header( def write_data( - filename: Union[Path, str], data: Any, comment: str = "", **kwargs: Any + filename: Path | str, data: Any, comment: str = "", **kwargs: Any ) -> None: """Writes the tabular data to the chosen file, adding it after the header. @@ -160,7 +172,7 @@ def write_data( @register_writer def write_numpy( - filename: Union[Path, str], data: Any, comment: str = "", **kwargs: Any + filename: Path | str, data: Any, comment: str = "", **kwargs: Any ) -> bool: """Writes the numpy array to the chosen file, adding it after the header. @@ -193,7 +205,7 @@ def write_numpy( @register_writer def write_pandas( - filename: Union[Path, str], data: Any, comment: str = "", **kwargs: Any + filename: Path | str, data: Any, comment: str = "", **kwargs: Any ) -> bool: """Writes the pandas dataframe to the chosen file, adding it after the header. @@ -224,7 +236,7 @@ def write_pandas( def write_csv( - filename: Union[Path, str], data: Any, comment: str = "", **kwargs: Any + filename: Path | str, data: Any, comment: str = "", **kwargs: Any ) -> bool: """Writes the tabular to the chosen file, adding it after the header. @@ -239,7 +251,6 @@ def write_csv( Returns: True if the writer worked, False otherwise. """ - with open(filename, "a", newline="") as f: writer = csv.writer(f, **kwargs) for row in data: From 4714d58545577a5674e2fca19f1546d5ba240d3c Mon Sep 17 00:00:00 2001 From: Daniel Cummins Date: Tue, 1 Oct 2024 14:20:04 +0100 Subject: [PATCH 6/7] Added test function docstrings --- tests/__init__.py | 1 + tests/conftest.py | 5 +++++ tests/test_read.py | 8 ++++++++ tests/test_write.py | 15 +++++++++++++++ 4 files changed, 29 insertions(+) diff --git a/tests/__init__.py b/tests/__init__.py index e69de29..6a4f508 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1 @@ +"""Tests for the csvy package.""" diff --git a/tests/conftest.py b/tests/conftest.py index 9124356..8562954 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,8 +1,11 @@ +"""Fixtures for the test suite.""" + import pytest @pytest.fixture def data_path(): + """A data path fixture.""" from pathlib import Path return Path(__file__).parent / "data.csv" @@ -10,6 +13,7 @@ def data_path(): @pytest.fixture def data_comment_path(): + """A data comment path fixture.""" from pathlib import Path return Path(__file__).parent / "data_comment.csv" @@ -17,6 +21,7 @@ def data_comment_path(): @pytest.fixture def array_data_path(): + """A data array path fixture.""" from pathlib import Path return Path(__file__).parent / "array_data.csv" diff --git a/tests/test_read.py b/tests/test_read.py index 32bf32d..ed95ca7 100644 --- a/tests/test_read.py +++ b/tests/test_read.py @@ -1,9 +1,12 @@ +"""Tests for the csvy reader functions.""" + from unittest.mock import patch import pytest def test_get_comment(): + """Test the get_comment function.""" from csvy.readers import get_comment assert "" == get_comment("--- Something else") @@ -15,6 +18,7 @@ def test_get_comment(): def test_get_header(data_path, data_comment_path): + """Test the read_header function.""" from csvy.readers import read_header header, nlines, comment = read_header(data_path) @@ -34,6 +38,7 @@ def test_get_header(data_path, data_comment_path): @patch("csvy.readers.read_header") def test_read_metadata(read_header_mock, data_path): + """Test the read_metadata function.""" from csvy import read_metadata read_header_mock.return_value = ("a", "b") @@ -47,6 +52,7 @@ def test_read_metadata(read_header_mock, data_path): def test_read_to_array(array_data_path): + """Test the read_to_array function.""" import numpy as np from csvy.readers import read_to_array @@ -66,6 +72,7 @@ def test_read_to_array(array_data_path): def test_read_to_dataframe(data_path): + """Test the read_to_dataframe function.""" import pandas as pd from csvy.readers import read_to_dataframe @@ -85,6 +92,7 @@ def test_read_to_dataframe(data_path): def test_read_to_list(array_data_path): + """Test the read_to_list function.""" from csvy.readers import read_to_list data, header = read_to_list(array_data_path, csv_options={"delimiter": ","}) diff --git a/tests/test_write.py b/tests/test_write.py index 8e1c18f..365104a 100644 --- a/tests/test_write.py +++ b/tests/test_write.py @@ -1,14 +1,19 @@ +"""Tests for the csvy writer functions.""" + from unittest.mock import MagicMock, patch import pytest class MockCSVWriter: + """A mock CSV writer.""" + writerow = MagicMock() writerows = MagicMock() def test_save_header(tmpdir, mocker): + """Test the write_header function.""" import yaml from csvy.writers import write_header @@ -47,6 +52,7 @@ def test_save_header(tmpdir, mocker): @patch("numpy.savetxt") def test_write_numpy(mock_save, tmpdir): + """Test the write_numpy function.""" import numpy as np from csvy.writers import write_numpy @@ -63,6 +69,7 @@ def test_write_numpy(mock_save, tmpdir): @patch("pandas.DataFrame.to_csv") def test_write_pandas(mock_save, tmpdir): + """Test the save_header function.""" import pandas as pd from csvy.writers import write_pandas @@ -79,6 +86,7 @@ def test_write_pandas(mock_save, tmpdir): @patch("csv.writer") def test_write_csv(mock_save, tmpdir): + """Test the write_csv function.""" from csvy.writers import write_csv class Writer: @@ -105,6 +113,7 @@ class Writer: ), ) def test_writer(mock_write_header, mock_csv_writer, csv_options, yaml_options, tmpdir): + """Test the Writer class.""" from csvy.writers import Writer mock_csv_writer.return_value = MockCSVWriter @@ -126,6 +135,7 @@ def test_writer(mock_write_header, mock_csv_writer, csv_options, yaml_options, t @patch("csv.writer") @patch("csvy.writers.write_header") def test_writer_writerow(mock_write_header, mock_csv_writer, tmpdir): + """Test Writer's writerow method.""" from csvy.writers import Writer filename = tmpdir / "some_file.csv" @@ -139,6 +149,7 @@ def test_writer_writerow(mock_write_header, mock_csv_writer, tmpdir): @patch("csv.writer") @patch("csvy.writers.write_header") def test_writer_writerows(mock_write_header, mock_csv_writer, tmpdir): + """Test Writer's writerows method.""" from csvy.writers import Writer filename = tmpdir / "some_file.csv" @@ -150,6 +161,7 @@ def test_writer_writerows(mock_write_header, mock_csv_writer, tmpdir): def test_writer_close(tmpdir): + """Test Writer's file closure.""" from csvy.writers import Writer filename = tmpdir / "some_file.csv" @@ -160,6 +172,7 @@ def test_writer_close(tmpdir): def test_writer_context(tmpdir): + """Test Writer's context manager.""" from csvy.writers import Writer filename = tmpdir / "some_file.csv" @@ -177,6 +190,7 @@ def test_writer_context(tmpdir): @patch("csvy.writers.write_header") @patch("csvy.writers.write_data") def test_write(mock_write_data, mock_write_header): + """Test the write function.""" from csvy.writers import write filename = "here.csv" @@ -201,6 +215,7 @@ def test_write(mock_write_data, mock_write_header): @patch("csvy.writers.write_csv") def test_write_data(mock_write_csv): + """Test the write_data function.""" from csvy.writers import KNOWN_WRITERS, write_data filename = "here.csv" From 156c246f583e7ec9d0f4f3a7687a07ab55141810 Mon Sep 17 00:00:00 2001 From: Daniel Cummins Date: Tue, 1 Oct 2024 14:20:56 +0100 Subject: [PATCH 7/7] Specify python 3.9 for ruff config --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index aa5d7c8..9925993 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ mkdocs-literate-nav = "^0.5.0" mkdocs-section-index = "^0.3.4" [tool.ruff] -target-version = "py312" +target-version = "py39" lint.select = [ "D", # pydocstyle "E", # pycodestyle