From 96fd1ddbbbea7c94f6f80a6462c54d4718e1b2f7 Mon Sep 17 00:00:00 2001 From: Ian Ward Date: Wed, 8 May 2024 12:51:23 -0400 Subject: [PATCH 1/9] [#8219] plugins_update only with plugins changes --- ckan/plugins/core.py | 12 +++++++++--- ckan/tests/config/test_environment.py | 3 +-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ckan/plugins/core.py b/ckan/plugins/core.py index 732640e9746..e8df039c49c 100644 --- a/ckan/plugins/core.py +++ b/ckan/plugins/core.py @@ -23,6 +23,7 @@ from ckan.common import config from ckan.types import SignalMapping from ckan.exceptions import CkanDeprecationWarning +from ckan.logic import get_validator __all__ = [ @@ -221,7 +222,8 @@ def load_all() -> None: # Clear any loaded plugins unload_all() - plugins = config.get('ckan.plugins') + find_system_plugins() + as_list = get_validator('as_list') + plugins = as_list(config.get('ckan.plugins')) + find_system_plugins() load(*plugins) @@ -254,7 +256,9 @@ def load( if interfaces.ISignal.implemented_by(service.__class__): _connect_signals(service.get_signal_subscriptions()) output.append(service) - plugins_update() + + if plugins: + plugins_update() # Return extension instance if only one was loaded. If more that one # has been requested then a list of instances is returned in the order @@ -301,7 +305,9 @@ def unload(*plugins: str) -> None: for observer_plugin in observers: observer_plugin.after_unload(service) - plugins_update() + + if plugins: + plugins_update() def plugin_loaded(name: str) -> bool: diff --git a/ckan/tests/config/test_environment.py b/ckan/tests/config/test_environment.py index 5b60df2b27c..7c8b5a02be3 100644 --- a/ckan/tests/config/test_environment.py +++ b/ckan/tests/config/test_environment.py @@ -43,8 +43,7 @@ def test_update_config_env_vars(ckan_config): """ for env_var, value in ENV_VAR_LIST: os.environ.setdefault(env_var, value) - # plugin.load() will force the config to update - p.load() + p.plugins_update() assert ckan_config[u"solr_url"] == u"http://mynewsolrurl/solr" assert ckan_config[u"sqlalchemy.url"] == u"postgresql://mynewsqlurl/" From b35e05fa7fee5c3aa63da644fc5d4039d8fc3368 Mon Sep 17 00:00:00 2001 From: Ian Ward Date: Wed, 8 May 2024 13:39:06 -0400 Subject: [PATCH 2/9] [#8219] fix docs circular import, changes file --- changes/8219.feature | 1 + ckan/plugins/core.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changes/8219.feature diff --git a/changes/8219.feature b/changes/8219.feature new file mode 100644 index 00000000000..dc8175b8a8d --- /dev/null +++ b/changes/8219.feature @@ -0,0 +1 @@ +Improved start-up performance diff --git a/ckan/plugins/core.py b/ckan/plugins/core.py index e8df039c49c..029287307dc 100644 --- a/ckan/plugins/core.py +++ b/ckan/plugins/core.py @@ -23,7 +23,6 @@ from ckan.common import config from ckan.types import SignalMapping from ckan.exceptions import CkanDeprecationWarning -from ckan.logic import get_validator __all__ = [ @@ -222,6 +221,7 @@ def load_all() -> None: # Clear any loaded plugins unload_all() + from ckan.logic import get_validator as_list = get_validator('as_list') plugins = as_list(config.get('ckan.plugins')) + find_system_plugins() From 44633e58003e8d33c65d1ad83ff186e316709e45 Mon Sep 17 00:00:00 2001 From: Ian Ward Date: Wed, 8 May 2024 14:27:01 -0400 Subject: [PATCH 3/9] [#8219] pyright --- ckan/plugins/core.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ckan/plugins/core.py b/ckan/plugins/core.py index 029287307dc..aad70eb9b49 100644 --- a/ckan/plugins/core.py +++ b/ckan/plugins/core.py @@ -20,7 +20,7 @@ import ckan.plugins.interfaces as interfaces -from ckan.common import config +from ckan.common import config, aslist from ckan.types import SignalMapping from ckan.exceptions import CkanDeprecationWarning @@ -221,9 +221,7 @@ def load_all() -> None: # Clear any loaded plugins unload_all() - from ckan.logic import get_validator - as_list = get_validator('as_list') - plugins = as_list(config.get('ckan.plugins')) + find_system_plugins() + plugins = aslist(config.get('ckan.plugins')) + find_system_plugins() load(*plugins) From 97daf18f9faa5c890ce10942c6cae1453641ad0a Mon Sep 17 00:00:00 2001 From: Ian Ward Date: Wed, 8 May 2024 18:56:24 -0400 Subject: [PATCH 4/9] [#8219] cli: skip make_app for --help --- ckan/cli/cli.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ckan/cli/cli.py b/ckan/cli/cli.py index 9835c3b692b..0f3a56e5a56 100644 --- a/ckan/cli/cli.py +++ b/ckan/cli/cli.py @@ -76,7 +76,8 @@ def format_commands( # provided, except for `--help`. In this case it has to be done # manually. if not ctx.obj: - _add_ctx_object(ctx) + if '-h' not in sys.argv[1:] and '--help' not in sys.argv[1:]: + _add_ctx_object(ctx) _add_external_commands(ctx) commands = [] @@ -127,7 +128,8 @@ def parse_args(self, ctx: click.Context, args: list[str]): def _init_ckan_config(ctx: click.Context, param: str, value: str): if any(sys.argv[1:len(cmd) + 1] == cmd for cmd in _no_config_commands): return - _add_ctx_object(ctx, value) + if '-h' not in sys.argv[1:] and '--help' not in sys.argv[1:]: + _add_ctx_object(ctx, value) _add_external_commands(ctx) From 42a62ae19e684b44b46502fa1f23303a59d1e1a9 Mon Sep 17 00:00:00 2001 From: Ian Ward Date: Thu, 9 May 2024 15:49:30 -0400 Subject: [PATCH 5/9] [#8219] update js translations only when required --- ckan/cli/server.py | 6 +++++- ckan/config/environment.py | 5 ----- doc/maintaining/installing/deployment.rst | 19 +++++++++++++++++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/ckan/cli/server.py b/ckan/cli/server.py index 190c72ea1c4..425a184f3a1 100644 --- a/ckan/cli/server.py +++ b/ckan/cli/server.py @@ -12,6 +12,7 @@ from ckan.common import config from . import error_shout +from ckan.lib.i18n import build_js_translations log = logging.getLogger(__name__) @@ -59,7 +60,7 @@ def run(ctx: click.Context, host: str, port: str, disable_reloader: bool, passthrough_errors: bool, disable_debugger: bool, threaded: bool, extra_files: list[str], processes: int, ssl_cert: Optional[str], ssl_key: Optional[str], prefix: Optional[str]): - u"""Runs the Werkzeug development server""" + """Regenerate JS translations and run the Werkzeug development server""" if config.get("debug"): warnings.filterwarnings("default", category=CkanDeprecationWarning) @@ -115,6 +116,9 @@ def run(ctx: click.Context, host: str, port: str, disable_reloader: bool, error_shout(u"Server port must be an integer, not {}".format(port)) raise click.Abort() + # Once automatic on startup, run only here for faster debug iterations + build_js_translations() + log.info(u"Running CKAN on {scheme}://{host}:{port}{prefix}".format( scheme='https' if ssl_context else 'http', host=host, port=port_int, prefix=prefix)) diff --git a/ckan/config/environment.py b/ckan/config/environment.py index 26b51edae2e..9de9e7cf09e 100644 --- a/ckan/config/environment.py +++ b/ckan/config/environment.py @@ -22,7 +22,6 @@ import ckan.logic as logic import ckan.authz as authz from ckan.lib.webassets_tools import webassets_init, register_core_assets -from ckan.lib.i18n import build_js_translations from ckan.common import CKANConfig, config, config_declaration from ckan.exceptions import CkanConfigurationException @@ -74,10 +73,6 @@ def load_environment(conf: Union[Config, CKANConfig]): app_globals.reset() - # Build JavaScript translations. Must be done after plugins have - # been loaded. - build_js_translations() - # A mapping of config settings that can be overridden by env vars. # Note: Do not remove the following lines, they are used in the docs diff --git a/doc/maintaining/installing/deployment.rst b/doc/maintaining/installing/deployment.rst index 6fc505f83ac..0695ee1c27b 100644 --- a/doc/maintaining/installing/deployment.rst +++ b/doc/maintaining/installing/deployment.rst @@ -198,8 +198,23 @@ To prevent conflicts, disable your default nginx sites and restart: sudo ln -s |nginx_config_file| /etc/nginx/sites-enabled/ckan |restart_nginx| + +----------------------------------- +7. Generate JavaScript Translations +----------------------------------- + +Some front-end features require translated strings from CKAN and its +extensions. Run this command once to extract and make these +strings available after initial installation, upgrades, enabling new +plugins or enabling new languages. + +.. parsed-literal:: + + ckan -c |ckan.ini| translation js + + ------------------------ -7. Access your CKAN site +8. Access your CKAN site ------------------------ @@ -208,7 +223,7 @@ CKAN instance. -------------------------------------- -8. Setup a worker for background jobs +9. Setup a worker for background jobs -------------------------------------- CKAN uses asynchronous :ref:`background jobs` for long tasks. These jobs are executed by a separate process which is called a :ref:`worker Date: Sun, 12 May 2024 10:02:30 -0400 Subject: [PATCH 6/9] [#8219] msgspec for faster yaml parsing --- ckan/config/declaration/load.py | 6 +++--- requirements.in | 1 + requirements.txt | 10 +++------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/ckan/config/declaration/load.py b/ckan/config/declaration/load.py index a998f5fab46..e52fb16dea7 100644 --- a/ckan/config/declaration/load.py +++ b/ckan/config/declaration/load.py @@ -25,7 +25,7 @@ def load_from_custom(declaration, *args, **kwargs): import pathlib from typing import TYPE_CHECKING, Any, Callable, Dict, List from typing_extensions import TypedDict -import yaml +import msgspec from .key import Key from .option import Flag, Option @@ -156,6 +156,6 @@ def load_core(declaration: "Declaration"): """Load core declarations. """ source = pathlib.Path(__file__).parent / ".." / "config_declaration.yaml" - with source.open("r") as stream: - data = yaml.safe_load(stream) + with source.open("rb") as stream: + data = msgspec.yaml.decode(stream.read()) load_dict(declaration, data) diff --git a/requirements.in b/requirements.in index 7f728704cf6..20682acd1a1 100644 --- a/requirements.in +++ b/requirements.in @@ -37,3 +37,4 @@ tzlocal==5.2 webassets==2.0 Werkzeug[watchdog]==3.0.2 zope.interface==6.2 +msgspec==0.18.6 diff --git a/requirements.txt b/requirements.txt index 33224ec6882..cb63c2e7d5c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.9 +# This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile requirements.in @@ -51,10 +51,6 @@ greenlet==3.0.3 # via sqlalchemy idna==3.7 # via requests -importlib-metadata==7.1.0 - # via - # flask - # markdown itsdangerous==2.2.0 # via # flask @@ -76,6 +72,8 @@ markupsafe==2.1.5 # mako # werkzeug # wtforms +msgspec==0.18.6 + # via -r requirements.in mypy==1.9.0 # via sqlalchemy mypy-extensions==1.0.0 @@ -160,8 +158,6 @@ werkzeug[watchdog]==3.0.2 # werkzeug wtforms==3.1.2 # via flask-wtf -zipp==3.18.1 - # via importlib-metadata zope-interface==6.2 # via -r requirements.in From be9d5a6820cb9a14922edb1ae09ca8dcff577f5b Mon Sep 17 00:00:00 2001 From: Ian Ward Date: Thu, 16 May 2024 13:41:50 -0400 Subject: [PATCH 7/9] improved feature description changes/8219.feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: AdriĆ  Mercader --- changes/8219.feature | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/changes/8219.feature b/changes/8219.feature index dc8175b8a8d..544268dfa5d 100644 --- a/changes/8219.feature +++ b/changes/8219.feature @@ -1 +1,2 @@ -Improved start-up performance +- Improved start-up performance +- JS translations are no longer generated on each server restart. The are built when starting the development server with `ckan run` or explicitly with `ckan translations js` From 0feff543a1f50b381990d40a44fbf11e91473022 Mon Sep 17 00:00:00 2001 From: Ian Ward Date: Thu, 16 May 2024 14:34:32 -0400 Subject: [PATCH 8/9] [#8219] revert unrelated requirements.txt changes --- requirements.txt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index b84337d65f7..150ecc65f03 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.10 +# This file is autogenerated by pip-compile with Python 3.9 # by the following command: # # pip-compile requirements.in @@ -54,6 +54,10 @@ greenlet==3.0.3 # via sqlalchemy idna==3.7 # via requests +importlib-metadata==7.1.0 + # via + # flask + # markdown itsdangerous==2.2.0 # via # flask @@ -76,7 +80,9 @@ markupsafe==2.1.5 # werkzeug # wtforms msgspec==0.18.6 - # via -r requirements.in + # via + # -r requirements.in + # flask-session mypy==1.9.0 # via sqlalchemy mypy-extensions==1.0.0 @@ -161,6 +167,8 @@ werkzeug[watchdog]==3.0.3 # werkzeug wtforms==3.1.2 # via flask-wtf +zipp==3.18.1 + # via importlib-metadata zope-interface==6.2 # via -r requirements.in From 6bbbfd8e04f676742bda503311ef9a82f1c4f26f Mon Sep 17 00:00:00 2001 From: amercader Date: Fri, 17 May 2024 13:16:24 +0200 Subject: [PATCH 9/9] [#8219] lint --- ckan/plugins/core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ckan/plugins/core.py b/ckan/plugins/core.py index ec648fce99d..20e49402b9e 100644 --- a/ckan/plugins/core.py +++ b/ckan/plugins/core.py @@ -219,10 +219,11 @@ def unload(*plugins: str) -> None: if implemented_by(service, interfaces.ISignal): _disconnect_signals(service.get_signal_subscriptions()) - + if plugins: plugins_update() + def plugin_loaded(name: str) -> bool: ''' See if a particular plugin is loaded.