diff --git a/.gitignore b/.gitignore index a90bd65..d316ee0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ # xrlint +/xrlint-config.* /xrlint_config.* +/notebooks/xrlint-config.* /notebooks/xrlint_config.* # Logs diff --git a/CHANGES.md b/CHANGES.md index cae6dd0..effe3e1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,12 @@ ## Version 0.5.1 (in development) +- XRLint now also loads default configuration from files named + `xrlint-config.yaml` and `xrlint-config.json`. (#60) + +- The command `xrlint --init` now writes `xrlint-config.yaml` + instead of `xrlint_config.yaml`. + - Enhanced documentation by a new page that compiles the code examples in the `examples` folder. diff --git a/docs/cli.md b/docs/cli.md index ccf06c6..624eb32 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -1,32 +1,44 @@ # Command Line Interface After installation, the `xrlint` command can be used from the terminal. -The following are the command's options and arguments: +The following are the command's usage help including a short description +of its options and arguments: ``` Usage: xrlint [OPTIONS] [FILES]... Validate the given dataset FILES. - Reads configuration from './xrlint_config.*' if such file exists and unless - '--no_config_lookup' is set or '--config' is provided. It then validates - each dataset in FILES against the configuration. The default dataset patters - are '**/*.zarr' and '**/.nc'. FILES may comprise also directories or URLs. - The supported URL protocols are the ones supported by xarray. Using remote - protocols may require installing additional packages such as S3Fs - (https://s3fs.readthedocs.io/) for the 's3' protocol. + When executed, XRLint does the following three things: - If a directory is provided that not matched by any file pattern, it will be - traversed recursively. The validation result is dumped to standard output if - not otherwise stated by '--output-file'. The output format is 'simple' by - default. Other inbuilt formats are 'json' and 'html' which you can specify - using the '--format' option. + (1) Unless options '--no-config-lookup' or '--config' are used it searches + for a default configuration file in the current working directory. Default + configuration files are determined by their filename, namely + 'xrlint_config.py' or 'xrlint-config.', where refers to the + filename extensions 'json', 'yaml', and 'yml'. A Python configuration file + ('*.py'), is expected to provide XRLInt configuration from a function + 'export_config()', which may include custom plugins and rules. + + (2) It then validates each dataset in FILES against the configuration. The + default dataset patters are '**/*.zarr' and '**/.nc'. FILES may comprise + also directories or URLs. The supported URL protocols are the ones supported + by xarray. Using remote protocols may require installing additional packages + such as S3Fs (https://s3fs.readthedocs.io/) for the 's3' protocol. If a + directory is provided that not matched by any file pattern, it will be + traversed recursively. + + (3) The validation result is dumped to standard output if not otherwise + stated by '--output-file'. The output format is 'simple' by default. Other + inbuilt formats are 'json' and 'html' which you can specify using the '-- + format' option. + + Please refer to the documentation (https://bcdev.github.io/xrlint/) for more + information. Options: - --no-config-lookup Disable use of default configuration from - xrlint_config.* - -c, --config FILE Use this configuration, overriding xrlint_config.* - config options if present + --no-config-lookup Disable use of default configuration files + -c, --config FILE Use this configuration instead of looking for a + default configuration file --print-config FILE Print the configuration for the given file --plugin MODULE Specify plugins. MODULE is the name of Python module that defines an 'export_plugin()' function. @@ -37,7 +49,9 @@ Options: --color / --no-color Force enabling/disabling of color --max-warnings COUNT Number of warnings to trigger nonzero exit code - default: 5 - --init Write initial configuration file and exit. + --init Write initial configuration file 'xrlint- + config.yaml' and exit. --version Show the version and exit. --help Show this message and exit. + ``` diff --git a/docs/config.md b/docs/config.md index 0a93f4f..e41fdab 100644 --- a/docs/config.md +++ b/docs/config.md @@ -7,9 +7,9 @@ Many parts have been copied and adjusted as it applies in many similar ways to X The XRLint configuration file may be named any of the following: -* `xrlint_config.yaml` -* `xrlint_config.json` -* `xrlint_config.py` +* YAML format: `xrlint-config.yaml` (or use extension `.yml`) +* JSON format: `xrlint-config.json` +* Python module: `xrlint_config.py` (note the underscore) It should be placed in the root directory of your project and export an array of [configuration objects](#configuration-objects) or @@ -40,7 +40,7 @@ Same using JSON: ] ``` -And as Python script: +And as Python module: ```python def export_config(): diff --git a/docs/start.md b/docs/start.md index d497236..3156ed4 100644 --- a/docs/start.md +++ b/docs/start.md @@ -27,7 +27,7 @@ Initializing a new project with xrlint --init ``` -writes a configuration file `xrlint_config.yaml` +writes a configuration file `xrlint-config.yaml` into the current working directory: ```yaml diff --git a/notebooks/xrlint-linter.ipynb b/notebooks/xrlint-linter.ipynb index 6d1728c..5b10b68 100644 --- a/notebooks/xrlint-linter.ipynb +++ b/notebooks/xrlint-linter.ipynb @@ -1924,7 +1924,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.1" + "version": "3.12.8" } }, "nbformat": 4, diff --git a/tests/cli/test_main.py b/tests/cli/test_main.py index f2d6c41..7db324e 100644 --- a/tests/cli/test_main.py +++ b/tests/cli/test_main.py @@ -160,8 +160,10 @@ def test_color_no_color(self): def test_files_with_invalid_config(self): with text_file(DEFAULT_CONFIG_FILE_YAML, self.invalid_config_yaml): result = self.xrlint("--no-color", *self.files) + # noinspection SpellCheckingInspection self.assertEqual( - "Error: xrlint_config.yaml: configuration 'recommentet' not found\n", + f"Error: {DEFAULT_CONFIG_FILE_YAML}:" + " configuration 'recommentet' not found\n", result.output, ) self.assertEqual(1, result.exit_code) diff --git a/xrlint/cli/constants.py b/xrlint/cli/constants.py index a8fad7d..a8ccba6 100644 --- a/xrlint/cli/constants.py +++ b/xrlint/cli/constants.py @@ -4,22 +4,33 @@ from typing import Final -DEFAULT_CONFIG_BASENAME: Final = "xrlint_config" -DEFAULT_CONFIG_FILE_YAML: Final = f"{DEFAULT_CONFIG_BASENAME}.yaml" -DEFAULT_CONFIG_FILE_JSON: Final = f"{DEFAULT_CONFIG_BASENAME}.json" -DEFAULT_CONFIG_FILE_PY: Final = f"{DEFAULT_CONFIG_BASENAME}.py" +_MODULE_BASENAME: Final = "xrlint_config" +_REGULAR_BASENAME: Final = "xrlint-config" + DEFAULT_CONFIG_FILES: Final = [ - DEFAULT_CONFIG_FILE_YAML, - DEFAULT_CONFIG_FILE_JSON, - DEFAULT_CONFIG_FILE_PY, + # Added in 0.5.1: + f"{_REGULAR_BASENAME}.yaml", + f"{_REGULAR_BASENAME}.yml", + f"{_REGULAR_BASENAME}.json", + # Until 0.5.0: + f"{_MODULE_BASENAME}.yaml", + f"{_MODULE_BASENAME}.yml", + f"{_MODULE_BASENAME}.json", + f"{_MODULE_BASENAME}.py", ] +DEFAULT_CONFIG_FILE_YAML: Final = f"{_REGULAR_BASENAME}.yaml" DEFAULT_OUTPUT_FORMAT: Final = "simple" DEFAULT_MAX_WARNINGS: Final = 5 -INIT_CONFIG_YAML: Final = "- recommended\n" +INIT_CONFIG_YAML: Final = ( + "# XRLint configuration file\n" + "# See https://bcdev.github.io/xrlint/config/\n" + "\n" + "- recommended\n" +) DEFAULT_GLOBAL_FILES: Final = ["**/*.zarr", "**/*.nc"] DEFAULT_GLOBAL_IGNORES: Final = [".git", "node_modules"] diff --git a/xrlint/cli/main.py b/xrlint/cli/main.py index efac007..7a381ca 100644 --- a/xrlint/cli/main.py +++ b/xrlint/cli/main.py @@ -9,9 +9,9 @@ # Warning: do not import heavy stuff here, it can # slow down commands like "xrlint --help" otherwise. from xrlint.cli.constants import ( - DEFAULT_CONFIG_BASENAME, DEFAULT_MAX_WARNINGS, DEFAULT_OUTPUT_FORMAT, + DEFAULT_CONFIG_FILE_YAML, ) from xrlint.version import version @@ -20,17 +20,14 @@ @click.option( "--no-config-lookup", "no_config_lookup", - help=f"Disable use of default configuration from {DEFAULT_CONFIG_BASENAME}.*", + help="Disable use of default configuration files", is_flag=True, ) @click.option( "--config", "-c", "config_path", - help=( - f"Use this configuration, overriding {DEFAULT_CONFIG_BASENAME}.*" - f" config options if present" - ), + help="Use this configuration instead of looking for a default configuration file", metavar="FILE", ) @click.option( @@ -94,7 +91,7 @@ @click.option( "--init", "init_mode", - help="Write initial configuration file and exit.", + help=f"Write initial configuration file '{DEFAULT_CONFIG_FILE_YAML}' and exit.", is_flag=True, ) @click.argument("files", nargs=-1) @@ -115,22 +112,33 @@ def main( ): """Validate the given dataset FILES. - Reads configuration from './xrlint_config.*' if such file - exists and unless '--no-config-lookup' is set or '--config' is - provided. - It then validates each dataset in FILES against the configuration. + When executed, XRLint does the following three things: + + (1) Unless options '--no-config-lookup' or '--config' are used + it searches for a default configuration file in the current working + directory. Default configuration files are determined by their + filename, namely 'xrlint_config.py' or 'xrlint-config.', + where refers to the filename extensions + 'json', 'yaml', and 'yml'. A Python configuration file ('*.py'), + is expected to provide XRLInt configuration from a function + 'export_config()', which may include custom plugins and rules. + + (2) It then validates each dataset in FILES against the configuration. The default dataset patters are '**/*.zarr' and '**/.nc'. FILES may comprise also directories or URLs. The supported URL protocols are the ones supported by xarray. Using remote protocols may require installing additional packages such as S3Fs (https://s3fs.readthedocs.io/) for the 's3' protocol. - If a directory is provided that not matched by any file pattern, it will be traversed recursively. - The validation result is dumped to standard output if not otherwise + + (3) The validation result is dumped to standard output if not otherwise stated by '--output-file'. The output format is 'simple' by default. Other inbuilt formats are 'json' and 'html' which you can specify using the '--format' option. + + Please refer to the documentation (https://bcdev.github.io/xrlint/) + for more information. """ from xrlint.cli.engine import XRLint