roboherd 0.1.6__tar.gz → 0.1.8__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.6 → roboherd-0.1.8}/.woodpecker/test.yml +1 -0
  2. {roboherd-0.1.6 → roboherd-0.1.8}/.woodpecker/website.yml +1 -0
  3. {roboherd-0.1.6 → roboherd-0.1.8}/CHANGES.md +10 -0
  4. {roboherd-0.1.6 → roboherd-0.1.8}/PKG-INFO +1 -1
  5. {roboherd-0.1.6 → roboherd-0.1.8}/docs/index.md +1 -1
  6. roboherd-0.1.8/docs/main.md +3 -0
  7. {roboherd-0.1.6 → roboherd-0.1.8}/mkdocs.yml +2 -0
  8. {roboherd-0.1.6 → roboherd-0.1.8}/pyproject.toml +1 -1
  9. {roboherd-0.1.6 → roboherd-0.1.8}/resources/docker/Dockerfile +2 -2
  10. roboherd-0.1.8/roboherd/__init__.py +25 -0
  11. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/cow/__init__.py +28 -19
  12. roboherd-0.1.8/roboherd/cow/test_init.py +41 -0
  13. roboherd-0.1.8/roboherd/examples/dev_null.py +10 -0
  14. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/examples/json_echo.py +6 -11
  15. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/examples/moocow.py +6 -10
  16. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/examples/number.py +5 -10
  17. roboherd-0.1.8/roboherd/examples/rooster.py +16 -0
  18. roboherd-0.1.8/roboherd/examples/scarecrow.py +23 -0
  19. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/herd/manager/config.py +30 -6
  20. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/herd/manager/test_config.py +2 -0
  21. {roboherd-0.1.6 → roboherd-0.1.8}/uv.lock +4 -4
  22. roboherd-0.1.6/roboherd/cow/test_init.py +0 -57
  23. roboherd-0.1.6/roboherd/examples/__init__.py +0 -0
  24. roboherd-0.1.6/roboherd/examples/dev_null.py +0 -13
  25. roboherd-0.1.6/roboherd/examples/rooster.py +0 -22
  26. roboherd-0.1.6/roboherd/examples/scarecrow.py +0 -27
  27. {roboherd-0.1.6 → roboherd-0.1.8}/.gitignore +0 -0
  28. {roboherd-0.1.6 → roboherd-0.1.8}/.woodpecker/create_release.yml +0 -0
  29. {roboherd-0.1.6 → roboherd-0.1.8}/.woodpecker/publish_docker.yml +0 -0
  30. {roboherd-0.1.6 → roboherd-0.1.8}/.woodpecker/publish_pypi.yml +0 -0
  31. {roboherd-0.1.6 → roboherd-0.1.8}/README.md +0 -0
  32. {roboherd-0.1.6 → roboherd-0.1.8}/docs/annotations.md +0 -0
  33. {roboherd-0.1.6 → roboherd-0.1.8}/docs/assets/bull-horns.png +0 -0
  34. {roboherd-0.1.6 → roboherd-0.1.8}/docs/assets/mastodon.png +0 -0
  35. {roboherd-0.1.6 → roboherd-0.1.8}/docs/cli.md +0 -0
  36. {roboherd-0.1.6 → roboherd-0.1.8}/docs/cow.md +0 -0
  37. {roboherd-0.1.6 → roboherd-0.1.8}/docs/herd.md +0 -0
  38. {roboherd-0.1.6 → roboherd-0.1.8}/docs/util.md +0 -0
  39. {roboherd-0.1.6 → roboherd-0.1.8}/resources/docker/build.sh +0 -0
  40. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/__main__.py +0 -0
  41. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/annotations/__init__.py +0 -0
  42. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/annotations/bovine.py +0 -0
  43. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/annotations/common.py +0 -0
  44. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/cow/const.py +0 -0
  45. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/cow/handlers.py +0 -0
  46. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/cow/profile.py +0 -0
  47. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/cow/test_handlers.py +0 -0
  48. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/cow/test_profile.py +0 -0
  49. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/cow/test_util.py +0 -0
  50. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/cow/types.py +0 -0
  51. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/cow/util.py +0 -0
  52. {roboherd-0.1.6/roboherd → roboherd-0.1.8/roboherd/examples}/__init__.py +0 -0
  53. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/examples/meta.py +0 -0
  54. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/herd/__init__.py +0 -0
  55. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/herd/builder.py +0 -0
  56. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/herd/manager/__init__.py +0 -0
  57. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/herd/manager/load.py +0 -0
  58. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/herd/manager/test_load.py +0 -0
  59. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/herd/manager/test_manager.py +0 -0
  60. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/herd/processor.py +0 -0
  61. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/herd/scheduler.py +0 -0
  62. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/herd/test_herd.py +0 -0
  63. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/herd/test_scheduler.py +0 -0
  64. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/herd/types.py +0 -0
  65. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/register.py +0 -0
  66. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/test_validators.py +0 -0
  67. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/util.py +0 -0
  68. {roboherd-0.1.6 → roboherd-0.1.8}/roboherd/validators.py +0 -0
