mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-08 12:18:54 -05:00
Reject package (extension) names that can't be valid Python identifiers (#3679)
* Reject package names that can't be valid Python identifiers * Add info to `[p](re)load` * Improve internal consistency of package vs cog
This commit is contained in:
parent
1a3e264b2a
commit
775528ce9b
@ -2,6 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import functools
|
import functools
|
||||||
|
import keyword
|
||||||
import os
|
import os
|
||||||
import pkgutil
|
import pkgutil
|
||||||
import shlex
|
import shlex
|
||||||
@ -495,6 +496,9 @@ class Repo(RepoJSONMixin):
|
|||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
for file_finder, name, is_pkg in pkgutil.iter_modules(path=[str(self.folder_path)]):
|
for file_finder, name, is_pkg in pkgutil.iter_modules(path=[str(self.folder_path)]):
|
||||||
|
if not name.isidentifier() or keyword.iskeyword(name):
|
||||||
|
# reject package names that can't be valid python identifiers
|
||||||
|
continue
|
||||||
if is_pkg:
|
if is_pkg:
|
||||||
curr_modules.append(
|
curr_modules.append(
|
||||||
Installable(location=self.folder_path / name, repo=self, commit=self.commit)
|
Installable(location=self.folder_path / name, repo=self, commit=self.commit)
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import contextlib
|
import contextlib
|
||||||
|
import keyword
|
||||||
import pkgutil
|
import pkgutil
|
||||||
from importlib import import_module, invalidate_caches
|
from importlib import import_module, invalidate_caches
|
||||||
from importlib.machinery import ModuleSpec
|
from importlib.machinery import ModuleSpec
|
||||||
@ -214,6 +215,13 @@ class CogManager:
|
|||||||
When no cog with the requested name was found.
|
When no cog with the requested name was found.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
if not name.isidentifier() or keyword.iskeyword(name):
|
||||||
|
# reject package names that can't be valid python identifiers
|
||||||
|
raise NoSuchCog(
|
||||||
|
f"No 3rd party module by the name of '{name}' was found in any available path.",
|
||||||
|
name=name,
|
||||||
|
)
|
||||||
|
|
||||||
real_paths = list(map(str, [await self.install_path()] + await self.user_defined_paths()))
|
real_paths = list(map(str, [await self.install_path()] + await self.user_defined_paths()))
|
||||||
|
|
||||||
for finder, module_name, _ in pkgutil.iter_modules(real_paths):
|
for finder, module_name, _ in pkgutil.iter_modules(real_paths):
|
||||||
@ -223,9 +231,7 @@ class CogManager:
|
|||||||
return spec
|
return spec
|
||||||
|
|
||||||
raise NoSuchCog(
|
raise NoSuchCog(
|
||||||
"No 3rd party module by the name of '{}' was found in any available path.".format(
|
f"No 3rd party module by the name of '{name}' was found in any available path.",
|
||||||
name
|
|
||||||
),
|
|
||||||
name=name,
|
name=name,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -291,7 +297,9 @@ class CogManager:
|
|||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
for finder, module_name, _ in pkgutil.iter_modules(paths):
|
for finder, module_name, _ in pkgutil.iter_modules(paths):
|
||||||
ret.append(module_name)
|
# reject package names that can't be valid python identifiers
|
||||||
|
if module_name.isidentifier() and not keyword.iskeyword(module_name):
|
||||||
|
ret.append(module_name)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import contextlib
|
|||||||
import datetime
|
import datetime
|
||||||
import importlib
|
import importlib
|
||||||
import itertools
|
import itertools
|
||||||
|
import keyword
|
||||||
import logging
|
import logging
|
||||||
import io
|
import io
|
||||||
import random
|
import random
|
||||||
@ -109,21 +110,34 @@ class CoreLogic:
|
|||||||
self.bot.register_rpc_handler(self._invite_url)
|
self.bot.register_rpc_handler(self._invite_url)
|
||||||
|
|
||||||
async def _load(
|
async def _load(
|
||||||
self, cog_names: Iterable[str]
|
self, pkg_names: Iterable[str]
|
||||||
) -> Tuple[List[str], List[str], List[str], List[str], List[Tuple[str, str]], Set[str]]:
|
) -> Tuple[
|
||||||
|
List[str], List[str], List[str], List[str], List[str], List[Tuple[str, str]], Set[str]
|
||||||
|
]:
|
||||||
"""
|
"""
|
||||||
Loads cogs by name.
|
Loads packages by name.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
cog_names : list of str
|
pkg_names : `list` of `str`
|
||||||
|
List of names of packages to load.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
tuple
|
tuple
|
||||||
4-tuple of loaded, failed, not found and already loaded cogs.
|
7-tuple of:
|
||||||
|
1. List of names of packages that loaded successfully
|
||||||
|
2. List of names of packages that failed to load without specified reason
|
||||||
|
3. List of names of packages that don't have a valid package name
|
||||||
|
4. List of names of packages that weren't found in any cog path
|
||||||
|
5. List of names of packages that are already loaded
|
||||||
|
6. List of 2-tuples (pkg_name, reason) for packages
|
||||||
|
that failed to load with a specified reason
|
||||||
|
7. Set of repo names that use deprecated shared libraries
|
||||||
"""
|
"""
|
||||||
failed_packages = []
|
failed_packages = []
|
||||||
loaded_packages = []
|
loaded_packages = []
|
||||||
|
invalid_pkg_names = []
|
||||||
notfound_packages = []
|
notfound_packages = []
|
||||||
alreadyloaded_packages = []
|
alreadyloaded_packages = []
|
||||||
failed_with_reason_packages = []
|
failed_with_reason_packages = []
|
||||||
@ -131,24 +145,27 @@ class CoreLogic:
|
|||||||
|
|
||||||
bot = self.bot
|
bot = self.bot
|
||||||
|
|
||||||
cogspecs = []
|
pkg_specs = []
|
||||||
|
|
||||||
for name in cog_names:
|
for name in pkg_names:
|
||||||
|
if not name.isidentifier() or keyword.iskeyword(name):
|
||||||
|
invalid_pkg_names.append(name)
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
spec = await bot._cog_mgr.find_cog(name)
|
spec = await bot._cog_mgr.find_cog(name)
|
||||||
if spec:
|
if spec:
|
||||||
cogspecs.append((spec, name))
|
pkg_specs.append((spec, name))
|
||||||
else:
|
else:
|
||||||
notfound_packages.append(name)
|
notfound_packages.append(name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception("Package import failed", exc_info=e)
|
log.exception("Package import failed", exc_info=e)
|
||||||
|
|
||||||
exception_log = "Exception during import of cog\n"
|
exception_log = "Exception during import of package\n"
|
||||||
exception_log += "".join(traceback.format_exception(type(e), e, e.__traceback__))
|
exception_log += "".join(traceback.format_exception(type(e), e, e.__traceback__))
|
||||||
bot._last_exception = exception_log
|
bot._last_exception = exception_log
|
||||||
failed_packages.append(name)
|
failed_packages.append(name)
|
||||||
|
|
||||||
async for spec, name in AsyncIter(cogspecs, steps=10):
|
async for spec, name in AsyncIter(pkg_specs, steps=10):
|
||||||
try:
|
try:
|
||||||
self._cleanup_and_refresh_modules(spec.name)
|
self._cleanup_and_refresh_modules(spec.name)
|
||||||
await bot.load_extension(spec)
|
await bot.load_extension(spec)
|
||||||
@ -159,7 +176,7 @@ class CoreLogic:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception("Package loading failed", exc_info=e)
|
log.exception("Package loading failed", exc_info=e)
|
||||||
|
|
||||||
exception_log = "Exception during loading of cog\n"
|
exception_log = "Exception during loading of package\n"
|
||||||
exception_log += "".join(traceback.format_exception(type(e), e, e.__traceback__))
|
exception_log += "".join(traceback.format_exception(type(e), e, e.__traceback__))
|
||||||
bot._last_exception = exception_log
|
bot._last_exception = exception_log
|
||||||
failed_packages.append(name)
|
failed_packages.append(name)
|
||||||
@ -184,6 +201,7 @@ class CoreLogic:
|
|||||||
return (
|
return (
|
||||||
loaded_packages,
|
loaded_packages,
|
||||||
failed_packages,
|
failed_packages,
|
||||||
|
invalid_pkg_names,
|
||||||
notfound_packages,
|
notfound_packages,
|
||||||
alreadyloaded_packages,
|
alreadyloaded_packages,
|
||||||
failed_with_reason_packages,
|
failed_with_reason_packages,
|
||||||
@ -212,13 +230,14 @@ class CoreLogic:
|
|||||||
for child_name, lib in children.items():
|
for child_name, lib in children.items():
|
||||||
importlib._bootstrap._exec(lib.__spec__, lib)
|
importlib._bootstrap._exec(lib.__spec__, lib)
|
||||||
|
|
||||||
async def _unload(self, cog_names: Iterable[str]) -> Tuple[List[str], List[str]]:
|
async def _unload(self, pkg_names: Iterable[str]) -> Tuple[List[str], List[str]]:
|
||||||
"""
|
"""
|
||||||
Unloads cogs with the given names.
|
Unloads packages with the given names.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
cog_names : list of str
|
pkg_names : `list` of `str`
|
||||||
|
List of names of packages to unload.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -230,7 +249,7 @@ class CoreLogic:
|
|||||||
|
|
||||||
bot = self.bot
|
bot = self.bot
|
||||||
|
|
||||||
for name in cog_names:
|
for name in pkg_names:
|
||||||
if name in bot.extensions:
|
if name in bot.extensions:
|
||||||
bot.unload_extension(name)
|
bot.unload_extension(name)
|
||||||
await bot.remove_loaded_package(name)
|
await bot.remove_loaded_package(name)
|
||||||
@ -241,22 +260,39 @@ class CoreLogic:
|
|||||||
return unloaded_packages, failed_packages
|
return unloaded_packages, failed_packages
|
||||||
|
|
||||||
async def _reload(
|
async def _reload(
|
||||||
self, cog_names: Sequence[str]
|
self, pkg_names: Sequence[str]
|
||||||
) -> Tuple[List[str], List[str], List[str], List[str], List[Tuple[str, str]], Set[str]]:
|
) -> Tuple[
|
||||||
await self._unload(cog_names)
|
List[str], List[str], List[str], List[str], List[str], List[Tuple[str, str]], Set[str]
|
||||||
|
]:
|
||||||
|
"""
|
||||||
|
Reloads packages with the given names.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
pkg_names : `list` of `str`
|
||||||
|
List of names of packages to reload.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
tuple
|
||||||
|
Tuple as returned by `CoreLogic._load()`
|
||||||
|
"""
|
||||||
|
await self._unload(pkg_names)
|
||||||
|
|
||||||
(
|
(
|
||||||
loaded,
|
loaded,
|
||||||
load_failed,
|
load_failed,
|
||||||
|
invalid_pkg_names,
|
||||||
not_found,
|
not_found,
|
||||||
already_loaded,
|
already_loaded,
|
||||||
load_failed_with_reason,
|
load_failed_with_reason,
|
||||||
repos_with_shared_libs,
|
repos_with_shared_libs,
|
||||||
) = await self._load(cog_names)
|
) = await self._load(pkg_names)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
loaded,
|
loaded,
|
||||||
load_failed,
|
load_failed,
|
||||||
|
invalid_pkg_names,
|
||||||
not_found,
|
not_found,
|
||||||
already_loaded,
|
already_loaded,
|
||||||
load_failed_with_reason,
|
load_failed_with_reason,
|
||||||
@ -1252,6 +1288,7 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
|
|||||||
(
|
(
|
||||||
loaded,
|
loaded,
|
||||||
failed,
|
failed,
|
||||||
|
invalid_pkg_names,
|
||||||
not_found,
|
not_found,
|
||||||
already_loaded,
|
already_loaded,
|
||||||
failed_with_reason,
|
failed_with_reason,
|
||||||
@ -1289,6 +1326,21 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
|
|||||||
).format(packs=humanize_list([inline(package) for package in failed]))
|
).format(packs=humanize_list([inline(package) for package in failed]))
|
||||||
output.append(formed)
|
output.append(formed)
|
||||||
|
|
||||||
|
if invalid_pkg_names:
|
||||||
|
if len(invalid_pkg_names) == 1:
|
||||||
|
formed = _(
|
||||||
|
"The following name is not a valid package name: {pack}\n"
|
||||||
|
"Package names cannot start with a number"
|
||||||
|
" and can only contain ascii numbers, letters, and underscores."
|
||||||
|
).format(pack=inline(invalid_pkg_names[0]))
|
||||||
|
else:
|
||||||
|
formed = _(
|
||||||
|
"The following names are not valid package names: {packs}\n"
|
||||||
|
"Package names cannot start with a number"
|
||||||
|
" and can only contain ascii numbers, letters, and underscores."
|
||||||
|
).format(packs=humanize_list([inline(package) for package in invalid_pkg_names]))
|
||||||
|
output.append(formed)
|
||||||
|
|
||||||
if not_found:
|
if not_found:
|
||||||
if len(not_found) == 1:
|
if len(not_found) == 1:
|
||||||
formed = _("The following package was not found in any cog path: {pack}.").format(
|
formed = _("The following package was not found in any cog path: {pack}.").format(
|
||||||
@ -1381,6 +1433,7 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
|
|||||||
(
|
(
|
||||||
loaded,
|
loaded,
|
||||||
failed,
|
failed,
|
||||||
|
invalid_pkg_names,
|
||||||
not_found,
|
not_found,
|
||||||
already_loaded,
|
already_loaded,
|
||||||
failed_with_reason,
|
failed_with_reason,
|
||||||
@ -1407,6 +1460,21 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
|
|||||||
).format(packs=humanize_list([inline(package) for package in failed]))
|
).format(packs=humanize_list([inline(package) for package in failed]))
|
||||||
output.append(formed)
|
output.append(formed)
|
||||||
|
|
||||||
|
if invalid_pkg_names:
|
||||||
|
if len(invalid_pkg_names) == 1:
|
||||||
|
formed = _(
|
||||||
|
"The following name is not a valid package name: {pack}\n"
|
||||||
|
"Package names cannot start with a number"
|
||||||
|
" and can only contain ascii numbers, letters, and underscores."
|
||||||
|
).format(pack=inline(invalid_pkg_names[0]))
|
||||||
|
else:
|
||||||
|
formed = _(
|
||||||
|
"The following names are not valid package names: {packs}\n"
|
||||||
|
"Package names cannot start with a number"
|
||||||
|
" and can only contain ascii numbers, letters, and underscores."
|
||||||
|
).format(packs=humanize_list([inline(package) for package in invalid_pkg_names]))
|
||||||
|
output.append(formed)
|
||||||
|
|
||||||
if not_found:
|
if not_found:
|
||||||
if len(not_found) == 1:
|
if len(not_found) == 1:
|
||||||
formed = _("The following package was not found in any cog path: {pack}.").format(
|
formed = _("The following package was not found in any cog path: {pack}.").format(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user