Ruby-Cogs/dev/env.py
2025-04-02 22:56:57 -04:00

996 lines
36 KiB
Python

import asyncio
import builtins
import collections
import datetime
import functools
import importlib
import inspect
import logging
import os
import re
import sys
import textwrap
import time
import traceback
import types
from contextvars import ContextVar
from functools import partial
from io import BytesIO, StringIO
import aiohttp
import discord.ext
import redbot
import rich
from AAA3A_utils.cog import Cog
from AAA3A_utils.cogsutils import CogsUtils
from AAA3A_utils.context import Context, is_dev
from AAA3A_utils.loop import Loop
from AAA3A_utils.menus import Menu, Reactions
from AAA3A_utils.sentry import SentryHelper
from AAA3A_utils.settings import Settings
from AAA3A_utils.shared_cog import SharedCog
from AAA3A_utils.views import (
Buttons,
ChannelSelect,
ConfirmationAskView,
Dropdown,
MentionableSelect,
Modal,
RoleSelect,
Select,
UserSelect,
) # NOQA
from redbot.core import Config, dev_commands
from redbot.core import utils as redutils
from redbot.core.utils import chat_formatting as cf
from redbot.core.utils.chat_formatting import box
from rich.console import Console
from rich.table import Table
from redbot.core import commands # isort:skip
from redbot.core.bot import Red # isort:skip
import discord # isort:skip
import typing # isort:skip
ctxconsole = ContextVar[rich.console.Console]("ctxconsole")
class Exit(BaseException):
pass
def no_colour_rich_markup(
*objects: typing.Any, lang: str = "", no_box: typing.Optional[bool] = False
) -> str:
"""
Slimmed down version of rich_markup which ensure no colours (/ANSI) can exist
https://github.com/Cog-Creators/Red-DiscordBot/pull/5538/files (Kowlin)
"""
temp_console = Console( # Prevent messing with STDOUT's console
color_system=None,
file=StringIO(),
force_terminal=True,
width=80,
)
temp_console.print(*objects)
if no_box:
return temp_console.file.getvalue()
return box(temp_console.file.getvalue(), lang=lang) # type: ignore
class DevSpace:
def __init__(self, **kwargs) -> None:
self.__dict__.update(**kwargs)
def __repr__(self) -> str:
items = [f"{k}={v!r}" for k, v in self.__dict__.items()]
return (
f"<{self.__class__.__name__} {' '.join(items)}>"
if items
else f"<{self.__class__.__name__} [Nothing]>"
)
def __eq__(self, other: object) -> bool:
if isinstance(self, self.__class__) and isinstance(other, self.__class__):
return self.__dict__ == other.__dict__
return NotImplemented
def __len__(self) -> int:
return len(self.__dict__)
def __contains__(self, key: str) -> typing.Any:
return key in self.__dict__
def __iter__(self) -> typing.Iterator[typing.Tuple[str, typing.Any]]:
yield from self.__dict__.items()
def __reversed__(self) -> typing.Dict:
return self.__dict__.__reversed__()
def __getattr__(self, attr: str) -> typing.Any:
raise AttributeError(attr)
def __setattr__(self, attr: str, value: typing.Any) -> None:
self.__dict__[attr] = value
def __delattr__(self, attr: str) -> None:
del self.__dict__[attr]
def __getitem__(self, key: str) -> typing.Any:
return self.__dict__[key]
def __setitem__(self, key: str, value: typing.Any) -> None:
self.__dict__[key] = value
def __delitem__(self, key: str) -> None:
del self.__dict__[key]
def clear(self) -> None:
self.__dict__.clear()
def update(self, **kwargs) -> None:
self.__dict__.update(**kwargs)
def copy(self) -> typing.Any: # typing_extensions.Self
return self.__class__(**self.__dict__)
def items(self):
return self.__dict__.items()
def keys(self):
return self.__dict__.keys()
def values(self):
return self.__dict__.values()
def get(self, key: str, _default: typing.Optional[typing.Any] = None) -> typing.Any:
return self.__dict__.get(key, _default)
def pop(self, key: str, _default: typing.Optional[typing.Any] = None) -> typing.Any:
return self.__dict__.pop(key, _default)
def popitem(self) -> typing.Any:
return self.__dict__.popitem()
def _update_with_defaults(
self, defaults: typing.Iterable[typing.Tuple[str, typing.Any]]
) -> None:
for key, value in defaults:
self.__dict__.setdefault(key, value)
class DevEnv(typing.Dict[str, typing.Any]):
is_dev = is_dev
def __init__(self, *args, **kwargs) -> None:
# self.__dict__ = {}
super().__init__(*args, **kwargs)
self.imported: typing.List[typing.Union[str, typing.Tuple[str, str]]] = []
@classmethod
def get_environment(
cls, ctx: commands.Context, use_extended_environment: bool = True
) -> typing.Dict[str, typing.Any]:
env = cls( # In Dev cog by Zeph.
**{
"me": ctx.me,
# Redirect builtin console functions to rich.
"print": rich.print,
"help": functools.partial(rich.inspect, help=True),
# Eval and exec automatically put this in, but types.FunctionType does not.
"__builtins__": builtins,
# Fill in various other environment keys that some code might expect.
"__builtin__": builtins,
"__doc__": ctx.command.help,
"__package__": None,
"__loader__": None,
"__spec__": None,
}
)
env["interaction"] = ctx.interaction
if getattr(ctx.channel, "category", None) is not None:
env["category"] = ctx.channel.category
Dev = ctx.bot.get_cog("Dev")
if use_extended_environment:
env.update(cls.get_env(ctx.bot, ctx)) # My nice env!
base_env = dev_commands.Dev.get_environment(Dev, ctx) # In Dev in Core.
# del base_env["_"]
env.update(base_env)
env.update({"dev_env": env, "devenv": env})
return env
def get_formatted_env(
self,
ctx: typing.Optional[commands.Context] = None,
show_values: typing.Optional[bool] = True,
) -> str:
if show_values:
raw_table = Table(
"Key",
"Value",
title="------------------------------ DevEnv ------------------------------",
)
else:
raw_table = Table(
"Key", title="------------------------------ DevEnv ------------------------------"
)
for name, value in self.items():
if name in self.imported:
continue
if show_values:
raw_table.add_row(str(name), repr(value))
else:
raw_table.add_row(str(name))
raw_table_str = no_colour_rich_markup(raw_table, no_box=True)
raw_table_str = self.sanitize_output(self.get("ctx", ctx), raw_table_str)
if ctx is not None:
asyncio.create_task(Menu(pages=raw_table_str, lang="py").start(ctx))
return raw_table_str
def get_formatted_imports(self) -> str:
if not (imported := self.imported):
return ""
imported.sort(key=lambda x: x if isinstance(x, str) else f"z{x[0]}")
message = "".join(
(
f">>> import {_import}\n"
if isinstance(_import, str)
else f">>> from {_import[0]} import {_import[1]}\n"
)
for _import in imported
)
imported.clear()
return message
def __missing__(self, key: str) -> typing.Any:
try:
if (value := self["devspace"].get(key)) is not None:
return value
except (KeyError, AttributeError):
pass
if not self.get("auto_imports", True):
raise KeyError(key)
if key in {"exit", "quit"}:
raise Exit()
try:
# this is called implicitly after KeyError, but
# some modules would overwrite builtins (e.g. bin)
return getattr(builtins, key)
except AttributeError:
pass
try:
module = importlib.import_module(key)
except ImportError:
pass
else:
self.imported.append(key)
self[key] = module
return module
try:
if (cog := self["bot"].get_cog(key)) is not None:
self[key] = cog
return cog
except (KeyError, AttributeError):
pass
if key.lower().startswith("id"):
_id = key[2:] if key[2] != "_" else key[3:]
try:
_id = int(_id)
except ValueError:
pass
else:
try:
if (member := self["guild"].get_member(_id)) is not None:
self[key] = member
return member
except (KeyError, AttributeError):
pass
try:
if (user := self["bot"].get_user(_id)) is not None:
self[key] = user
return user
except (KeyError, AttributeError):
pass
try:
if (guild := self["bot"].get_guild(_id)) is not None:
self[key] = guild
return guild
except (KeyError, AttributeError):
pass
try:
if (channel := self["guild"].get_channel(_id)) is not None:
self[key] = channel
return channel
except (KeyError, AttributeError):
pass
try:
if (role := self["guild"].get_role(_id)) is not None:
self[key] = role
return role
except (KeyError, AttributeError):
pass
try:
if (message := self["channel"].get_partial_message(_id)) is not None:
self[key] = message
return message
except (KeyError, AttributeError):
pass
if (attr := getattr(discord, key, None)) is not None:
self.imported.append(("discord", key))
self[key] = attr
return attr
if (attr := getattr(typing, key, None)) is not None:
self.imported.append(("typing", key))
self[key] = attr
return attr
if (attr := getattr(cf, key, None)) is not None:
self.imported.append(("redbot.core.utils.chat_formatting", key))
self[key] = attr
return attr
try:
if is_dev(bot=self["bot"]) and (attr := getattr(CogsUtils, key, None)) is not None:
self.imported.append(("AAA3A_utils.CogsUtils", key))
self[key] = attr
return attr
except (KeyError, AttributeError):
pass
raise KeyError(key)
@staticmethod
def sanitize_output(ctx: commands.Context, input_: str) -> str:
"""Hides the bot's token from a string."""
token = ctx.bot.http.token
input_ = CogsUtils.replace_var_paths(input_)
return re.sub(re.escape(token), "[EXPUNGED]", input_, re.I)
@classmethod
def get_env(
cls, bot: Red, ctx: typing.Optional[commands.Context] = None
) -> typing.Dict[str, typing.Any]:
logger = CogsUtils.get_logger(name="Test")
def where(name_or_module: typing.Union[str, types.MethodType]) -> str:
name = (
name_or_module
if isinstance(name_or_module, str)
else (getattr(name_or_module, "__module__", None) or name_or_module.__name__)
).replace("-", "_")
spec = importlib.util.find_spec(name)
if spec is None:
raise RuntimeError("Module `{name}` not found.".format(name=name))
return spec.origin
async def _rtfs(ctx: commands.Context, object):
code = inspect.getsource(object)
await Menu(pages=code, lang="py").start(ctx)
def reference(ctx: commands.Context) -> typing.Optional[discord.Message]:
if ctx.message.reference is not None and isinstance(
ctx.message.reference.resolved, discord.Message
):
return ctx.message.reference.resolved
# def _console_custom(ctx: commands.Context):
# return {"width": 80, "color_system": None}
def search_attribute(
a, b: typing.Optional[str] = "", startswith: typing.Optional[str] = ""
) -> typing.List[str]:
return [
x
for x in dir(a)
if b.lower() in x.lower() and x.lower().startswith(startswith.lower())
]
async def run_converter(
converter: typing.Any, argument: str, label: typing.Optional[str] = "test"
) -> typing.Any:
param = discord.ext.commands.parameters.Parameter(
name=label, kind=inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=converter
)
return await discord.ext.commands.converter.run_converters(
ctx, converter=param.converter, argument=argument, param=param
)
async def run_converters(
command_or_function: typing.Union[str, commands.Command, typing.Callable],
arguments: str,
) -> typing.Dict[str, typing.Any]:
if isinstance(command_or_function, str):
if (command := ctx.bot.get_command(command_or_function)) is None:
raise RuntimeError()
elif isinstance(command_or_function, commands.Command):
command = command_or_function
else:
command = commands.Command(command_or_function)
view = discord.ext.commands.view.StringView(arguments)
fake_context = type(
"FakeContext",
(),
{
"bot": ctx.bot,
"command": command,
"message": ctx.message,
"prefix": None,
"view": view,
},
)
await command._parse_arguments(fake_context)
kwargs = {}
for i, arg in enumerate(fake_context.args[1:]):
kwargs[list(command.params.keys())[i]] = arg
kwargs.update(fake_context.kwargs)
return kwargs
def get_internal(ctx: commands.Context):
def _get_internal(
name: typing.Literal["events", "listeners", "loggers", "parsers", "converters"],
b: typing.Optional[str] = "",
startswith: typing.Optional[str] = "",
):
if name == "events":
if b == "":
result = ctx.bot.extra_events.copy()
else:
return ctx.bot.extra_events[b]
elif name == "listeners":
if b == "":
result = ctx.bot._listeners.copy()
else:
return ctx.bot._listeners[b]
elif name == "loggers":
result = logging.Logger.manager.loggerDict.copy()
elif name == "parsers":
result = ctx.bot._get_websocket(0)._discord_parsers.copy()
elif name == "converters":
result = discord.ext.commands.converter.CONVERTER_MAPPING.copy()
else:
raise ValueError(name)
result = {
name: value
for name, value in result.items()
if b.lower() in name.lower() and name.lower().startswith(startswith.lower())
}
return result
return _get_internal
def set_loggers_level(
level: typing.Optional[str] = logging.DEBUG,
loggers: typing.Optional[typing.List] = None,
exclusions: typing.Optional[typing.List] = None,
b: typing.Optional[str] = "",
startswith: typing.Optional[str] = "",
) -> int:
__loggers = logging.Logger.manager.loggerDict
if loggers is not None:
_loggers = [
logger
for name, logger in __loggers.items()
if name in loggers and isinstance(logger, logging.Logger)
]
else:
_loggers = [
logger for logger in __loggers.values() if isinstance(logger, logging.Logger)
]
_loggers = [
logger
for logger in _loggers
if b.lower() in logger.name and logger.name.lower().startswith(startswith.lower())
]
if exclusions is not None:
_loggers = [logger for logger in _loggers if logger.name not in exclusions]
for logger in _loggers:
logger.setLevel(level)
return len(_loggers)
def params(_object: typing.Any) -> None:
return {param.name: param for param in inspect.signature(_object).parameters.values()}
def find_all(predicate, iterable: collections.abc.Iterable) -> typing.List[typing.Any]:
if hasattr(iterable, "__aiter__"):
async def _a_find_all():
return [element async for element in iterable if predicate(element)]
return _a_find_all()
else:
return [element for element in iterable if predicate(element)]
def get_all(iterable: collections.abc.Iterable, **attrs) -> typing.List[typing.Any]:
attrget = discord.utils.attrgetter
converted = [
(attrget(attr.replace("__", ".")), value) for attr, value in attrs.items()
]
if hasattr(iterable, "__aiter__"):
async def _a_get_all():
return [
element
async for element in iterable
if all(pred(element) == value for pred, value in converted)
]
return _a_get_all()
else:
return [
element
for element in iterable
if all(pred(element) == value for pred, value in converted)
]
dev_space: DevSpace = getattr(ctx.bot.get_cog("Dev"), "dev_space", AttributeError())
def get_url(ctx: commands.Context):
async def _get_url(url: str, **kwargs):
async with ctx.bot.get_cog("Dev")._session.get(url=url, **kwargs) as r:
return r
return _get_url
if is_dev(bot=bot):
env = {
# CogsUtils
"CogsUtils": lambda ctx: CogsUtils,
"Loop": lambda ctx: Loop,
"Reactions": lambda ctx: Reactions,
"Menu": lambda ctx: Menu,
"SharedCog": lambda ctx: SharedCog,
"Cog": lambda ctx: Cog,
"Context": lambda ctx: Context,
"Settings": lambda ctx: Settings,
"SentryHelper": lambda ctx: SentryHelper,
"logger": lambda ctx: logger,
"_rtfs": lambda ctx: partial(_rtfs, ctx),
"DevEnv": lambda ctx: cls,
"DevSpace": lambda ctx: DevSpace,
"Cogs": lambda ctx: CogsCommands.Cogs(
bot=ctx.bot, Cog=CogsCommands.Cog, Command=CogsCommands.Command
),
"Commands": lambda ctx: CogsCommands.Commands(
bot=ctx.bot, Cog=CogsCommands.Cog, Command=CogsCommands.Command
),
}
# Dpy2 things
env.update(
{
"ConfirmationAskView": lambda ctx: ConfirmationAskView,
"Buttons": lambda ctx: Buttons,
"Dropdown": lambda ctx: Dropdown,
"Select": lambda ctx: Select,
"ChannelSelect": lambda ctx: ChannelSelect,
"MentionableSelect": lambda ctx: MentionableSelect,
"RoleSelect": lambda ctx: RoleSelect,
"UserSelect": lambda ctx: UserSelect,
"Modal": lambda ctx: Modal,
}
)
else:
env = {}
env.update(
{
# Dpy & Red
"discord": lambda ctx: discord,
"redbot": lambda ctx: redbot,
"Red": lambda ctx: Red,
"redutils": lambda ctx: redutils,
"cf": lambda ctx: cf,
"Config": lambda ctx: Config,
"run_converter": lambda ctx: run_converter,
"run_converters": lambda ctx: run_converters,
"Route": lambda ctx: discord.http.Route,
"websocket": lambda ctx: ctx.bot._get_websocket(ctx.guild.id),
"get_internal": get_internal,
"set_loggers_level": lambda ctx: set_loggers_level,
"find": lambda ctx: discord.utils.find,
"get": lambda ctx: discord.utils.get,
"MISSING": lambda ctx: discord.utils.MISSING,
"escape_markdown": lambda ctx: discord.utils.escape_markdown,
"as_chunks": lambda ctx: discord.utils.as_chunks,
"format_dt": lambda ctx: discord.utils.format_dt,
# Ty Lemon.
"params": lambda ctx: params,
"find_all": lambda ctx: find_all,
"get_all": lambda ctx: get_all,
# Dev Space
"dev_space": lambda ctx: dev_space,
"devspace": lambda ctx: dev_space,
# Typing
"typing": lambda ctx: typing,
# Inspect
"inspect": lambda ctx: inspect,
"source": lambda ctx: lambda _object: rich.print(
textwrap.dedent(inspect.getsource(_object)).strip()
),
"gs": lambda ctx: lambda _object: rich.print(
textwrap.dedent(inspect.getsource(_object)).strip()
),
# "gs": lambda ctx: inspect.getsource,
# logging
"logging": lambda ctx: logging,
# Date & Time
"datetime": lambda ctx: datetime,
"time": lambda ctx: time,
"utc_now": lambda ctx: datetime.datetime.now(tz=datetime.timezone.utc),
"local_now": lambda ctx: datetime.datetime.now(),
"get_utc_now": lambda ctx: functools.partial(
datetime.datetime.now, tz=datetime.timezone.utc
),
"get_local_now": lambda ctx: datetime.datetime.now,
# Os & Sys
"os": lambda ctx: os,
"sys": lambda ctx: sys,
# Aiohttp
"aiohttp": lambda ctx: aiohttp,
"session": lambda ctx: ctx.bot.get_cog("Dev")._session,
"get_url": get_url,
"BytesIO": lambda ctx: BytesIO,
# TextWrap
"textwrap": lambda ctx: textwrap,
# Search attributes
"search_attrs": lambda ctx: search_attribute,
# search python library
"where": lambda ctx: where,
# `reference`
"reference": reference,
# No color (Dev cog from fluffy-cogs in mobile).
# "_console_custom": _console_custom,
# Dpy get
"get_cog": lambda ctx: ctx.bot.get_cog,
"get_command": lambda ctx: ctx.bot.get_command,
"get_guild": lambda ctx: ctx.bot.get_guild,
"get_channel": lambda ctx: ctx.guild.get_channel,
"fetch_message": lambda ctx: ctx.channel.fetch_message,
# Fake
"token": lambda ctx: "[EXPUNGED]",
}
)
if ctx is not None:
_env = {}
for name, value in env.items():
try:
_env[name] = value(ctx)
except Exception as exc:
traceback.clear_frames(exc.__traceback__)
_env[name] = exc
else:
_env = env
return _env
class CogsCommands:
class Cog(commands.Cog):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
@classmethod
def _setup(cls, bot: Red, Cog, Command, cog) -> typing.Any: # typing_extensions.Self
c = cls()
c.__dict__ = cog.__dict__
c.__cog_name__ = cog.__cog_name__
c.bot = bot
c.Cog = Cog
c.Command = Command
c.original_object = cog
return c
def __repr__(self) -> str:
if getattr(self, "original_object", None) is not None:
return repr(self.original_object)
return super().__repr__()
def __len__(self) -> int:
cog = self
source = {
command.name: command
for command in self.bot.all_commands.values()
if getattr(command.cog, "qualified_name", None)
== getattr(cog, "qualified_name", None)
}
return len(source)
def __contains__(self, key: str) -> bool:
cog = self
source = {
command.name: command
for command in self.bot.all_commands.values()
if getattr(command.cog, "qualified_name", None)
== getattr(cog, "qualified_name", None)
}
return key in source
def __iter__(self) -> typing.Iterator[typing.Tuple[str, typing.Any]]:
cog = self
source = {
command.name: command
for command in self.bot.all_commands.values()
if getattr(command.cog, "qualified_name", None)
== getattr(cog, "qualified_name", None)
}
_items = source
items = {
key: self.Command._setup(
bot=self.bot, Cog=self.Cog, Command=self.Command, command=value
)
for key, value in _items.items()
}
yield from items.items()
def __getitem__(self, key: str) -> typing.Any:
cog = self
source = {
command.name: command
for command in self.bot.all_commands.values()
if getattr(command.cog, "qualified_name", None)
== getattr(cog, "qualified_name", None)
}
_item = source[key]
return self.Command._setup(
bot=self.bot, Cog=self.Cog, Command=self.Command, command=_item
)
def items(self):
cog = self
source = {
command.name: command
for command in self.bot.all_commands.values()
if getattr(command.cog, "qualified_name", None)
== getattr(cog, "qualified_name", None)
}
_items = source
return {
key: self.Command._setup(
bot=self.bot, Cog=self.Cog, Command=self.Command, command=value
)
for key, value in _items.items()
}
def keys(self):
cog = self
source = {
command.name: command
for command in self.bot.all_commands.values()
if getattr(command.cog, "qualified_name", None)
== getattr(cog, "qualified_name", None)
}
return source.keys()
def values(self):
cog = self
source = {
command.name: command
for command in self.bot.all_commands.values()
if getattr(command.cog, "qualified_name", None)
== getattr(cog, "qualified_name", None)
}
_items = source
items = {
key: self.Command._setup(
bot=self.bot, Cog=self.Cog, Command=self.Command, command=value
)
for key, value in _items.items()
}
return items.values()
class Command(commands.Command):
def __init__(func, *args, **kwargs):
super().__init__(func=func, *args, **kwargs)
@classmethod
def _setup(cls, bot: Red, Cog, Command, command) -> typing.Any: # typing_extensions.Self
c = cls(command.callback)
c.__dict__ = command.__dict__
c.bot = bot
c.Cog = Cog
c.Command = Command
c.original_object = command
return c
def __repr__(self) -> str:
if getattr(self, "original_object", None) is not None:
return repr(self.original_object)
return super().__repr__()
def __eq__(self, other) -> bool:
return (
isinstance(other, commands.Command)
and other.qualified_name == self.qualified_name
and other.callback == self.callback
)
def __len__(self) -> int:
command = self
source = {
c.name: c
for c in self.bot.walk_commands()
if getattr(c.parent, "qualified_name", None) == command.qualified_name
}
return len(source)
def __contains__(self, key: str) -> bool:
command = self
source = {
c.name: c
for c in self.bot.walk_commands()
if getattr(c.parent, "qualified_name", None) == command.qualified_name
}
return key in source
def __iter__(self) -> typing.Iterator[typing.Tuple[str, typing.Any]]:
command = self
source = {
c.name: c
for c in self.bot.walk_commands()
if getattr(c.parent, "qualified_name", None) == command.qualified_name
}
_items = source
items = {
key: self.Command._setup(
bot=self.bot, Cog=self.Cog, Command=self.Command, command=value
)
for key, value in _items.items()
}
yield from items.items()
def __getitem__(self, key: str) -> typing.Any:
command = self
source = {
c.name: c
for c in self.bot.walk_commands()
if getattr(c.parent, "qualified_name", None) == command.qualified_name
}
_item = source[key]
return self.Command._setup(
bot=self.bot, Cog=self.Cog, Command=self.Command, command=_item
)
def items(self):
command = self
source = {
c.name: c
for c in self.bot.walk_commands()
if getattr(c.parent, "qualified_name", None) == command.qualified_name
}
_items = source
return {
key: self.Command._setup(
bot=self.bot, Cog=self.Cog, Command=self.Command, command=value
)
for key, value in _items.items()
}
def keys(self):
command = self
source = {
c.name: c
for c in self.bot.walk_commands()
if getattr(c.parent, "qualified_name", None) == command.qualified_name
}
return source.keys()
def values(self):
command = self
source = {
c.name: c
for c in self.bot.walk_commands()
if getattr(c.parent, "qualified_name", None) == command.qualified_name
}
_items = source
items = {
key: self.Command._setup(
bot=self.bot, Cog=self.Cog, Command=self.Command, command=value
)
for key, value in _items.items()
}
return items.values()
class Cogs:
def __init__(self, bot: Red, Cog, Command) -> None:
self.bot: Red = bot
self.Cog = Cog
self.Command = Command
def __eq__(self, other: object) -> bool:
return isinstance(self, self.__class__) and isinstance(other, self.__class__)
def __len__(self) -> int:
source = {cog.qualified_name: cog for cog in self.bot.cogs.values()}
return len(source)
def __contains__(self, key: str) -> bool:
source = {cog.qualified_name: cog for cog in self.bot.cogs.values()}
return key in source
def __iter__(self) -> typing.Iterator[typing.Tuple[str, typing.Any]]:
source = {cog.qualified_name: cog for cog in self.bot.cogs.values()}
_items = source.items()
yield from {
key: self.Cog._setup(bot=self.bot, Cog=self.Cog, Command=self.Command, cog=value)
for key, value in _items
}
def __getitem__(self, key: str) -> typing.Any:
source = {cog.qualified_name: cog for cog in self.bot.cogs.values()}
_item = source[key]
return self.Cog._setup(bot=self.bot, Cog=self.Cog, Command=self.Command, cog=_item)
def items(self):
source = {cog.qualified_name: cog for cog in self.bot.cogs.values()}
_items = source.items()
return {
key: self.Cog._setup(bot=self.bot, Cog=self.Cog, Command=self.Command, cog=value)
for key, value in _items
}
def keys(self):
source = {cog.qualified_name: cog for cog in self.bot.cogs.values()}
return source.keys()
def values(self):
source = {cog.qualified_name: cog for cog in self.bot.cogs.values()}
_items = source.items()
items = {
key: self.Cog._setup(bot=self.bot, Cog=self.Cog, Command=self.Command, cog=value)
for key, value in _items
}
return items.values()
class Commands:
def __init__(self, bot: Red, Cog, Command) -> None:
self.bot: Red = bot
self.Cog = Cog
self.Command = Command
def __eq__(self, other: object) -> bool:
return isinstance(self, self.__class__) and isinstance(other, self.__class__)
def __len__(self) -> int:
source = {command.name: command for command in self.bot.all_commands.values()}
return len(source)
def __contains__(self, key: str) -> bool:
source = {command.name: command for command in self.bot.all_commands.values()}
return key in source
def __iter__(self) -> typing.Iterator[typing.Tuple[str, typing.Any]]:
source = {command.name: command for command in self.bot.all_commands.values()}
_items = source.items()
yield from {
key: self.Command._setup(
bot=self.bot, Cog=self.Cog, Command=self.Command, command=value
)
for key, value in _items.items()
}
def __getitem__(self, key: str) -> typing.Any:
source = {command.name: command for command in self.bot.all_commands.values()}
_item = source[key]
return self.Command._setup(
bot=self.bot, Cog=self.Cog, Command=self.Command, command=_item
)
def items(self):
source = {command.name: command for command in self.bot.all_commands.values()}
_items = source.items()
return {
key: self.Command._setup(
bot=self.bot, Cog=self.Cog, Command=self.Command, command=value
)
for key, value in _items.items()
}
def keys(self):
source = {command.name: command for command in self.bot.all_commands.values()}
return source.keys()
def values(self):
source = {command.name: command for command in self.bot.all_commands.values()}
_items = source.items()
items = {
key: self.Command._setup(
bot=self.bot, Cog=self.Cog, Command=self.Command, command=value
)
for key, value in _items.items()
}
return items.values()