@@ -31,6 +31,7 @@ steps:
31
31
  build_docs:
32
32
  image: ghcr.io/astral-sh/uv:python3.11-alpine
33
33
  commands:
34
+ - cp CHANGES.md docs/CHANGES.md
34
35
  - uv run mkdocs build
35
36
  when:
36
37
  - matrix: { extras: "--all-extras" }
@@ -7,6 +7,7 @@ steps:
7
7
  image: ghcr.io/astral-sh/uv:python3.11-alpine
8
8
  commands:
9
9
  - uv sync --all-extras
10
+ - cp CHANGES.md docs/CHANGES.md
10
11
  - uv run mkdocs build
11
12
  deploy:
12
13
  image: codeberg.org/xfix/plugin-codeberg-pages-deploy:1
@@ -1,5 +1,15 @@
1
1
  # Changes to roboherd
2
2
 
3
+ ## 0.1.8 ([Milestone](https://codeberg.org/bovine/roboherd/milestone/11129))
4
+
5
+ - Add ConfigOverrides model [roboherd#43](https://codeberg.org/bovine/roboherd/issues/43)
6
+ - Allow to skip startup [roboherd#41](https://codeberg.org/bovine/roboherd/issues/41)
7
+
8
+ ## 0.1.7 ([Milestone](https://codeberg.org/bovine/roboherd/milestone/10741))
9
+
10
+ - Repair docker file [roboherd#38](https://codeberg.org/bovine/roboherd/issues/38)
11
+ - Simplify imports and creating a RoboCow [roboherd#39](https://codeberg.org/bovine/roboherd/issues/39)
12
+
3
13
  ## 0.1.6 ([Milestone](https://codeberg.org/bovine/roboherd/milestone/10694))
4
14
 
5
15
  - Comment on python path [roboherd#34](https://codeberg.org/bovine/roboherd/issues/34)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: roboherd
3
- Version: 0.1.6
3
+ Version: 0.1.8
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
@@ -122,7 +122,7 @@ handle = "nothingness"
122
122
  ```
123
123
 
124
124
  one would instead create a bot with the handle `acct:nothingness@dev.bovine.social`.
125
- Similarly, one can override the name and the `base_url` to use.
125
+ The full list of options can be found in [roboherd.herd.manager.config.ConfigOverrides][].
126
126
 
127
127
  ### Posting on startup
128
128
 
@@ -0,0 +1,3 @@
1
+ :::roboherd
2
+ options:
3
+ show_submodules: false
@@ -59,8 +59,10 @@ plugins:
59
59
  - griffe_fieldz: { include_inherited: true }
60
60
  nav:
61
61
  - Home: index.md
62
+ - "Changes": CHANGES.md
62
63
  - "Commang Line Tool": cli.md
63
64
  - "References":
65
+ - "roboherd": main.md
64
66
  - "roboherd.annotations": annotations.md
65
67
  - "roboherd.cow": cow.md
66
68
  - "roboherd.herd": herd.md
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "roboherd"
3
- version = "0.1.6"
3
+ version = "0.1.8"
4
4
  description = "A Fediverse bot framework"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1,7 +1,7 @@
1
1
  FROM helgekr/bovine:0.5.18-python3.13
2
2
 
3
- ARG tag
4
- RUN pip install roboherd==${tag}
3
+ ARG tag=0.1.6
4
+ RUN pip install roboherd[bovine]==${tag}
5
5
 
6
6
  RUN mkdir /app
7
7
  WORKDIR /app
@@ -0,0 +1,25 @@
1
+ """Main roboherd module. Should contain all necessary elements to build a robocow"""
2
+
3
+ from .cow import RoboCow
4
+ from .annotations import (
5
+ PublishObject,
6
+ PublishActivity,
7
+ RawData,
8
+ ParsedData,
9
+ Activity,
10
+ EmbeddedObject,
11
+ )
12
+ from .annotations.bovine import MarkdownPoster, ObjectFactory, ActivityFactory
13
+
14
+ __all__ = [
15
+ "RoboCow",
16
+ "RawData",
17
+ "ParsedData",
18
+ "Activity",
19
+ "EmbeddedObject",
20
+ "MarkdownPoster",
21
+ "ActivityFactory",
22
+ "ObjectFactory",
23
+ "PublishObject",
24
+ "PublishActivity",
25
+ ]
@@ -76,11 +76,26 @@ class RoboCow:
76
76
  ),
77
77
  )
78
78
 
79
+ skip_profile_update: bool = field(
80
+ default=False,
81
+ metadata=dict(
82
+ description="When set to True the profile is not updated automatically. Useful when managing a cow from multiple scripts."
83
+ ),
84
+ )
85
+
79
86
  internals: RoboCowInternals = field(
80
87
  default_factory=RoboCowInternals,
81
88
  metadata=dict(description="Internal data for the cow"),
82
89
  )
83
90
 
91
+ @staticmethod
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"))`.
96
+ """
97
+ return RoboCow(information=Information(**kwargs))
98
+
84
99
  def action(self, action: str = "*", activity_type: str = "*"):
85
100
  """Adds a handler for an event. Use "*" as a wildcard.
86
101
 
@@ -158,19 +173,6 @@ class RoboCow:
158
173
 
159
174
  self.internals.startup_routine = func
160
175
 
161
- def needs_update(self):
162
- """Checks if the cow needs to be updated"""
163
- if self.internals.profile is None:
164
- return True
165
-
166
- if self.information.name != self.internals.profile.get("name"):
167
- return True
168
-
169
- if self.information.description != self.internals.profile.get("summary"):
170
- return True
171
-
172
- return False
173
-
174
176
  async def run_startup(self, connection: Almabtrieb):
175
177
  """Runs when the cow is birthed"""
176
178
 
@@ -190,12 +192,8 @@ class RoboCow:
190
192
  )
191
193
  self.information.frequency = frequency
192
194
 
193
- update = determine_profile_update(self.information, self.internals.profile)
194
-
195
- if update:
196
- logger.info("Updating profile for %s", self.information.handle)
197
-
198
- await connection.trigger("update_actor", update)
195
+ if not self.skip_profile_update:
196
+ await self._run_profile_update(connection)
199
197
 
200
198
  if self.internals.startup_routine:
201
199
  await inject(self.internals.startup_routine)(
@@ -203,3 +201,14 @@ class RoboCow:
203
201
  connection=connection, # type:ignore
204
202
  actor_id=self.internals.actor_id, # type:ignore
205
203
  ) # type:ignore
204
+
205
+ async def _run_profile_update(self, connection: Almabtrieb):
206
+ if self.internals.profile is None:
207
+ raise ValueError("Profile is not set")
208
+
209
+ update = determine_profile_update(self.information, self.internals.profile)
210
+
211
+ if update:
212
+ logger.info("Updating profile for %s", self.information.handle)
213
+
214
+ await connection.trigger("update_actor", update)
@@ -0,0 +1,41 @@
1
+ from unittest.mock import AsyncMock
2
+
3
+ from . import RoboCow
4
+ from .types import Information
5
+
6
+
7
+ def test_cron():
8
+ info = Information(handle="testcow")
9
+ cow = RoboCow(information=info)
10
+
11
+ @cow.cron("* * * * *")
12
+ async def test_func():
13
+ pass
14
+
15
+ assert len(cow.internals.cron_entries) == 1
16
+
17
+
18
+ async def test_startup():
19
+ info = Information(handle="testcow")
20
+ cow = RoboCow(information=info)
21
+ cow.internals.profile = {"id": "http://host.test/actor/cow"}
22
+ mock = AsyncMock()
23
+ connection = AsyncMock()
24
+
25
+ cow.startup(mock)
26
+
27
+ await cow.run_startup(connection=connection)
28
+
29
+ mock.assert_called_once()
30
+ connection.trigger.assert_awaited_once()
31
+
32
+
33
+ async def test_skip_startup():
34
+ info = Information(handle="testcow")
35
+ cow = RoboCow(information=info, skip_profile_update=True)
36
+ cow.internals.profile = {"id": "http://host.test/actor/cow"}
37
+
38
+ connection = AsyncMock()
39
+ await cow.run_startup(connection=connection)
40
+
41
+ connection.trigger.assert_not_awaited()
@@ -0,0 +1,10 @@
1
+ from roboherd import RoboCow
2
+
3
+ from .meta import meta_information
4
+
5
+ bot = RoboCow.create(
6
+ name="/dev/null",
7
+ description="""I don't do anything.""",
8
+ handle="devnull",
9
+ meta_information=meta_information,
10
+ )
@@ -1,24 +1,19 @@
1
1
  import json
2
2
 
3
- from roboherd.cow import RoboCow
4
- from roboherd.annotations import RawData, PublishObject
5
- from roboherd.annotations.bovine import ObjectFactory
3
+ from roboherd import RoboCow, RawData, PublishObject, ObjectFactory
6
4
 
7
- from roboherd.cow.types import Information
8
5
  from .meta import meta_information
9
6
 
10
- bot = RoboCow(
11
- information=Information(
12
- handle="jsonecho",
13
- name="JSON Echo {}",
14
- description="""<p>I'm a silly bot that replies to
7
+ bot = RoboCow.create(
8
+ handle="jsonecho",
9
+ name="JSON Echo {}",
10
+ description="""<p>I'm a silly bot that replies to
15
11
  you with the JSON as received through a HTTP
16
12
  post request by
17
13
  <a href="https://codeberg.org/helge/cattle_grid">cattle_grid</a>.</p>
18
14
 
19
15
  """,
20
- meta_information=meta_information,
21
- )
16
+ meta_information=meta_information,
22
17
  )
23
18
 
24
19
 
@@ -1,22 +1,18 @@
1
1
  import logging
2
2
 
3
- from roboherd.cow import RoboCow
4
- from roboherd.annotations import EmbeddedObject, PublishObject
5
- from roboherd.cow.types import Information
3
+ from roboherd import RoboCow, EmbeddedObject, PublishObject
6
4
  from .meta import meta_information
7
5
 
8
6
  logger = logging.getLogger(__name__)
9
7
 
10
- moocow = RoboCow(
11
- information=Information(
12
- handle="moocow",
13
- name="The mooing cow 🐮",
14
- description="""I'm a cow that likes to moo.
8
+ moocow = RoboCow.create(
9
+ handle="moocow",
10
+ name="The mooing cow 🐮",
11
+ description="""I'm a cow that likes to moo.
15
12
 
16
13
  I also serve as an example for the RoboHerd python tool.
17
14
  See <a href="https://codeberg.org/helge/roboherd">codeberg.org</a>.""",
18
- meta_information=meta_information,
19
- )
15
+ meta_information=meta_information,
20
16
  )
21
17
 
22
18
 
@@ -3,10 +3,7 @@ from urllib.parse import urlparse
3
3
 
4
4
  from almabtrieb import Almabtrieb
5
5
 
6
- from roboherd.cow import RoboCow
7
- from roboherd.annotations import PublishObject
8
- from roboherd.annotations.bovine import ObjectFactory
9
- from roboherd.cow.types import Information
6
+ from roboherd import RoboCow, PublishObject, ObjectFactory
10
7
  from .meta import meta_information
11
8
 
12
9
 
@@ -14,14 +11,12 @@ def hostname(actor_id):
14
11
  return urlparse(actor_id).netloc
15
12
 
16
13
 
17
- bot = RoboCow(
18
- information=Information(
19
- handle="even",
20
- description="""<p>I'm a bot by Helge. I post a random number every hour. When posting an even number, I change my Fediverse handle to even. When posting an odd one, I use odd.</p>
14
+ bot = RoboCow.create(
15
+ handle="even",
16
+ description="""<p>I'm a bot by Helge. I post a random number every hour. When posting an even number, I change my Fediverse handle to even. When posting an odd one, I use odd.</p>
21
17
 
22
18
  <p>I also update my name. I'm not sure how you should display my handle with your Fediverse application. Please write a FEP explaining it.</p>""",
23
- meta_information=meta_information,
24
- )
19
+ meta_information=meta_information,
25
20
  )
26
21
 
27
22
 
@@ -0,0 +1,16 @@
1
+ from roboherd import RoboCow, PublishObject, ObjectFactory
2
+
3
+ from .meta import meta_information
4
+
5
+ bot = RoboCow.create(
6
+ handle="rooster",
7
+ name="The crowing rooster 🐓",
8
+ meta_information=meta_information,
9
+ )
10
+
11
+
12
+ @bot.cron("42 * * * *")
13
+ async def crow(publisher: PublishObject, object_factory: ObjectFactory):
14
+ await publisher(
15
+ object_factory.note(content="cock-a-doodle-doo").as_public().build() # type: ignore
16
+ )
@@ -0,0 +1,23 @@
1
+ from roboherd import RoboCow, MarkdownPoster
2
+
3
+ # from roboherd import PublishObject, ObjectFactory
4
+
5
+ from .meta import meta_information
6
+
7
+ bot = RoboCow.create(
8
+ name="The scare crow 👩‍🌾",
9
+ description="""On startup I scare crows""",
10
+ handle="scarecrow",
11
+ meta_information=meta_information,
12
+ )
13
+
14
+
15
+ # @bot.startup
16
+ # async def startup(publish_object: PublishObject, object_factory: ObjectFactory):
17
+ # note = object_factory.note(content="Booo! 🐦").as_public().build() # type: ignore
18
+ # await publish_object(note)
19
+
20
+
21
+ @bot.startup
22
+ async def startup(poster: MarkdownPoster):
23
+ await poster("__Booo!__ 🐦")
@@ -1,9 +1,32 @@
1
+ from pydantic import BaseModel, Field
2
+
1
3
  from dataclasses import dataclass, field
2
4
 
3
5
  from roboherd.cow import RoboCow
4
6
  from .load import load_cow
5
7
 
6
8
 
9
+ class ConfigOverrides(BaseModel):
10
+ """Values used in `roboherd.toml` to overide the default
11
+ values in the imported cow. This class is meant as a
12
+ reference, and not meant to be directly used."""
13
+
14
+ name: str | None = Field(
15
+ default=None, description="set to override the name", examples=["New name"]
16
+ )
17
+ handle: str | None = Field(
18
+ default=None, description="set to override the handle", examples=["new-handle"]
19
+ )
20
+ base_url: str | None = Field(
21
+ default=None,
22
+ description="set to override the base url",
23
+ examples=["https://other.example"],
24
+ )
25
+ skip_profile_update: bool | None = Field(
26
+ default=None, description="set to skip updating the profile", examples=[True]
27
+ )
28
+
29
+
7
30
  @dataclass
8
31
  class CowConfig:
9
32
  name: str = field(metadata={"description": "Name of the cow, must be unique"})
@@ -20,13 +43,14 @@ class CowConfig:
20
43
  def load(self) -> RoboCow:
21
44
  cow = load_cow(self.module, self.attribute)
22
45
 
23
- if "name" in self.config:
24
- cow.information.name = self.config["name"]
25
- if "handle" in self.config:
26
- cow.information.handle = self.config["handle"]
46
+ overrides = ConfigOverrides(**self.config)
47
+
48
+ for value in ["name", "handle", "base_url"]:
49
+ if getattr(overrides, value):
50
+ setattr(cow.information, value, getattr(overrides, value))
27
51
 
28
- if "base_url" in self.config:
29
- cow.internals.base_url = self.config["base_url"]
52
+ if overrides.skip_profile_update:
53
+ cow.skip_profile_update = overrides.skip_profile_update
30
54
 
31
55
  return cow
32
56
 
@@ -44,6 +44,7 @@ def test_from_name_and_dict_with_new_name():
44
44
  "bot": "roboherd.examples.moocow:moocow",
45
45
  "handle": "new_handle",
46
46
  "name": "new name",
47
+ "skip_profile_update": True,
47
48
  }
48
49
 
49
50
  config = CowConfig.from_name_and_dict(name, value)
@@ -52,6 +53,7 @@ def test_from_name_and_dict_with_new_name():
52
53
 
53
54
  assert cow.information.name == "new name"
54
55
  assert cow.information.handle == "new_handle"
56
+ assert cow.skip_profile_update is True
55
57
 
56
58
 
57
59
  def test_load_config(test_config):
@@ -15,11 +15,11 @@ wheels = [
15
15
 
16
16
  [[package]]
17
17
  name = "aiohappyeyeballs"
18
- version = "2.4.6"
18
+ version = "2.4.8"
19
19
  source = { registry = "https://pypi.org/simple" }
20
- sdist = { url = "https://files.pythonhosted.org/packages/08/07/508f9ebba367fc3370162e53a3cfd12f5652ad79f0e0bfdf9f9847c6f159/aiohappyeyeballs-2.4.6.tar.gz", hash = "sha256:9b05052f9042985d32ecbe4b59a77ae19c006a78f1344d7fdad69d28ded3d0b0", size = 21726 }
20
+ sdist = { url = "https://files.pythonhosted.org/packages/de/7c/79a15272e88d2563c9d63599fa59f05778975f35b255bf8f90c8b12b4ada/aiohappyeyeballs-2.4.8.tar.gz", hash = "sha256:19728772cb12263077982d2f55453babd8bec6a052a926cd5c0c42796da8bf62", size = 22337 }
21
21
  wheels = [
22
- { url = "https://files.pythonhosted.org/packages/44/4c/03fb05f56551828ec67ceb3665e5dc51638042d204983a03b0a1541475b6/aiohappyeyeballs-2.4.6-py3-none-any.whl", hash = "sha256:147ec992cf873d74f5062644332c539fcd42956dc69453fe5204195e560517e1", size = 14543 },
22
+ { url = "https://files.pythonhosted.org/packages/52/0e/b187e2bb3eeb2644515109657c4474d65a84e7123de249bf1e8467d04a65/aiohappyeyeballs-2.4.8-py3-none-any.whl", hash = "sha256:6cac4f5dd6e34a9644e69cf9021ef679e4394f54e58a183056d12009e42ea9e3", size = 15005 },
23
23
  ]
24
24
 
25
25
  [[package]]
@@ -1363,7 +1363,7 @@ wheels = [
1363
1363
 
1364
1364
  [[package]]
1365
1365
  name = "roboherd"
1366
- version = "0.1.6"
1366
+ version = "0.1.8"
1367
1367
  source = { editable = "." }
1368
1368
  dependencies = [
1369
1369
  { name = "aiohttp" },
@@ -1,57 +0,0 @@
1
- import pytest
2
- from unittest.mock import AsyncMock
3
-
4
- from . import RoboCow
5
- from .types import Information
6
-
7
-
8
- @pytest.mark.parametrize(
9
- "name,summary,profile,expected",
10
- [
11
- ("moocow", None, None, True),
12
- ("moocow", None, {"id": "123"}, True),
13
- ("moocow", None, {"id": "123", "name": "moocow"}, False),
14
- ("moocow", None, {"id": "123", "name": "other"}, True),
15
- ("moocow", "description", {"id": "123", "name": "moocow"}, True),
16
- (
17
- "moocow",
18
- "description",
19
- {"id": "123", "name": "moocow", "summary": "description"},
20
- False,
21
- ),
22
- ],
23
- )
24
- def test_needs_update(name, summary, profile, expected):
25
- info = Information(
26
- handle="testcow",
27
- name=name,
28
- description=summary,
29
- )
30
- cow = RoboCow(information=info)
31
- cow.internals.profile = profile
32
-
33
- assert cow.needs_update() == expected
34
-
35
-
36
- def test_cron():
37
- info = Information(handle="testcow")
38
- cow = RoboCow(information=info)
39
-
40
- @cow.cron("* * * * *")
41
- async def test_func():
42
- pass
43
-
44
- assert len(cow.internals.cron_entries) == 1
45
-
46
-
47
- async def test_startup():
48
- info = Information(handle="testcow")
49
- cow = RoboCow(information=info)
50
- cow.internals.profile = {"id": "http://host.test/actor/cow"}
51
- mock = AsyncMock()
52
-
53
- cow.startup(mock)
54
-
55
- await cow.run_startup(AsyncMock())
56
-
57
- mock.assert_called_once()
File without changes
@@ -1,13 +0,0 @@
1
- from roboherd.cow import RoboCow
2
- from roboherd.cow.types import Information
3
-
4
- from .meta import meta_information
5
-
6
- bot = RoboCow(
7
- information=Information(
8
- name="/dev/null",
9
- description="""I don't do anything.""",
10
- handle="devnull",
11
- meta_information=meta_information,
12
- )
13
- )
@@ -1,22 +0,0 @@
1
- from roboherd.cow import RoboCow
2
- from roboherd.cow.types import Information
3
-
4
- from roboherd.annotations import PublishObject
5
- from roboherd.annotations.bovine import ObjectFactory
6
-
7
- from .meta import meta_information
8
-
9
- bot = RoboCow(
10
- information=Information(
11
- handle="rooster",
12
- name="The crowing rooster 🐓",
13
- meta_information=meta_information,
14
- )
15
- )
16
-
17
-
18
- @bot.cron("42 * * * *")
19
- async def crow(publisher: PublishObject, object_factory: ObjectFactory):
20
- await publisher(
21
- object_factory.note(content="cock-a-doodle-doo").as_public().build() # type: ignore
22
- )
@@ -1,27 +0,0 @@
1
- from roboherd.cow import RoboCow
2
- from roboherd.cow.types import Information
3
-
4
- from roboherd.annotations import PublishObject
5
- from roboherd.annotations.bovine import ObjectFactory
6
-
7
- from .meta import meta_information
8
-
9
- bot = RoboCow(
10
- information=Information(
11
- name="The scare crow 👩‍🌾",
12
- description="""On startup I scare crows""",
13
- handle="scarecrow",
14
- meta_information=meta_information,
15
- )
16
- )
17
-
18
-
19
- @bot.startup
20
- async def startup(publish_object: PublishObject, object_factory: ObjectFactory):
21
- note = object_factory.note(content="Booo! 🐦").as_public().build() # type: ignore
22
- await publish_object(note)
23
-
24
-
25
- # @bot.startup
26
- # async def startup(poster: MarkdownPoster):
27
- # await poster("__Booo!__ 🐦")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes