Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Handle 0.7 breaking changes and updates [SBK-369] #46

Merged
merged 10 commits into from
Jan 2, 2024
1 change: 0 additions & 1 deletion .mdformat.toml

This file was deleted.

10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.2.0
rev: v4.5.0
hooks:
- id: check-yaml

Expand All @@ -10,24 +10,24 @@ repos:
- id: isort

- repo: https://github.com/psf/black
rev: 23.7.0
rev: 23.12.0
hooks:
- id: black
name: black

- repo: https://github.com/pycqa/flake8
rev: 5.0.4
rev: 6.1.0
hooks:
- id: flake8

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.4.1
rev: v1.7.1
hooks:
- id: mypy
additional_dependencies: [types-setuptools, pydantic]

- repo: https://github.com/executablebooks/mdformat
rev: 0.7.14
rev: 0.7.17
hooks:
- id: mdformat
additional_dependencies: [mdformat-gfm, mdformat-frontmatter]
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ To run your bot against a live network, this SDK includes a simple runner you ca
$ silverback run "example:app" --network :mainnet:alchemy
```

**NOTE**: The example is designed to work with Python 3.9+, and we suggest using 3.11+ for speed.

## Docker Usage

```sh
Expand Down
2 changes: 1 addition & 1 deletion example.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Annotated
from typing import Annotated # NOTE: Only Python 3.9+

