From 557b6cb686a64dfc416190565a0e192e073fa766 Mon Sep 17 00:00:00 2001 From: Sijis Aviles Date: Sun, 12 Oct 2025 23:16:35 -0600 Subject: [PATCH 1/5] chore: updated sphinx version --- docs/conf.py | 1 - docs/requirements.txt | 4 +--- .../testing_plugins_fullstack.rst | 12 ++++++------ .../plugin_development/threaded_replies.rst | 18 +++++++++--------- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 5f7bed142..d69dc2b84 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -38,7 +38,6 @@ extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.viewcode', - 'sphinx_autodoc_annotation', ] # Add any paths that contain templates here, relative to this directory. diff --git a/docs/requirements.txt b/docs/requirements.txt index 6ba2c7197..c63762b6f 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,6 +1,4 @@ -sphinx>=1.2 - -sphinx-autodoc-annotation +sphinx>=8.2.3 -e . hypchat diff --git a/docs/user_guide/plugin_development/testing_plugins_fullstack.rst b/docs/user_guide/plugin_development/testing_plugins_fullstack.rst index 3e74989ef..11304611e 100644 --- a/docs/user_guide/plugin_development/testing_plugins_fullstack.rst +++ b/docs/user_guide/plugin_development/testing_plugins_fullstack.rst @@ -4,7 +4,7 @@ Testing your plugins with unittest This guide explains how to test your Errbot plugins using the built-in testing framework. Errbot provides a powerful testing backend called ``FullStackTest`` that allows you to write unit tests for your plugins in a familiar unittest style. Basic Test Setup --------------- +---------------- To test your plugin, create a test file (e.g., `test_myplugin.py`) in your plugin's directory. Here's a basic example: @@ -29,7 +29,7 @@ To test your plugin, create a test file (e.g., `test_myplugin.py`) in your plugi self.assertIn('Hello!', self.pop_message()) Running Tests ------------- +------------- You can run your tests using Python's unittest framework: @@ -38,7 +38,7 @@ You can run your tests using Python's unittest framework: python -m unittest test_myplugin.py Test Methods ------------ +------------ FullStackTest provides several methods to help test your plugin's behavior: @@ -59,7 +59,7 @@ FullStackTest provides several methods to help test your plugin's behavior: - Test plugin dependencies Example Test Cases ----------------- +------------------ Here are some example test cases showing different testing scenarios: @@ -105,7 +105,7 @@ Here are some example test cases showing different testing scenarios: self.assertIn('Mock response', self.pop_message()) Best Practices -------------- +-------------- 1. **Test Isolation**: Each test should be independent and not rely on the state from other tests. @@ -118,7 +118,7 @@ Best Practices 5. **Documentation**: Document your test cases to explain what they're testing and why. Complete Example --------------- +---------------- Here's a complete example of a test suite for a plugin: diff --git a/docs/user_guide/plugin_development/threaded_replies.rst b/docs/user_guide/plugin_development/threaded_replies.rst index 0794c10aa..e9c06edc6 100644 --- a/docs/user_guide/plugin_development/threaded_replies.rst +++ b/docs/user_guide/plugin_development/threaded_replies.rst @@ -1,10 +1,10 @@ Threaded Replies -=============== +================ Errbot supports threaded replies, which allows bot responses to be organized in conversation threads when the backend supports this feature. This is particularly useful for maintaining context in group chats and keeping related messages together. Enabling Threaded Replies ------------------------- +------------------------- There are two ways to enable threaded replies in Errbot: @@ -12,7 +12,7 @@ There are two ways to enable threaded replies in Errbot: 2. Globally for specific commands using the `DIVERT_TO_THREAD` configuration Per-command Threaded Replies ---------------------------- +---------------------------- You can send a threaded reply to any message using the `in_reply_to` parameter in `send`: @@ -27,7 +27,7 @@ You can send a threaded reply to any message using the `in_reply_to` parameter i self.send(msg.frm, "This is a threaded response", in_reply_to=msg) Global Thread Configuration -------------------------- +--------------------------- You can configure Errbot to automatically send responses in threads for specific commands by adding them to the `DIVERT_TO_THREAD` configuration in your config.py: @@ -40,7 +40,7 @@ You can configure Errbot to automatically send responses in threads for specific DIVERT_TO_THREAD = ("ALL_COMMANDS",) Backend Support --------------- +--------------- Threaded replies are supported by the following backends: @@ -52,7 +52,7 @@ Threaded replies are supported by the following backends: Note that not all backends support threaded replies. If a backend doesn't support threading, the message will be sent as a regular message. Best Practices -------------- +-------------- 1. Use threaded replies for: - Long conversations that need to maintain context @@ -66,7 +66,7 @@ Best Practices - Debug information Example Plugin -------------- +-------------- Here's a complete example of a plugin that demonstrates threaded replies: @@ -96,7 +96,7 @@ Here's a complete example of a plugin that demonstrates threaded replies: self.send(msg.frm, help_text, in_reply_to=msg) Configuration ------------- +------------- To enable threaded replies globally for specific commands, add them to your config.py: @@ -114,7 +114,7 @@ To enable threaded replies globally for specific commands, add them to your conf DIVERT_TO_THREAD = ("ALL_COMMANDS",) Limitations ----------- +----------- 1. Not all backends support threaded replies 2. Threaded replies may not be visible in all chat clients From 749311ecb89dfd30e015dbe4e95a66f7f7e928d0 Mon Sep 17 00:00:00 2001 From: Sijis Aviles Date: Sun, 12 Oct 2025 23:19:41 -0600 Subject: [PATCH 2/5] docs: add command parametes and renamed provisioning --- .../plugin_development/command_parameters.rst | 130 ++++++++++++++++++ docs/user_guide/plugin_development/index.rst | 2 + .../{ => plugin_development}/provisioning.rst | 13 +- docs/user_guide/setup.rst | 2 +- 4 files changed, 138 insertions(+), 9 deletions(-) create mode 100644 docs/user_guide/plugin_development/command_parameters.rst rename docs/user_guide/{ => plugin_development}/provisioning.rst (83%) diff --git a/docs/user_guide/plugin_development/command_parameters.rst b/docs/user_guide/plugin_development/command_parameters.rst new file mode 100644 index 000000000..d2fe56334 --- /dev/null +++ b/docs/user_guide/plugin_development/command_parameters.rst @@ -0,0 +1,130 @@ +Command Parameters +================== + +This page explains how to handle command parameters in Errbot plugins, including default values, argument parsing, and best practices. + +Basic Command Parameters +------------------------ + +The most basic form of a bot command takes a message object and arguments: + +.. code-block:: python + + @botcmd + def hello(self, msg, args): + return f"Hello! You said: {args}" + +In this case, ``msg`` is the message object containing information about who sent the command and where, and ``args`` is a string containing everything after the command. + +Default Values +-------------- + +You can provide default values for command parameters. This is useful when you want to make certain arguments optional: + +.. code-block:: python + + @botcmd + def echo(self, msg, args="default message"): + return f"You said: {args}" + +In this example, if someone calls the command without arguments, ``args`` will be set to "default message". + +.. note:: + Default values work for both the ``msg`` and ``args`` parameters. However, it's recommended to only use default values for ``args`` as the ``msg`` parameter is typically required for proper command handling. + +Argument Splitting +------------------ + +You can automatically split arguments into a list using the ``split_args_with`` parameter: + +.. code-block:: python + + @botcmd(split_args_with=None) # Split on any whitespace + def count(self, msg, args): + # If user types: !count one two three + # args will be ['one', 'two', 'three'] + return f"You provided {len(args)} arguments" + +The ``split_args_with`` parameter works exactly like Python's ``str.split()``. Common values are: + +- ``None``: Split on any whitespace (recommended for most cases) +- ``' '``: Split on single spaces only +- ``','``: Split on commas +- ``'|'``: Split on pipe characters + +Advanced Argument Parsing +------------------------- + +For more complex argument parsing, you can use the ``arg_botcmd`` decorator which provides argparse-style argument handling: + +.. code-block:: python + + @arg_botcmd('name', type=str) + @arg_botcmd('--count', dest='repeat', type=int, default=1) + def repeat(self, msg, name=None, repeat=None): + return name * repeat + +This allows for: +- Type checking and conversion +- Optional arguments with defaults +- Named arguments +- Help text generation + +Best Practices +-------------- + +1. **Parameter Order**: Always keep parameters in the order ``(self, msg, args)`` for consistency. + +2. **Default Values**: Use default values for optional parameters, but be careful with the ``msg`` parameter as it's usually required. + +3. **Argument Splitting**: Use ``split_args_with=None`` when you need to handle multiple space-separated arguments. + +4. **Type Safety**: Use ``arg_botcmd`` when you need type checking or complex argument parsing. + +5. **Documentation**: Always document your command's parameters and expected usage in the function's docstring. + +Example with All Features +------------------------- + +Here's a complete example showing various parameter handling techniques: + +.. code-block:: python + + @arg_botcmd('name', type=str, help='The name to greet') + @arg_botcmd('--count', dest='repeat', type=int, default=1, help='Number of times to repeat') + @arg_botcmd('--shout', dest='shout', action='store_true', help='Convert to uppercase') + def greet(self, msg, name=None, repeat=None, shout=False): + """Greet someone with a customizable message. + + Example: + !greet Alice --count 3 --shout + """ + if not name: + return "Please provide a name to greet" + + message = f"Hello, {name}!" + if shout: + message = message.upper() + + return message * repeat + +This command demonstrates: +- Required and optional arguments +- Type conversion +- Default values +- Boolean flags +- Help text +- Proper documentation + +Common Pitfalls +--------------- + +1. **Default Values for msg**: While possible, it's generally not recommended to provide default values for the ``msg`` parameter as it's essential for command context. + +2. **Argument Splitting**: Remember that ``split_args_with=None`` splits on any whitespace, which might not be what you want if you need to preserve spaces in arguments. + +3. **Type Conversion**: When using ``arg_botcmd``, always specify the correct type for arguments to ensure proper conversion and validation. + +4. **Parameter Names**: Keep parameter names consistent with the decorator's expectations (``msg`` and ``args`` for basic commands, or the names specified in ``arg_botcmd``). + +5. **Documentation**: Always include examples in your docstrings to help users understand how to use your commands correctly. \ No newline at end of file diff --git a/docs/user_guide/plugin_development/index.rst b/docs/user_guide/plugin_development/index.rst index 086a4d9cc..bfc8059c8 100644 --- a/docs/user_guide/plugin_development/index.rst +++ b/docs/user_guide/plugin_development/index.rst @@ -14,12 +14,14 @@ with sets of recipes on a range of topics describing how to handle more advanced development_environment basics botcommands + command_parameters messaging threaded_replies presence mentions persistence configuration + provisioning streams dependencies dynaplugs diff --git a/docs/user_guide/provisioning.rst b/docs/user_guide/plugin_development/provisioning.rst similarity index 83% rename from docs/user_guide/provisioning.rst rename to docs/user_guide/plugin_development/provisioning.rst index 188b89406..cf029317c 100644 --- a/docs/user_guide/provisioning.rst +++ b/docs/user_guide/plugin_development/provisioning.rst @@ -33,13 +33,13 @@ It will give you on stdout a python dictionary of the core namespace like:: {'configs': {'Webserver': {'PORT': 8888}}} -To read the values from a plugin storage, for example here from alimac/err-factoid you can do:: +To read the values from a plugin storage, for example here from the ChatRoom plugin you can do:: - errbot --storage-get Factoid + errbot --storage-get ChatRoom It will give you on stdout a similar output:: - {'FACTOID': {'fire': 'burns', 'water': 'wet'}} + {'rooms': ['#general', '#support']} Writing values @@ -54,11 +54,8 @@ Checking back:: errbot --storage-get core {'configs': {'Webserver': {'PORT': 9999}}} -Changing facts in Factoid (note the merge is only on the first level so we change all FACTOID here):: +Changing plugin storage values (note the merge is only on the first level):: - echo "{'FACTOID': {'errbot': 'awesome'}}" | errbot --storage-merge Factoid - - >>> !errbot? - errbot is awesome + echo "{'rooms': ['#general', '#support', '#dev']}" | errbot --storage-merge ChatRoom You can use --storage-set in the same fashion but it will erase first the namespace before writing your values. diff --git a/docs/user_guide/setup.rst b/docs/user_guide/setup.rst index 7146a087a..3b3c89f35 100644 --- a/docs/user_guide/setup.rst +++ b/docs/user_guide/setup.rst @@ -197,7 +197,7 @@ on `PyPI `_. Provisioning (advanced) ----------------------- -See the :doc:`provisioning documentation ` +See the :doc:`provisioning documentation ` .. _virtualenv: https://virtualenv.pypa.io/en/latest/ .. _pip: https://pip.pypa.io/en/stable/ From ddf0cbf571f0e7d991ed22b90f60731cfd89f1f6 Mon Sep 17 00:00:00 2001 From: Sijis Aviles Date: Tue, 19 May 2026 00:34:53 -0500 Subject: [PATCH 3/5] docs: ignore config-template.py in build and remove modules autobuild --- docs/README.rst | 2 ++ docs/conf.py | 2 +- docs/modules.rst | 7 ------- 3 files changed, 3 insertions(+), 8 deletions(-) delete mode 100644 docs/modules.rst diff --git a/docs/README.rst b/docs/README.rst index 0013d1e75..ae5be76b7 100644 --- a/docs/README.rst +++ b/docs/README.rst @@ -1,3 +1,5 @@ +:orphan: + Website and documentation ========================= diff --git a/docs/conf.py b/docs/conf.py index d69dc2b84..a4134ead9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -120,7 +120,7 @@ def autodoc_skip_member(app, what, name, obj, skip, options): def run_apidoc(_): - subprocess.check_call("sphinx-apidoc --separate -f -o . ../errbot", shell=True) + subprocess.check_call("sphinx-apidoc -T --separate -f -o . ../errbot ../errbot/config-template.py", shell=True) def run_repos_builder(*_): diff --git a/docs/modules.rst b/docs/modules.rst deleted file mode 100644 index 7f8d5e213..000000000 --- a/docs/modules.rst +++ /dev/null @@ -1,7 +0,0 @@ -errbot -====== - -.. toctree:: - :maxdepth: 4 - - errbot From 2051dfb2dcf5f41fe511092541b35e02289915f9 Mon Sep 17 00:00:00 2001 From: Sijis Aviles Date: Tue, 19 May 2026 00:36:41 -0500 Subject: [PATCH 4/5] docs: resolve sphinx build warnings --- errbot/__init__.py | 2 +- errbot/backends/base.py | 2 +- errbot/backends/irc.py | 2 +- errbot/backends/xmpp.py | 2 +- errbot/core_plugins/flows.py | 6 +++--- tests/flow_e2e_test.py | 9 +++++++++ 6 files changed, 16 insertions(+), 7 deletions(-) diff --git a/errbot/__init__.py b/errbot/__init__.py index 2be60e2eb..61cbf0e90 100644 --- a/errbot/__init__.py +++ b/errbot/__init__.py @@ -258,7 +258,7 @@ def botmatch(*args, **kwargs): """ Decorator for regex-based message match. - :param *args: The regular expression a message should match against in order to + :param args: The regular expression a message should match against in order to trigger the command. :param flags: The `flags` parameter which should be passed to :func:`re.compile()`. This allows the expression's behaviour to be modified, such as making it case-insensitive diff --git a/errbot/backends/base.py b/errbot/backends/base.py index 11822eb64..a3a672aa1 100644 --- a/errbot/backends/base.py +++ b/errbot/backends/base.py @@ -223,7 +223,7 @@ def invite(self, *args) -> None: """ Invite one or more people into the room. - :param *args: + :param args: One or more identifiers to invite into the room. """ raise NotImplementedError( diff --git a/errbot/backends/irc.py b/errbot/backends/irc.py index abc82a4e6..d714f39aa 100644 --- a/errbot/backends/irc.py +++ b/errbot/backends/irc.py @@ -315,7 +315,7 @@ def invite(self, *args) -> None: """ Invite one or more people into the room. - :param \*args: + :param args: One or more nicks to invite into the room. """ for nick in args: diff --git a/errbot/backends/xmpp.py b/errbot/backends/xmpp.py index 8e28da034..27942f078 100644 --- a/errbot/backends/xmpp.py +++ b/errbot/backends/xmpp.py @@ -273,7 +273,7 @@ def invite(self, *args) -> None: """ Invite one or more people into the room. - :*args: + :param args: One or more JID's to invite into the room. """ room = str(self) diff --git a/errbot/core_plugins/flows.py b/errbot/core_plugins/flows.py index 33c2fd676..5b25d654e 100644 --- a/errbot/core_plugins/flows.py +++ b/errbot/core_plugins/flows.py @@ -107,14 +107,14 @@ def flows_status(self, msg, args): for flow in self._bot.flow_executor.in_flight: if self.check_user(msg, flow): next_steps = [ - f"\\*{str(step[1].command)}\\*" + rf"\*{str(step[1].command)}\*" for step in flow._current_step.children if step[1].command ] next_steps_str = "\n".join(next_steps) text = ( - f"\\>>> {str(flow.requestor)} is using flow \\*{flow.name}\\* on step " - f"\\*{flow.current_step}\\*\nNext Step(s): \n{next_steps_str}" + rf"\>>> {str(flow.requestor)} is using flow \*{flow.name}\* on step " + rf"\*{flow.current_step}\*\nNext Step(s): \n{next_steps_str}" ) response.write(text) return response.getvalue() diff --git a/tests/flow_e2e_test.py b/tests/flow_e2e_test.py index ed81d226a..5bc07b5d2 100644 --- a/tests/flow_e2e_test.py +++ b/tests/flow_e2e_test.py @@ -130,3 +130,12 @@ def test_room_flow(testbot): flow_message = testbot.pop_message() assert "You are in the flow w3, you can continue with" in flow_message assert "!b" in flow_message + +def test_flows_status(testbot): + assert "started" in testbot.exec_command("!flows start w1") + assert "You are in the flow" in testbot.pop_message() + status = testbot.exec_command("!flows status") + assert ">>>" in status + assert "gbin@localhost is using flow *w1*" in status + assert "Next Step(s):" in status + assert "*a*" in status From c39afcf66d6ad310136d426fda7c9d4211f77a1a Mon Sep 17 00:00:00 2001 From: Sijis Aviles Date: Tue, 19 May 2026 00:47:39 -0500 Subject: [PATCH 5/5] docs: add info to CHANGES --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index ddeb966b9..9c4d774ca 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -43,6 +43,7 @@ fixes: - chore: bump docker/build-push-action version (#1759) - chore: bump docker/login-action version (#1760) - chore: bump docker/setup-qemu-action version (#1761) +- docs: add command parameter section and minor doc edits (#1740) v6.2.0 (2024-01-01)