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

Indicate when a core cog is overridden in [p]cogs and debuginfo #6208

Draft
wants to merge 1 commit into
base: V3/develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 39 additions & 11 deletions redbot/core/_cog_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import keyword
import pkgutil
from importlib import import_module, invalidate_caches
from importlib.machinery import ModuleSpec
from importlib.machinery import FileFinder, ModuleSpec
from pathlib import Path
from typing import Union, List, Optional
from typing import Union, List, Optional, Tuple

import redbot.cogs
from redbot.core.commands import positive_int
Expand Down Expand Up @@ -288,15 +288,37 @@ async def find_cog(self, name: str) -> Optional[ModuleSpec]:
with contextlib.suppress(NoSuchCog):
return await self._find_core_cog(name)

async def available_modules(self) -> List[str]:
"""Finds the names of all available modules to load."""
paths = list(map(str, await self.paths()))

ret = []
def _iter_cogs(self, paths: List[str]) -> List[Tuple[str, bool]]:
"""Find the names of all available cogs to load from given paths."""
for finder, module_name, _ in pkgutil.iter_modules(paths):
# reject package names that can't be valid python identifiers
if module_name.isidentifier() and not keyword.iskeyword(module_name):
ret.append(module_name)
yield finder, module_name

def available_core_cogs(self) -> List[str]:
"""Find the names of all available core cogs to load."""
return [module_name for _, module_name in self._iter_cogs([self.CORE_PATH])]

async def available_cogs(self) -> List[Tuple[str, bool]]:
"""
Find the names of all available cog packages to load.

Includes info about whether the cog would be loaded from a core path.

Returns
-------
List[Tuple[str, bool]]
A list of (str, bool) pairs where the first item is the cog package name
and the second item is a bool indicating whether the cog would be loaded
from a core path.
"""
paths = list(map(str, await self.paths()))

ret = []
core_path = str(self.CORE_PATH)
for finder, module_name in self._iter_cogs(paths):
is_from_core_path = isinstance(finder, FileFinder) and finder.path == core_path
ret.append((module_name, is_from_core_path))
return ret

@staticmethod
Expand Down Expand Up @@ -456,12 +478,18 @@ async def cogs(self, ctx: commands.Context):
"""
loaded = set(ctx.bot.extensions.keys())

all_cogs = set(await ctx.bot._cog_mgr.available_modules())
core_cogs = set(ctx.bot._cog_mgr.available_core_cogs())
all_cogs = set()
overridden_core_cogs = set()
for cog_name, is_from_core_path in await ctx.bot._cog_mgr.available_cogs():
all_cogs.add(cog_name)
if not is_from_core_path and cog_name in core_cogs:
overridden_core_cogs.add(cog_name)

unloaded = all_cogs - loaded

loaded = sorted(list(loaded), key=str.lower)
unloaded = sorted(list(unloaded), key=str.lower)
loaded = sorted(loaded, key=str.lower)
unloaded = sorted(unloaded, key=str.lower)

if await ctx.embed_requested():
loaded = _("**{} loaded:**\n").format(len(loaded)) + ", ".join(loaded)
Expand Down
6 changes: 6 additions & 0 deletions redbot/core/_debuginfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,12 @@ async def _get_red_vars_section(self) -> DebugInfoSection:
# and calling repr() on prefix strings ensures that the list isn't ambiguous.
prefixes = ", ".join(map(repr, await self.bot._config.prefix()))
parts.append(f"Global prefix(es): {prefixes}")
core_cogs = set(self.bot._cog_mgr.available_core_cogs())
overridden_core_cogs = set()
for cog_name, is_from_core_path in await self.bot._cog_mgr.available_cogs():
if not is_from_core_path and cog_name in core_cogs:
overridden_core_cogs.add(cog_name)
parts.append(f"Overridden core cogs: {', '.join(overridden_core_cogs) or 'None'}")

if self.is_logged_in:
owners = []
Expand Down