roboherd 0.1.11__tar.gz → 0.1.12__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of roboherd might be problematic. Click here for more details.

Files changed (68) hide show
  1. {roboherd-0.1.11 → roboherd-0.1.12}/.woodpecker/publish_docker.yml +4 -0
  2. {roboherd-0.1.11 → roboherd-0.1.12}/.woodpecker/test.yml +1 -0
  3. {roboherd-0.1.11 → roboherd-0.1.12}/.woodpecker/website.yml +1 -1
  4. {roboherd-0.1.11 → roboherd-0.1.12}/CHANGES.md +6 -0
  5. {roboherd-0.1.11 → roboherd-0.1.12}/PKG-INFO +5 -4
  6. {roboherd-0.1.11 → roboherd-0.1.12}/docs/cli.md +4 -0
  7. {roboherd-0.1.11 → roboherd-0.1.12}/docs/index.md +3 -2
  8. {roboherd-0.1.11 → roboherd-0.1.12}/pyproject.toml +11 -10
  9. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/__main__.py +1 -1
  10. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/annotations/common.py +4 -4
  11. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/cow/__init__.py +28 -6
  12. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/cow/test_init.py +11 -0
  13. roboherd-0.1.12/roboherd/examples/json_echo.py +51 -0
  14. roboherd-0.1.12/roboherd/py.typed +0 -0
  15. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/register.py +2 -1
  16. roboherd-0.1.12/roboherd/version.py +1 -0
  17. roboherd-0.1.12/uv.lock +2137 -0
  18. roboherd-0.1.11/roboherd/examples/json_echo.py +0 -51
  19. roboherd-0.1.11/roboherd/version.py +0 -1
  20. roboherd-0.1.11/uv.lock +0 -1925
  21. {roboherd-0.1.11 → roboherd-0.1.12}/.gitignore +0 -0
  22. {roboherd-0.1.11 → roboherd-0.1.12}/.woodpecker/create_release.yml +0 -0
  23. {roboherd-0.1.11 → roboherd-0.1.12}/.woodpecker/publish_pypi.yml +0 -0
  24. {roboherd-0.1.11 → roboherd-0.1.12}/README.md +0 -0
  25. {roboherd-0.1.11 → roboherd-0.1.12}/docs/annotations.md +0 -0
  26. {roboherd-0.1.11 → roboherd-0.1.12}/docs/assets/bull-horns.png +0 -0
  27. {roboherd-0.1.11 → roboherd-0.1.12}/docs/assets/mastodon.png +0 -0
  28. {roboherd-0.1.11 → roboherd-0.1.12}/docs/cow.md +0 -0
  29. {roboherd-0.1.11 → roboherd-0.1.12}/docs/herd.md +0 -0
  30. {roboherd-0.1.11 → roboherd-0.1.12}/docs/main.md +0 -0
  31. {roboherd-0.1.11 → roboherd-0.1.12}/docs/util.md +0 -0
  32. {roboherd-0.1.11 → roboherd-0.1.12}/mkdocs.yml +0 -0
  33. {roboherd-0.1.11 → roboherd-0.1.12}/resources/docker/Dockerfile +0 -0
  34. {roboherd-0.1.11 → roboherd-0.1.12}/resources/docker/build.sh +0 -0
  35. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/__init__.py +0 -0
  36. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/annotations/__init__.py +0 -0
  37. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/annotations/bovine.py +0 -0
  38. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/cow/const.py +0 -0
  39. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/cow/handlers.py +0 -0
  40. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/cow/profile.py +0 -0
  41. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/cow/test_handlers.py +0 -0
  42. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/cow/test_profile.py +0 -0
  43. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/cow/test_util.py +0 -0
  44. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/cow/types.py +0 -0
  45. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/cow/util.py +0 -0
  46. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/examples/__init__.py +0 -0
  47. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/examples/dev_null.py +0 -0
  48. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/examples/meta.py +0 -0
  49. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/examples/moocow.py +0 -0
  50. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/examples/number.py +0 -0
  51. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/examples/rooster.py +0 -0
  52. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/examples/scarecrow.py +0 -0
  53. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/herd/__init__.py +0 -0
  54. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/herd/builder.py +0 -0
  55. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/herd/manager/__init__.py +0 -0
  56. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/herd/manager/config.py +0 -0
  57. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/herd/manager/load.py +0 -0
  58. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/herd/manager/test_config.py +0 -0
  59. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/herd/manager/test_load.py +0 -0
  60. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/herd/manager/test_manager.py +0 -0
  61. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/herd/processor.py +0 -0
  62. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/herd/scheduler.py +0 -0
  63. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/herd/test_herd.py +0 -0
  64. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/herd/test_scheduler.py +0 -0
  65. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/herd/types.py +0 -0
  66. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/test_validators.py +0 -0
  67. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/util.py +0 -0
  68. {roboherd-0.1.11 → roboherd-0.1.12}/roboherd/validators.py +0 -0
