diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f2daabf..6f2061f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [UNRELEASED] - YYYY-MM-DD +### Fixed +- [#482](https://github.com/equinor/webviz-config/pull/482) - Reverted the assumption +made in [#419](https://github.com/equinor/webviz-config/pull/419) that all argument +section in init-docstrings are lists of argument descriptions, and separated deprecated +plugins and arguments in doc sidebar. ## [0.3.3] - 2021-07-13 @@ -32,7 +37,7 @@ button to `WebvizPluginABC`. - [#463](https://github.com/equinor/webviz-config/pull/463) - Reflect external change. Repository name for standard `OAuth2` Docker containers is changed from `quay.io/pusher/oauth2_proxy` to `quay.io/oauth2-proxy/oauth2-proxy`. -- [#440](https://github.com/equinor/webviz-config/pull/440) - Fixed setting of global +- [#440](https://github.com/equinor/webviz-config/pull/440) - Fixed setting of global log level for webviz application. - [#457](https://github.com/equinor/webviz-config/pull/457) - Use non-root `redis` Docker image in generated Radix setup. @@ -53,7 +58,7 @@ from `deprecated_plugin` decorator. ### Added - [#419](https://github.com/equinor/webviz-config/pull/419) - Plugins and their -arguments can now be marked as deprecated by using the newly implemented +arguments can now be marked as deprecated by using the newly implemented deprecation framework that, in addition to console FutureWarnings, automatically shows deprecation messages to the end user in the app and in the documentation. Adjusted contributing guide accordingly. @@ -96,7 +101,7 @@ See also [#392](https://github.com/equinor/webviz-config/pull/392) ## [0.2.8] - 2021-01-26 ### Added -- [#345](https://github.com/equinor/webviz-config/pull/345) - Added Oauth2 +- [#345](https://github.com/equinor/webviz-config/pull/345) - Added Oauth2 Authorization Code flow support for Azure AD applications. ### Changed @@ -115,7 +120,7 @@ for multiple versions of same plugin if the metadata is equal. ### Changed - [#368](https://github.com/equinor/webviz-config/pull/368) - Made Webviz global -settings available to plugin implementations through special `webviz_settings` +settings available to plugin implementations through special `webviz_settings` argument. This argument is an instance of the `WebvizSettings` class and currently contains both the `shared_settings` and `theme` properties. @@ -127,14 +132,14 @@ plugins as the special `app` argument) has been deprecated. ## [0.2.6] - 2021-01-07 ### Fixed -- [#373](https://github.com/equinor/webviz-config/pull/373) - Fix for import of TypedDict +- [#373](https://github.com/equinor/webviz-config/pull/373) - Fix for import of TypedDict in Python versions older than 3.8. Check against Python version instead of using try-except. ## [0.2.5] - 2020-12-19 ### Changed - [#367](https://github.com/equinor/webviz-config/pull/367) - Made type information -available to package consumers by indicating support for typing as specified in +available to package consumers by indicating support for typing as specified in [PEP 561](https://www.python.org/dev/peps/pep-0561/). ## [0.2.4] - 2020-12-08 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e6004de4..4ae4ff9c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -442,13 +442,13 @@ instance representing the absolute path to the configuration file that was used, a boolean value stating if the Webviz application running is a portable one. The (optionally transformed) `shared_settings` can be retrieved in a plugin by adding -a specially named `webviz_settings` argument to the plugin's `__init__` function. The -`webviz_settings` argument works similar to the `app` argument in that it is a special -argument name that will not be originating from the configuration file, but will be -automatically given to the plugin by the core functionality of webviz-config. +a specially named `webviz_settings` argument to the plugin's `__init__` function. The +`webviz_settings` argument works similar to the `app` argument in that it is a special +argument name that will not be originating from the configuration file, but will be +automatically given to the plugin by the core functionality of webviz-config. -Shared settings can then be accessed through `webviz_settings`. E.g., in the case -above, the wanted settings are found as `webviz_settings.shared_settings["some_key"]` +Shared settings can then be accessed through `webviz_settings`. E.g., in the case +above, the wanted settings are found as `webviz_settings.shared_settings["some_key"]` as shown in the example below: ```python @@ -469,8 +469,8 @@ class ExamplePlugin(WebvizPluginABC): ### OAuth 2.0 Authorization Code flow -It is possible to use OAuth 2.0 Authorization Code flow to secure a `webviz` application. -In order to do so, add `oauth2` attribute in a custom plugin with a boolean `True` value. +It is possible to use OAuth 2.0 Authorization Code flow to secure a `webviz` application. +In order to do so, add `oauth2` attribute in a custom plugin with a boolean `True` value. The following is an example. ```python @@ -485,8 +485,8 @@ class OurCustomPlugin(WebvizPluginABC): return self.use_oauth2 ``` -Information related to the application for OAuth 2.0 has to be provided in environment -variables. These environment variables are `WEBVIZ_TENANT_ID`, `WEBVIZ_CLIENT_ID`, +Information related to the application for OAuth 2.0 has to be provided in environment +variables. These environment variables are `WEBVIZ_TENANT_ID`, `WEBVIZ_CLIENT_ID`, `WEBVIZ_CLIENT_SECRET`, `WEBVIZ_SCOPE`. The values can be found in the Azure AD configuration page. Short explanation of these environment variables: @@ -631,7 +631,7 @@ class MyPluginExample1(WebvizPluginABC): @deprecated_plugin_arguments( { "arg3": ( - "Short message shown to the end user both in the app and documentation.", + "Short message shown to the end user both in the app and documentation.", ( "This can be a long message, which is shown only in the documentation, explaining " "e.g. why it is deprecated and which plugin should be used instead." @@ -642,14 +642,14 @@ class MyPluginExample1(WebvizPluginABC): def __init__(self, arg1: str, arg2: int, arg3: Optional[int] = None): ... -class MyPluginExample2(WebvizPluginABC): - ... - @deprecated_plugin_arguments(check_deprecation) - def __init__(self, arg1: str, arg2: int, arg3: Optional[int] = None): - ... - -def check_deprecation(arg1: int, arg3: int) -> Optional[Tuple[str, str]]: +def check_deprecation_example2(arg1: int, arg3: int) -> Optional[Tuple[str, str]]: if arg3 == arg1: return ("This message is shown to the end user in the app.", "This message is shown in the documentation of the plugin.") return None + +class MyPluginExample2(WebvizPluginABC): + ... + @deprecated_plugin_arguments(check_deprecation_example2) + def __init__(self, arg1: int, arg2: int, arg3: int): + ... ``` diff --git a/webviz_config/_config_parser.py b/webviz_config/_config_parser.py index a1d77cb3..2e80eb29 100644 --- a/webviz_config/_config_parser.py +++ b/webviz_config/_config_parser.py @@ -121,13 +121,14 @@ def _call_signature( pass kwargs_including_defaults = kwargs - deprecation_warnings = [] + plugin_deprecation_warnings = [] + argument_deprecation_warnings = [] deprecated_plugin = _ds.DEPRECATION_STORE.get_stored_plugin_deprecation( getattr(webviz_config.plugins, plugin_name) ) if deprecated_plugin: - deprecation_warnings.append(deprecated_plugin.short_message) + plugin_deprecation_warnings.append(deprecated_plugin.short_message) warnings.warn( f"""Plugin '{plugin_name}' has been deprecated. ------------------------ @@ -150,7 +151,7 @@ def _call_signature( for deprecation in deprecations: if isinstance(deprecation, _ds.DeprecatedArgument): if deprecation.argument_name in kwargs_including_defaults.keys(): - deprecation_warnings.append(deprecation.short_message) + argument_deprecation_warnings.append(deprecation.short_message) warnings.warn( """Deprecated Argument: '{}' with value '{}' in plugin '{}' ------------------------ @@ -176,7 +177,7 @@ def _call_signature( result = deprecation.callback(**mapped_args) # type: ignore if result: - deprecation_warnings.append(result[0]) + argument_deprecation_warnings.append(result[0]) warnings.warn( """Deprecated Argument(s): '{}' with value(s) '{}' in plugin '{}' ------------------------ @@ -207,7 +208,8 @@ def _call_signature( f"{plugin_name}({special_args}**{kwargs})", ( f"plugin_layout(contact_person={contact_person}" - f", deprecation_warnings={deprecation_warnings})" + f", plugin_deprecation_warnings={plugin_deprecation_warnings}" + f", argument_deprecation_warnings={argument_deprecation_warnings})" ), ) diff --git a/webviz_config/_docs/_build_docs.py b/webviz_config/_docs/_build_docs.py index f2ee6f7d..5a618421 100644 --- a/webviz_config/_docs/_build_docs.py +++ b/webviz_config/_docs/_build_docs.py @@ -17,7 +17,6 @@ from importlib import import_module from collections import defaultdict from typing import Any, Dict, Optional, Tuple, List -import re try: @@ -86,24 +85,15 @@ def _find_plugin_deprecated_arguments(plugin: Any) -> Dict[str, Tuple[str, str]] def _extract_init_arguments_and_check_for_deprecation( - docstring: Optional[str], reference: Any + reference: Any, ) -> Tuple[bool, Dict[str, ArgumentInfo], str]: """Returns all arguments of the given class' __init__ function including related documentation strings, typehints and deprecation information. """ result: Dict[str, ArgumentInfo] = {} deprecated_arguments = _find_plugin_deprecated_arguments(reference) - regex = ( - "(\\* \\*\\*`([a-zA-Z0-9_]+)`:\\*\\*)((.|\\n|\\r)+?)" - "((?=\\* \\*\\*`([a-zA-Z0-9_]+)`:\\*\\*)|$)" - ) - documented_args: Dict[str, str] = {} deprecation_check_code = "" - if docstring: - for match in re.finditer(regex, docstring): - documented_args[match.group(2)] = match.group(3) - argspec = inspect.getfullargspec(reference.__init__) result = {arg: ArgumentInfo() for arg in argspec.args if arg not in SPECIAL_ARGS} @@ -126,8 +116,6 @@ def _extract_init_arguments_and_check_for_deprecation( result[arg]["typehint_string"] = _annotation_to_string(annotation) for arg, arg_info in result.items(): - arg_info["description"] = " ".join(documented_args.get(arg, "").split()) - if arg in deprecated_arguments: arg_info["deprecated"] = True arg_info["deprecation_message"] = deprecated_arguments[arg][0] @@ -155,9 +143,7 @@ def _document_plugin(plugin: Tuple[str, Any]) -> PluginInfo: has_deprecated_arguments, arguments, deprecation_check_code, - ) = _extract_init_arguments_and_check_for_deprecation( - docstring_parts[1] if len(docstring_parts) > 1 else None, reference - ) + ) = _extract_init_arguments_and_check_for_deprecation(reference) deprecated = _ds.DEPRECATION_STORE.get_stored_plugin_deprecation(reference) plugin_info: PluginInfo = { @@ -242,14 +228,13 @@ def build_docs(build_directory: pathlib.Path) -> None: plugin_documentation = get_plugin_documentation() - deprecated_packages = {} + has_deprecated_plugins = {} + has_deprecated_arguments = {} for dist_name, package_doc in plugin_documentation.items(): - if any( - plugin["deprecated"] or plugin["has_deprecated_arguments"] - for plugin in package_doc["plugins"] - ): - deprecated_packages[dist_name] = package_doc - + if any(plugin["deprecated"] for plugin in package_doc["plugins"]): + has_deprecated_plugins[dist_name] = package_doc + if any(plugin["has_deprecated_arguments"] for plugin in package_doc["plugins"]): + has_deprecated_arguments[dist_name] = package_doc template = template_environment.get_template("README.md.jinja2") for dist_name, package_doc in plugin_documentation.items(): (build_directory / f"{dist_name}.md").write_text( @@ -261,7 +246,8 @@ def build_docs(build_directory: pathlib.Path) -> None: template.render( { "packages": plugin_documentation.keys(), - "deprecated_plugins": bool(deprecated_packages), + "deprecated_plugins": bool(has_deprecated_plugins), + "deprecated_arguments": bool(has_deprecated_arguments), } ) ) @@ -273,9 +259,13 @@ def build_docs(build_directory: pathlib.Path) -> None: ) ) - template = template_environment.get_template("deprecations.md.jinja2") - (build_directory / "deprecations.md").write_text( - template.render({"packages": deprecated_packages}) + template = template_environment.get_template("plugin_deprecations.md.jinja2") + (build_directory / "plugin_deprecations.md").write_text( + template.render({"packages": has_deprecated_plugins}) + ) + template = template_environment.get_template("argument_deprecations.md.jinja2") + (build_directory / "argument_deprecations.md").write_text( + template.render({"packages": has_deprecated_arguments}) ) diff --git a/webviz_config/_plugin_abc.py b/webviz_config/_plugin_abc.py index bf21e387..fdc59216 100644 --- a/webviz_config/_plugin_abc.py +++ b/webviz_config/_plugin_abc.py @@ -175,7 +175,8 @@ def plugin_data_compress(content: List[ZipFileMember]) -> EncodedFile: def _make_extended_deprecation_warnings( self, - deprecation_warnings: Optional[List[str]] = None, + plugin_deprecation_warnings: Optional[List[str]] = None, + argument_deprecation_warnings: Optional[List[str]] = None, ) -> List[Dict[str, str]]: # pylint: disable=import-outside-toplevel from .plugins import PLUGIN_METADATA, PLUGIN_PROJECT_METADATA @@ -186,16 +187,27 @@ def _make_extended_deprecation_warnings( dist_name = PLUGIN_METADATA[plugin_name]["dist_name"] metadata = PLUGIN_PROJECT_METADATA[dist_name] - if deprecation_warnings: + if plugin_deprecation_warnings: url = ( - f"{metadata['documentation_url']}/#/deprecations?id={plugin_name.lower()}" + f"{metadata['documentation_url']}/#/plugin_deprecations?id={plugin_name.lower()}" if metadata["documentation_url"] is not None else "" ) - for deprecation_warning in deprecation_warnings: + for plugin_deprecation_warning in plugin_deprecation_warnings: extended_deprecation_warnings.append( - {"message": deprecation_warning, "url": url} + {"message": plugin_deprecation_warning, "url": url} + ) + if argument_deprecation_warnings: + url = ( + f"{metadata['documentation_url']}/#/argument_deprecations?id={plugin_name.lower()}" + if metadata["documentation_url"] is not None + else "" + ) + + for argument_deprecation_warning in argument_deprecation_warnings: + extended_deprecation_warnings.append( + {"message": argument_deprecation_warning, "url": url} ) return extended_deprecation_warnings @@ -230,7 +242,8 @@ def _make_feedback_url(self) -> str: def plugin_layout( self, contact_person: Optional[dict] = None, - deprecation_warnings: Optional[List[str]] = None, + plugin_deprecation_warnings: Optional[List[str]] = None, + argument_deprecation_warnings: Optional[List[str]] = None, ) -> Union[str, Type[Component]]: """This function returns (if the class constant SHOW_TOOLBAR is True, the plugin layout wrapped into a common webviz config plugin @@ -256,7 +269,7 @@ def plugin_layout( if self._add_download_button: buttons.append("download") - if buttons or deprecation_warnings: + if buttons or plugin_deprecation_warnings or argument_deprecation_warnings: # pylint: disable=no-member return wcc.WebvizPluginPlaceholder( id=self._plugin_wrapper_id, @@ -270,7 +283,7 @@ def plugin_layout( if "guided_tour" in buttons and hasattr(self, "tour_steps") else [], deprecation_warnings=self._make_extended_deprecation_warnings( - deprecation_warnings + plugin_deprecation_warnings, argument_deprecation_warnings ), feedback_url=self._make_feedback_url(), ) diff --git a/webviz_config/templates/README.md.jinja2 b/webviz_config/templates/README.md.jinja2 index 16bd192d..b78511b2 100644 --- a/webviz_config/templates/README.md.jinja2 +++ b/webviz_config/templates/README.md.jinja2 @@ -1,74 +1,12 @@ # Plugin project {{ dist_name }} -?> :bookmark: This documentation is valid for version `{{ package_doc["dist_version"] }}` of `{{ dist_name}}`. +?> :bookmark: This documentation is valid for version `{{ package_doc["dist_version"] }}` of `{{ dist_name}}`. -{% if package_doc["doc"] is not none %} +{% if package_doc["doc"] is not none %} {{ package_doc["doc"] }} -{% endif %} - ---- - -{% for plugin in package_doc["plugins"] %} - -