from ape import chain
from ape.api import BlockAPI
Expand Down
20 changes: 11 additions & 9 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@
extras_require = {
"test": [ # `test` GitHub Action jobs uses this
"pytest>=6.0", # Core testing package
"pytest-xdist", # multi-process runner
"pytest-xdist", # Multi-process runner
"pytest-cov", # Coverage analyzer plugin
"hypothesis>=6.2.0,<7.0", # Strategy-based fuzzer
],
"lint": [
"black>=23.7.0", # auto-formatter and linter
"mypy>=1.4.1,<2", # Static type analyzer
"black>=23.12.0,<24", # Auto-formatter and linter
"mypy>=1.7.1,<2", # Static type analyzer
"types-setuptools", # Needed for mypy type shed
"flake8>=5.0.4", # Style linter
"isort>=5.10.1", # Import sorting linter
"mdformat>=0.7.16", # Auto-formatter for markdown
"flake8>=6.1.0,<7", # Style linter
"isort>=5.10.1,<6", # Import sorting linter
"mdformat>=0.7.17", # Auto-formatter for markdown
"mdformat-gfm>=0.3.5", # Needed for formatting GitHub-flavored markdown
"mdformat-frontmatter>=0.4.1", # Needed for frontmatters-style headers in issue templates
"mdformat-pyproject>=0.0.1", # So we can keep config for mdformat in `pyproject.toml`
"mdformat-pyproject>=0.0.1", # Allows configuring in pyproject.toml
],
"doc": [
"myst-parser>=1.0.0,<2", # Parse markdown docs
Expand Down Expand Up @@ -67,9 +67,11 @@
url="https://github.com/ApeWorX/silverback",
include_package_data=True,
install_requires=[
"eth-ape>=0.6.19,<1.0",
"taskiq[metrics]>=0.6.0,<0.7.0",
"click", # Use same version as eth-ape
"eth-ape>=0.7.0,<1.0",
mikeshultz marked this conversation as resolved.
Show resolved Hide resolved
"eth-pydantic-types", # Use same version as eth-ape
"pydantic_settings", # Use same version as eth-ape
"taskiq[metrics]>=0.10.4,<0.11.0",
],
entry_points={
"console_scripts": ["silverback=silverback._cli:cli"],
Expand Down
48 changes: 34 additions & 14 deletions silverback/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
from concurrent.futures import ThreadPoolExecutor

import click
from ape.cli import AccountAliasPromptChoice, ape_cli_context, network_option, verbosity_option
from ape.cli import (
AccountAliasPromptChoice,
ConnectedProviderCommand,
ape_cli_context,
network_option,
verbosity_option,
)
from ape.exceptions import Abort
from taskiq import AsyncBroker
from taskiq.cli.worker.run import shutdown_broker
from taskiq.receiver import Receiver
Expand Down Expand Up @@ -36,10 +43,18 @@ def _account_callback(ctx, param, val):


def _network_callback(ctx, param, val):
if val:
os.environ["SILVERBACK_NETWORK_CHOICE"] = val
# NOTE: Make sure both of these have the same setting
if env_network_choice := os.environ.get("SILVERBACK_NETWORK_CHOICE"):
if val.network_choice != env_network_choice:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: @mikeshultz noticed if you use the shortened form in the environment variable, that the selection would be fully resolved and thus be mismatching

easy fix is to just update the environment variable to the fully resolved form

raise Abort(
f"Network choice '{val.network_choice}' does not "
f"match environment variable '{env_network_choice}'."
)

# else it matches, no issue

else:
val = os.environ.get("SILVERBACK_NETWORK_CHOICE", "")
os.environ["SILVERBACK_NETWORK_CHOICE"] = val.network_choice

return val

Expand All @@ -64,10 +79,13 @@ async def run_worker(broker: AsyncBroker, worker_count=2, shutdown_timeout=90):
await shutdown_broker(broker, shutdown_timeout)


@cli.command(help="Run Silverback application client")
@cli.command(cls=ConnectedProviderCommand, help="Run Silverback application client")
@ape_cli_context()
@verbosity_option()
@network_option(default=None, callback=_network_callback)
@network_option(
default=os.environ.get("SILVERBACK_NETWORK_CHOICE", "auto"),
callback=_network_callback,
)
@click.option("--account", type=AccountAliasPromptChoice(), callback=_account_callback)
@click.option(
"--runner",
Expand All @@ -76,22 +94,24 @@ async def run_worker(broker: AsyncBroker, worker_count=2, shutdown_timeout=90):
)
@click.option("-x", "--max-exceptions", type=int, default=3)
@click.argument("path")
def run(cli_ctx, network, account, runner, max_exceptions, path):
with cli_ctx.network_manager.parse_network_choice(network):
app = import_from_string(path)
runner = runner(app, max_exceptions=max_exceptions)
asyncio.run(runner.run())
def run(cli_ctx, account, runner, max_exceptions, path):
app = import_from_string(path)
runner = runner(app, max_exceptions=max_exceptions)
asyncio.run(runner.run())


@cli.command(help="Run Silverback application task workers")
@cli.command(cls=ConnectedProviderCommand, help="Run Silverback application task workers")
@ape_cli_context()
@verbosity_option()
@network_option(default=None, callback=_network_callback)
@network_option(
default=os.environ.get("SILVERBACK_NETWORK_CHOICE", "auto"),
callback=_network_callback,
)
@click.option("--account", type=AccountAliasPromptChoice(), callback=_account_callback)
@click.option("-w", "--workers", type=int, default=2)
@click.option("-x", "--max-exceptions", type=int, default=3)
@click.option("-s", "--shutdown_timeout", type=int, default=90)
@click.argument("path")
def worker(cli_ctx, network, account, workers, max_exceptions, shutdown_timeout, path):
def worker(cli_ctx, account, workers, max_exceptions, shutdown_timeout, path):
app = import_from_string(path)
asyncio.run(run_worker(app.broker, worker_count=workers, shutdown_timeout=shutdown_timeout))
8 changes: 4 additions & 4 deletions silverback/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def get_startup_handler(self) -> Optional[AsyncTaskiqDecoratedTask]:
Returns:
Optional[AsyncTaskiqDecoratedTask]: Returns decorated task, if one has been created.
"""
return self.broker.available_tasks.get("silverback_startup")
return self.broker.find_task("silverback_startup")

def get_shutdown_handler(self) -> Optional[AsyncTaskiqDecoratedTask]:
"""
Expand All @@ -136,7 +136,7 @@ def get_shutdown_handler(self) -> Optional[AsyncTaskiqDecoratedTask]:
Returns:
Optional[AsyncTaskiqDecoratedTask]: Returns decorated task, if one has been created.
"""
return self.broker.available_tasks.get("silverback_shutdown")
return self.broker.find_task("silverback_shutdown")

def get_block_handler(self) -> Optional[AsyncTaskiqDecoratedTask]:
"""
Expand All @@ -145,7 +145,7 @@ def get_block_handler(self) -> Optional[AsyncTaskiqDecoratedTask]:
Returns:
Optional[AsyncTaskiqDecoratedTask]: Returns decorated task, if one has been created.
"""
return self.broker.available_tasks.get("block")
return self.broker.find_task("block")

def get_event_handler(
self, event_target: AddressType, event_name: str
Expand All @@ -160,7 +160,7 @@ def get_event_handler(
Returns:
Optional[AsyncTaskiqDecoratedTask]: Returns decorated task, if one has been created.
"""
return self.broker.available_tasks.get(f"{event_target}/event/{event_name}")
return self.broker.find_task(f"{event_target}/event/{event_name}")

def on_(
self,
Expand Down
2 changes: 1 addition & 1 deletion silverback/middlewares.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def pre_execute(self, message: TaskiqMessage) -> TaskiqMessage:

elif "event" in message.task_name:
# NOTE: Just in case the user doesn't specify type as `ContractLog`
message.args[0] = ContractLog.parse_obj(message.args[0])
message.args[0] = ContractLog.model_validate(message.args[0])

logger.info(f"{self._create_label(message)} - Started")
return message
Expand Down
6 changes: 2 additions & 4 deletions silverback/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from ape.api import AccountAPI, ProviderContextManager
from ape.utils import ManagerAccessMixin
from pydantic import BaseSettings
from pydantic_settings import BaseSettings, SettingsConfigDict
from taskiq import AsyncBroker, InMemoryBroker, PrometheusMiddleware, TaskiqMiddleware

from ._importer import import_from_string
Expand Down Expand Up @@ -38,9 +38,7 @@ class Settings(BaseSettings, ManagerAccessMixin):
# Used for persistent store
PERSISTENCE_CLASS: Optional[str] = None

class Config:
env_prefix = "SILVERBACK_"
case_sensitive = True
model_config = SettingsConfigDict(env_prefix="SILVERBACK_", case_sensitive=True)

def get_broker(self) -> AsyncBroker:
broker_class = import_from_string(self.BROKER_CLASS)
Expand Down