@@ -8,6 +8,10 @@ matrix:
8
8
  depends_on: ["publish_pypi"]
9
9
 
10
10
  steps:
11
+ sleep:
12
+ image: ghcr.io/astral-sh/uv:python3.11-alpine
13
+ commands:
14
+ - sleep 120
11
15
  publish_docker_latest:
12
16
  image: woodpeckerci/plugin-docker-buildx:6.0.2
13
17
  settings:
@@ -32,6 +32,7 @@ steps:
32
32
  image: ghcr.io/astral-sh/uv:python3.11-alpine
33
33
  commands:
34
34
  - cp CHANGES.md docs/CHANGES.md
35
+ - uv sync --group docs
35
36
  - uv run mkdocs build
36
37
  when:
37
38
  - matrix: { extras: "--all-extras" }
@@ -6,7 +6,7 @@ steps:
6
6
  build:
7
7
  image: ghcr.io/astral-sh/uv:python3.11-alpine
8
8
  commands:
9
- - uv sync --all-extras
9
+ - uv sync --all-extras --group docs
10
10
  - cp CHANGES.md docs/CHANGES.md
11
11
  - uv run mkdocs build
12
12
  deploy:
@@ -1,5 +1,11 @@
1
1
  # Changes to roboherd
2
2
 
3
+ ## 0.1.12
4
+
5
+ - Add ability to set description by markdown
6
+ - Add py.typed [roboherd#54](https://codeberg.org/bovine/roboherd/issues/54)
7
+ - Fix typo [roboherd#55](https://codeberg.org/bovine/roboherd/issues/55)
8
+
3
9
  ## 0.1.11
4
10
 
5
11
  - Add `--version` flag [roboherd#50](https://codeberg.org/bovine/roboherd/issues/50)
@@ -1,22 +1,23 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: roboherd
3
- Version: 0.1.11
3
+ Version: 0.1.12
4
4
  Summary: A Fediverse bot framework
5
5
  Project-URL: Documentation, https://bovine.codeberg.page/roboherd/
6
6
  Project-URL: Repository, https://codeberg.org/bovine/roboherd
7
7
  Requires-Python: >=3.11
8
- Requires-Dist: aiohttp>=3.11.12
9
8
  Requires-Dist: almabtrieb[mqtt]>=0.2
10
9
  Requires-Dist: apscheduler>=3.11.0
11
10
  Requires-Dist: click>=8.1.8
12
11
  Requires-Dist: cron-descriptor>=1.4.5
13
12
  Requires-Dist: dynaconf>=3.2.6
14
- Requires-Dist: fast-depends>=2.4.12
13
+ Requires-Dist: fast-depends>=3.0.0
15
14
  Requires-Dist: tomli-w>=1.1.0
16
- Requires-Dist: watchfiles>=1.0.4
17
15
  Provides-Extra: bovine
18
16
  Requires-Dist: bovine>=0.5.15; extra == 'bovine'
19
17
  Requires-Dist: markdown>=3.7; extra == 'bovine'
18
+ Provides-Extra: dev
19
+ Requires-Dist: aiohttp>=3.11.12; extra == 'dev'
20
+ Requires-Dist: watchfiles>=1.0.4; extra == 'dev'
20
21
  Description-Content-Type: text/markdown
21
22
 
22
23
  # Roboherd
@@ -7,6 +7,10 @@ to run
7
7
  roboherd run
8
8
  ```
9
9
 
10
+ !!! info
11
+ The watch and register commands require you to install
12
+ `roboherd[dev]`.
13
+
10
14
  ::: mkdocs-click
11
15
  :module: roboherd.__main__
12
16
  :command: main
@@ -1,11 +1,12 @@
1
1
  # Roboherd
2
2
 
3
3
  Roboherd is a tool to build automated Fediverse actors. It does
4
- so by connecting to a server through the [Cattle Drive protocol](https://bovine.codeberg.page/cattle_grid/cattle_drive/) protocol. Once you have
4
+ so by connecting to a server through the [Cattle Drive protocol](https://bovine.codeberg.page/cattle_grid/cattle_drive/)
5
+ protocol. Once you have
5
6
  configured the connection, all other tasks can be done using
6
7
  python code and a toml configuration file.
7
8
 
8
- The serer roboherd connects to is specified through a connection string,
9
+ The server roboherd connects to is specified through a connection string,
9
10
  see [Configuration](#configuration).
10
11
 
11
12
  ## Usage examples
@@ -4,15 +4,13 @@ description = "A Fediverse bot framework"
4
4
  readme = "README.md"
5
5
  requires-python = ">=3.11"
6
6
  dependencies = [
7
- "aiohttp>=3.11.12",
8
7
  "almabtrieb[mqtt]>=0.2",
9
8
  "apscheduler>=3.11.0",
10
9
  "click>=8.1.8",
11
10
  "cron-descriptor>=1.4.5",
12
11
  "dynaconf>=3.2.6",
13
- "fast-depends>=2.4.12",
12
+ "fast-depends>=3.0.0",
14
13
  "tomli-w>=1.1.0",
15
- "watchfiles>=1.0.4",
16
14
  ]
17
15
 
18
16
  dynamic = ["version"]
@@ -36,24 +34,27 @@ roboherd = "roboherd.__main__:main"
36
34
 
37
35
  [project.optional-dependencies]
38
36
  bovine = ["bovine>=0.5.15", "markdown>=3.7"]
37
+ dev = ["aiohttp>=3.11.12", "watchfiles>=1.0.4"]
39
38
 
40
- [tool.uv]
41
- dev-dependencies = [
39
+ [dependency-groups]
40
+ dev = [
42
41
  "pytest>=8.3.4",
43
42
  "pytest-asyncio>=0.25.2",
44
43
  "pytest-watcher>=0.4.3",
45
- "mkdocs-material>=9.5.50",
44
+ "ruff>=0.9.6",
45
+ "pyright>=1.1.394",
46
+ ]
47
+ docs = [
48
+ "mkdocs-material==9.6.20",
46
49
  "mkdocstrings-python>=1.13.0",
47
50
  "griffe-fieldz>=0.2.1",
48
51
  "mkdocs-click>=0.8.1",
49
- "ruff>=0.9.6",
50
- "pyright>=1.1.394",
51
52
  ]
52
53
 
53
54
  [tool.pytest.ini_options]
54
55
  addopts = "--doctest-modules"
55
56
  asyncio_mode = "auto"
56
- log_cli = 1
57
- log_cli_level = "info"
57
+ log_cli = true
58
+ log_cli_level = "INFO"
58
59
  doctest_optionflags = "NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL ELLIPSIS"
59
60
  testpaths = ["roboherd/**/*.py"]
@@ -4,7 +4,6 @@ import os
4
4
 
5
5
  import click
6
6
  import dynaconf
7
- import watchfiles
8
7
 
9
8
  from roboherd.herd import RoboHerd
10
9
  from roboherd.herd.manager import HerdManager
@@ -113,6 +112,7 @@ def watch(ctx):
113
112
  """Watches the file the module is in for changes and then restarts roboherd.
114
113
 
115
114
  Note: Options for roboherd are currently ignored (FIXME)."""
115
+ import watchfiles
116
116
 
117
117
  watchfiles.run_process("roboherd", target="roboherd run")
118
118
 
@@ -1,5 +1,5 @@
1
1
  from fast_depends import Depends
2
- from typing import Annotated, Callable, Awaitable
2
+ from typing import Annotated, Any, Callable, Awaitable
3
3
 
4
4
  from almabtrieb import Almabtrieb
5
5
 
@@ -7,17 +7,17 @@ from almabtrieb import Almabtrieb
7
7
  from roboherd.cow import RoboCow
8
8
 
9
9
 
10
- def get_profile(cow: RoboCow) -> dict:
10
+ def get_profile(cow: RoboCow) -> dict[str, Any]:
11
11
  if cow.internals.profile is None:
12
12
  raise ValueError("Cow has no profile")
13
13
  return cow.internals.profile
14
14
 
15
15
 
16
- Profile = Annotated[dict, Depends(get_profile)]
16
+ Profile = Annotated[dict[str, Any], Depends(get_profile)]
17
17
  """The profile of the cow"""
18
18
 
19
19
 
20
- Publisher = Callable[[dict], Awaitable[None]]
20
+ Publisher = Callable[[dict[str, Any]], Awaitable[None]]
21
21
  """Type returned by the publishing functions"""
22
22
 
23
23
 
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
 
3
- from typing import Callable, List
3
+ from typing import Any, Callable, List
4
4
 
5
5
  from dataclasses import dataclass, field
6
6
  from fast_depends import inject
@@ -28,7 +28,7 @@ class CronEntry:
28
28
  class RoboCowInternals:
29
29
  """Internal data for the cow"""
30
30
 
31
- profile: dict | None = field(
31
+ profile: dict[str, Any] | None = field(
32
32
  default=None,
33
33
  metadata=dict(
34
34
  description="""The profile of the cow, aka as the actor object in ActivityPub"""
@@ -90,11 +90,33 @@ class RoboCow:
90
90
 
91
91
  @staticmethod
92
92
  def create(**kwargs):
93
- """Creates a new cow. We note that
94
- `RoboCow.create(name="my name")` is equivalent
95
- to `RoboCow(information=Information(name="my name"))`.
93
+ """Creates a new cow, by creating a new [Information][roboherd.cow.types.Information].
94
+
95
+ ```python
96
+ >>> RoboCow.create(name="my cow")
97
+ RoboCow(information=Information(type='Service', handle=None, name='my cow', ...
98
+
99
+ ```
100
+
101
+ The parameter `description_md` is transformed from markdown to html and then
102
+ assigned to `description`.
103
+
104
+ ```python
105
+ >> cow = RoboCow.create(description_md="__bold__")
106
+ >> cow.information.description
107
+ '<p><strong>bold</strong></p>'
108
+
109
+ ```
96
110
  """
97
- return RoboCow(information=Information(**kwargs))
111
+
112
+ if "description_md" in kwargs:
113
+ import markdown
114
+
115
+ kwargs["description"] = markdown.markdown(kwargs["description_md"])
116
+ del kwargs["description_md"]
117
+
118
+ information = Information.model_validate(kwargs)
119
+ return RoboCow(information=information)
98
120
 
99
121
  def action(self, action: str = "*", activity_type: str = "*"):
100
122
  """Adds a handler for an event. Use "*" as a wildcard.
@@ -1,3 +1,4 @@
1
+ import pytest
1
2
  from unittest.mock import AsyncMock
2
3
 
3
4
  from . import RoboCow
@@ -39,3 +40,13 @@ async def test_skip_startup():
39
40
  await cow.run_startup(connection=connection)
40
41
 
41
42
  connection.trigger.assert_not_awaited()
43
+
44
+
45
+ @pytest.mark.skipif(
46
+ not pytest.importorskip("markdown"), reason="markdown not installed"
47
+ )
48
+ def test_create():
49
+ cow = RoboCow.create(handle="testcow", description_md="__bold__")
50
+
51
+ assert cow.information.handle == "testcow"
52
+ assert cow.information.description == "<p><strong>bold</strong></p>"
@@ -0,0 +1,51 @@
1
+ import json
2
+
3
+ from roboherd import RoboCow, RawData, PublishObject, ObjectFactory
4
+
5
+ from .meta import meta_information
6
+
7
+
8
+ def reply_content(raw: dict) -> str:
9
+ """Formats and escapes the JSON data:
10
+
11
+ ```pycon
12
+ >>> reply_content({"html": "<b>bold</b>"})
13
+ '<pre><code>{\\n "html": "&lt;b&gt;bold&lt;/b&gt;"\\n}</code></re>'
14
+
15
+ ```
16
+ """
17
+ json_formatted = (
18
+ json.dumps(raw, indent=2)
19
+ .replace("&", "&amp;")
20
+ .replace("<", "&lt;")
21
+ .replace(">", "&gt;")
22
+ )
23
+ return f"<pre><code>{json_formatted}</code></re>"
24
+
25
+
26
+ try:
27
+ bot = RoboCow.create(
28
+ handle="jsonecho",
29
+ name="JSON Echo {}",
30
+ description_md="""I'm a silly bot that replies to
31
+ you with the JSON as received through a HTTP
32
+ post request by [cattle_grid](https://bovine.codeberg.page/cattle_grid/).""",
33
+ meta_information=meta_information,
34
+ )
35
+
36
+ @bot.incoming_create
37
+ async def create(
38
+ raw: RawData, publish_object: PublishObject, object_factory: ObjectFactory
39
+ ):
40
+ note = (
41
+ object_factory.reply( # type: ignore
42
+ raw.get("object"),
43
+ content=reply_content(raw),
44
+ )
45
+ .as_public()
46
+ .build()
47
+ )
48
+
49
+ await publish_object(note)
50
+ except ImportError:
51
+ ...
File without changes
@@ -1,4 +1,3 @@
1
- import aiohttp
2
1
  import tomli_w
3
2
 
4
3
 
@@ -24,6 +23,8 @@ def create_config(
24
23
 
25
24
 
26
25
  async def register(config_file: str, name: str, password: str, fediverse: str):
26
+ import aiohttp
27
+
27
28
  async with aiohttp.ClientSession() as session:
28
29
  result = await session.post(
29
30
  "https://dev.bovine.social/register",
@@ -0,0 +1 @@
1
+ __version__ = "0.1.12"