diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 6d09fc58..75361ad1 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -67,7 +67,7 @@ jobs: - run: | mk python-release owner=vkottler \ - repo=runtimepy version=2.10.4 + repo=runtimepy version=2.11.0 if: | matrix.python-version == '3.11' && matrix.system == 'ubuntu-latest' diff --git a/README.md b/README.md index 9f73aaa5..28a6bcef 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ ===================================== generator=datazen version=3.1.3 - hash=e80a04d895371053de2f136293708ddb + hash=0d5b513fa5fde98a9fd6371397800b42 ===================================== --> -# runtimepy ([2.10.4](https://pypi.org/project/runtimepy/)) +# runtimepy ([2.11.0](https://pypi.org/project/runtimepy/)) [![python](https://img.shields.io/pypi/pyversions/runtimepy.svg)](https://pypi.org/project/runtimepy/) ![Build Status](https://github.com/vkottler/runtimepy/workflows/Python%20Package/badge.svg) diff --git a/local/variables/package.yaml b/local/variables/package.yaml index fcb93883..ced7da13 100644 --- a/local/variables/package.yaml +++ b/local/variables/package.yaml @@ -1,5 +1,5 @@ --- major: 2 -minor: 10 -patch: 4 +minor: 11 +patch: 0 entry: runtimepy diff --git a/pyproject.toml b/pyproject.toml index 3af4f0fb..380a1106 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta:__legacy__" [project] name = "runtimepy" -version = "2.10.4" +version = "2.11.0" description = "A framework for implementing Python services." readme = "README.md" requires-python = ">=3.11" diff --git a/runtimepy/__init__.py b/runtimepy/__init__.py index 8afda653..40c41bd1 100644 --- a/runtimepy/__init__.py +++ b/runtimepy/__init__.py @@ -1,7 +1,7 @@ # ===================================== # generator=datazen # version=3.1.3 -# hash=ecdca268d8d6298f7b49567a705b295e +# hash=75678e755b9ec7eac077dba7fa2c2be8 # ===================================== """ @@ -10,7 +10,7 @@ DESCRIPTION = "A framework for implementing Python services." PKG_NAME = "runtimepy" -VERSION = "2.10.4" +VERSION = "2.11.0" # runtimepy-specific content. METRICS_NAME = "metrics" diff --git a/runtimepy/channel/environment/command/__init__.py b/runtimepy/channel/environment/command/__init__.py index 16dcb041..1c5df7ca 100644 --- a/runtimepy/channel/environment/command/__init__.py +++ b/runtimepy/channel/environment/command/__init__.py @@ -174,3 +174,21 @@ def command(self, value: str) -> CommandResult: result = self.handle_command(args) return result + + +EnvironmentMap = dict[str, ChannelCommandProcessor] +ENVIRONMENTS: EnvironmentMap = {} + + +def clear_env() -> None: + """Reset the global environment mapping.""" + ENVIRONMENTS.clear() + + +def register_env(name: str, env: ChannelCommandProcessor) -> None: + """Register a channel environment globally.""" + + assert ( + name not in ENVIRONMENTS or ENVIRONMENTS[name] is env + ), f"Can't register environment '{name}'!" + ENVIRONMENTS[name] = env diff --git a/runtimepy/net/arbiter/base.py b/runtimepy/net/arbiter/base.py index 81490cf2..036f9427 100644 --- a/runtimepy/net/arbiter/base.py +++ b/runtimepy/net/arbiter/base.py @@ -23,6 +23,7 @@ from vcorelib.namespace import NamespaceMixin as _NamespaceMixin # internal +from runtimepy.channel.environment.command import clear_env, register_env from runtimepy.net.arbiter.housekeeping import metrics_poller from runtimepy.net.arbiter.info import AppInfo, ConnectionMap from runtimepy.net.arbiter.task import ( @@ -186,6 +187,13 @@ async def _entry( tasks = {x.name: x for x in self.task_manager.tasks} + # Register environments. + clear_env() + for task in tasks.values(): + register_env(task.name, task.command) + for name, conn in self._connections.items(): + register_env(name, conn.command) + # Run application, but only if all the registered connections are # still alive after initialization. if not check_connections or not any( diff --git a/runtimepy/net/arbiter/config.py b/runtimepy/net/arbiter/config.py index 2cf30e43..08fc9251 100644 --- a/runtimepy/net/arbiter/config.py +++ b/runtimepy/net/arbiter/config.py @@ -223,4 +223,7 @@ async def process_config( # Update application configuration data if necessary. if config.config is not None: + root = self._config["root"] self._config = config.config + assert "root" not in config.config, config.config + config.config["root"] = root diff --git a/runtimepy/net/stream/json/base.py b/runtimepy/net/stream/json/base.py index a7c4a3e8..8495db3d 100644 --- a/runtimepy/net/stream/json/base.py +++ b/runtimepy/net/stream/json/base.py @@ -16,10 +16,7 @@ # internal from runtimepy import PKG_NAME, VERSION -from runtimepy.channel.environment.command import ( - ChannelCommandProcessor, - FieldOrChannel, -) +from runtimepy.channel.environment.command import ENVIRONMENTS, FieldOrChannel from runtimepy.channel.environment.command.result import CommandResult from runtimepy.net.stream.json.handlers import ( ChannelCommand, @@ -55,10 +52,11 @@ def _register_handlers(self) -> None: # Extra handlers. self.typed_handler("find_file", FindFile, find_file_request_handler) self.typed_handler( - "channel_command", ChannelCommand, channel_env_handler(self.envs) + "channel_command", + ChannelCommand, + channel_env_handler(ENVIRONMENTS, self.command), ) - envs: dict[str, ChannelCommandProcessor] outgoing_commands: asyncio.Queue[ChannelCommandParams] async def process_command_queue(self) -> None: @@ -104,7 +102,6 @@ def init(self) -> None: "kind": type(self).__name__, } - self.envs = {"default": self.command} self.command.hooks.append(self._handle_remote_command) self.curr_id: int = 1 diff --git a/runtimepy/net/stream/json/handlers.py b/runtimepy/net/stream/json/handlers.py index 956bddb0..04afd863 100644 --- a/runtimepy/net/stream/json/handlers.py +++ b/runtimepy/net/stream/json/handlers.py @@ -24,7 +24,7 @@ class ChannelCommand(RuntimepyDictCodec, BasicDictCodec): def channel_env_handler( - envs: dict[str, ChannelCommandProcessor] + envs: dict[str, ChannelCommandProcessor], default: ChannelCommandProcessor ) -> TypedHandler[ChannelCommand]: """Create a channel-environment map command handler.""" @@ -36,9 +36,13 @@ async def handler(outbox: JsonMessage, request: ChannelCommand) -> None: env_name = request.data["environment"] + env = envs.get(env_name) + if env_name == "default": + env = default + # Run the command if we have the environment. - if env_name in envs: - result = envs[env_name].command(request.data["command"]) + if env is not None: + result = env.command(request.data["command"]) outbox["success"] = result.success outbox["reason"] = result.reason diff --git a/tests/net/arbiter/test_config.py b/tests/net/arbiter/test_config.py index fb17d285..50900dd9 100644 --- a/tests/net/arbiter/test_config.py +++ b/tests/net/arbiter/test_config.py @@ -53,6 +53,8 @@ async def echo_test_app(app: AppInfo) -> int: """Test some of the echo connections.""" # Ensure that configuration data got set correctly. + if "root" in app.config: + del app.config["root"] assert app.config == {"a": 1, "b": 2, "c": 3} assert len(list(app.search(pattern="sample"))) == 3