Skip to content

Commit

Permalink
Migrate cryptocurrency.py to use pydantic models
Browse files Browse the repository at this point in the history
  • Loading branch information
linuxdaemon committed Apr 14, 2024
1 parent e36fd90 commit 47c3d80
Show file tree
Hide file tree
Showing 15 changed files with 337 additions and 565 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,4 @@ config.json
.vagrant/
.mypy_cache/
.DS_Store
*.bak
12 changes: 9 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ci:
exclude: ^\.vscode/.*$
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: c4a0b883114b00d8d76b479c820ce7950211c99b # frozen: v4.5.0
rev: 2c9f875913ee60ca25ce70243dc24d5b6415598c # frozen: v4.6.0
hooks:
- id: trailing-whitespace
args: ['--markdown-linebreak-ext=md,markdown']
Expand Down Expand Up @@ -36,7 +36,7 @@ repos:
args:
- --remove
- repo: https://github.com/psf/black
rev: 6fdf8a4af28071ed1d079c01122b34c5d587207a # frozen: 24.2.0
rev: 8fe627072f15ff2e3d380887b92f7868efaf6d05 # frozen: 24.4.0
hooks:
- id: black
- repo: https://github.com/pycqa/isort
Expand All @@ -49,12 +49,18 @@ repos:
- id: python-no-eval
- id: python-no-log-warn
- repo: https://github.com/asottile/pyupgrade
rev: df17dfa3911b81b4a27190b0eea5b1debc7ffa0a # frozen: v3.15.1
rev: 12af25eb252deaaecb6b259df40d01f42e716dc3 # frozen: v3.15.2
hooks:
- id: pyupgrade
args:
- "--py38-plus"

- repo: https://github.com/PyCQA/autoflake
rev: 0544741e2b4a22b472d9d93e37d4ea9153820bb1 # frozen: v2.3.1
hooks:
- id: autoflake


- repo: local
hooks:
- id: mypy
Expand Down
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
"editor.formatOnType": true,
"editor.wordBasedSuggestions": "off",
"editor.defaultFormatter": "ms-python.black-formatter"
}
},
"python.analysis.diagnosticMode": "workspace"
}
9 changes: 6 additions & 3 deletions cloudbot/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import time
from collections import OrderedDict
from pathlib import Path
from typing import Dict, Optional, cast

logger = logging.getLogger("cloudbot")

Expand All @@ -15,19 +16,21 @@ def __init__(self, bot, *, filename="config.json"):
self.path = Path(self.filename).resolve()
self.bot = bot

self._api_keys = {}
self._api_keys: Dict[str, Optional[str]] = {}

# populate self with config data
self.load_config()

def get_api_key(self, name, default=None):
def get_api_key(
self, name: str, default: Optional[str] = None
) -> Optional[str]:
try:
return self._api_keys[name]
except LookupError:
self._api_keys[name] = value = self.get("api_keys", {}).get(
name, default
)
return value
return cast(Optional[str], value)

def load_config(self):
"""(re)loads the bot config from the config file"""
Expand Down
4 changes: 2 additions & 2 deletions cloudbot/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import enum
import logging
from functools import partial
from typing import Any, Iterator, Mapping
from typing import Any, Iterator, Mapping, Optional

from irclib.parser import Message

Expand Down Expand Up @@ -245,7 +245,7 @@ def admin_log(self, message, broadcast=False):
if conn and conn.connected:
conn.admin_log(message, console=not broadcast)

def reply(self, *messages, target=None):
def reply(self, *messages: str, target: Optional[str] = None) -> None:
"""sends a message to the current channel/user with a prefix"""
reply_ping = self.conn.config.get("reply_ping", True)
if target is None:
Expand Down
68 changes: 61 additions & 7 deletions cloudbot/hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@
import re
import warnings
from enum import Enum, IntEnum, unique
from typing import (
Any,
Callable,
List,
Optional,
Sequence,
TypeVar,
Union,
overload,
)

from typing_extensions import ParamSpec

from cloudbot.event import EventType
from cloudbot.util import HOOK_ATTR
Expand Down Expand Up @@ -186,10 +198,36 @@ def _hook_warn():
)


def command(*args, **kwargs):
_T = TypeVar("_T")
_P = ParamSpec("_P")
_Func = Callable[_P, _T]


@overload
def command(arg: Callable[_P, _T], /) -> Callable[_P, _T]: ...


@overload
def command(
arg: Optional[Union[str, Sequence[str]]] = None,
/,
*args: Union[str, Sequence[str]],
**kwargs: Any,
) -> Callable[[Callable[_P, _T]], Callable[_P, _T]]: ...


def command(
arg: Optional[Union[Callable[_P, _T], str, Sequence[str]]] = None,
/,
*args: Union[str, Sequence[str]],
**kwargs: Any,
) -> Union[Callable[_P, _T], Callable[[Callable[_P, _T]], Callable[_P, _T]]]:
"""External command decorator. Can be used directly as a decorator, or with args to return a decorator."""

def _command_hook(func, alias_param=None):
def _command_hook(
func: Callable[_P, _T],
alias_param: Optional[Sequence[Union[Sequence[str], str]]] = None,
) -> Callable[_P, _T]:
hook = _get_hook(func, "command")
if hook is None:
hook = _CommandHook(func)
Expand All @@ -198,13 +236,17 @@ def _command_hook(func, alias_param=None):
hook.add_hook(alias_param, kwargs)
return func

if len(args) == 1 and callable(args[0]):
if arg is not None and not isinstance(arg, (str, collections.abc.Sequence)):
# this decorator is being used directly
_hook_warn()
return _command_hook(args[0])
return _command_hook(arg)

arg_list: List[Union[str, Sequence[str]]] = list(args)
if arg:
arg_list.insert(0, arg)

# this decorator is being used indirectly, so return a decorator function
return lambda func: _command_hook(func, alias_param=args)
return lambda func: _command_hook(func, alias_param=arg_list)


def irc_raw(triggers_param, **kwargs):
Expand Down Expand Up @@ -332,10 +374,22 @@ def _config_hook(func):
return _config_hook


def on_start(param=None, **kwargs):
@overload
def on_start(
**kwargs: Any,
) -> Callable[[Callable[_P, _T]], Callable[_P, _T]]: ...


@overload
def on_start(param: Callable[_P, _T], /) -> Callable[_P, _T]: ...


def on_start(
param: Optional[Callable[_P, _T]] = None, /, **kwargs: Any
) -> Union[Callable[_P, _T], Callable[[Callable[_P, _T]], Callable[_P, _T]]]:
"""External on_start decorator. Can be used directly as a decorator, or with args to return a decorator"""

def _on_start_hook(func):
def _on_start_hook(func: Callable[_P, _T]) -> Callable[_P, _T]:
hook = _get_hook(func, "on_start")
if hook is None:
hook = _Hook(func, "on_start")
Expand Down
2 changes: 1 addition & 1 deletion cloudbot/util/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def get_available_colours():
return ret[:-2]


def parse(string):
def parse(string: str) -> str:
"""
parse: Formats a string, replacing words wrapped in $( ) with actual colours or formatting.
example:
Expand Down
10 changes: 9 additions & 1 deletion cloudbot/util/func_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import inspect
from typing import Any, Callable, Mapping, TypeVar


class ParameterError(Exception):
Expand All @@ -12,7 +13,14 @@ def __init__(self, name, valid_args):
self.valid_args = list(valid_args)


def call_with_args(func, arg_data):
_T = TypeVar("_T")


def call_with_args(func: Callable[..., _T], arg_data: Mapping[str, Any]) -> _T:
"""
>>> call_with_args(lambda a: a, {'a':1, 'b':2})
1
"""
sig = inspect.signature(func, follow_wrapped=False)
try:
args = [
Expand Down
Loading

0 comments on commit 47c3d80

Please sign in to comment.