diff --git a/gsuid_core/help/draw_plugin_help.py b/gsuid_core/help/draw_plugin_help.py index e057de0..7787caa 100644 --- a/gsuid_core/help/draw_plugin_help.py +++ b/gsuid_core/help/draw_plugin_help.py @@ -1,18 +1,50 @@ +from pathlib import Path from copy import deepcopy from typing import Dict, List, Tuple, Callable, Optional -from PIL import Image, ImageDraw, ImageFont +from PIL import Image, ImageDraw, ImageFont, ImageFilter from gsuid_core.data_store import get_res_path from gsuid_core.utils.image.convert import convert_img -from gsuid_core.utils.image.image_tools import ( - crop_center_img, - easy_alpha_composite, -) +from gsuid_core.utils.image.image_tools import crop_center_img from .model import PluginHelp cache: Dict[str, int] = {} +MICON_PATH = Path(__file__).parent / 'icon' +DEFAULT_ICON = MICON_PATH / '拼图.png' + + +def cx(w: int, x: int) -> int: + return int((w - x) / 2) + + +def _get_icon(name: str, ICON_PATH: Path) -> Optional[Image.Image]: + path = ICON_PATH / f'{name}.png' + icon = None + if path.exists(): + icon = Image.open(path) + else: + for i in ICON_PATH.glob('*.png'): + if i.stem in name: + icon = Image.open(i) + break + + return icon + + +def get_icon(name: str, ICON_PATH: Optional[Path]) -> Image.Image: + if ICON_PATH is not None: + icon = _get_icon(name, ICON_PATH) + if icon is None: + icon = _get_icon(name, MICON_PATH) + else: + icon = _get_icon(name, MICON_PATH) + + if icon is None: + icon = Image.open(DEFAULT_ICON) + + return icon.resize((36, 36)) async def get_help( @@ -28,6 +60,12 @@ async def get_help( is_dark: bool = True, text_color: Tuple[int, int, int] = (250, 250, 250), sub_color: Optional[Tuple[int, int, int]] = None, + op_color: Optional[Tuple[int, int, int]] = None, + column: int = 5, + is_gaussian: bool = False, + gaussian_blur: int = 20, + is_icon: bool = True, + ICON_PATH: Optional[Path] = None, ) -> bytes: help_path = get_res_path('help') / f'{name}.jpg' @@ -39,73 +77,112 @@ async def get_help( elif sub_color is None and not is_dark: sub_color = tuple(x + 50 for x in text_color if x < 205) - title = Image.new('RGBA', (900, 600)) + if op_color is None and is_dark: + op_color = tuple(x - 90 for x in text_color if x > 90) + elif op_color is None and not is_dark: + op_color = tuple(x + 90 for x in text_color if x < 160) + + w, h = 50 + 260 * column, 630 + button_x = 260 + button_y = 103 # 80 + + title = Image.new('RGBA', (w, 600)) icon = icon.resize((300, 300)) - title.paste(icon, (300, 89), icon) - title.paste(badge, (0, 390), badge) + + title.paste(icon, (cx(w, 300), 89), icon) + title.paste(badge, (cx(w, 900), 390), badge) badge_s = badge.resize((720, 80)) - title.paste(badge_s, (90, 480), badge_s) + title.paste(badge_s, (cx(w, 720), 480), badge_s) title_draw = ImageDraw.Draw(title) - title_draw.text((450, 440), f'{name} 帮助', text_color, font(36), 'mm') - title_draw.text((450, 520), sub_text, sub_color, font(26), 'mm') + title_draw.text((cx(w, 0), 440), f'{name} 帮助', text_color, font(36), 'mm') + title_draw.text((cx(w, 0), 520), sub_text, sub_color, font(26), 'mm') - w, h = 900, 630 + if is_dark: + icon_mask = Image.new('RGBA', (36, 36), (255, 255, 255)) + else: + icon_mask = Image.new('RGBA', (36, 36), (10, 10, 10)) sv_img_list: List[Image.Image] = [] for sv_name in help_data: tr_size = len(help_data[sv_name]['data']) - y = 100 + ((tr_size + 3) // 4) * 80 + y = 100 + ((tr_size + column - 1) // column) * button_y h += y - sv_img = Image.new('RGBA', (900, y)) + + # 生成单个服务的背景, 依据默认column + sv_img = Image.new('RGBA', (w, y)) sv_data = help_data[sv_name]['data'] sv_desc = help_data[sv_name]['desc'] bc = deepcopy(banner) bc_draw = ImageDraw.Draw(bc) bc_draw.text((30, 25), sv_name, text_color, font(35), 'lm') + if hasattr(font, 'getsize'): - size, _ = font(35).getsize(sv_name) + size, _ = font(35).getsize(sv_name) # type: ignore else: bbox = font(35).getbbox(sv_name) size, _ = bbox[2] - bbox[0], bbox[3] - bbox[1] - bc_draw.text((42 + size, 30), sv_desc, sub_color, font(20), 'lm') - sv_img = easy_alpha_composite(sv_img, bc, (0, 10)) - # sv_img.paste(bc, (0, 10), bc) + bc_draw.text((42 + size, 30), sv_desc, sub_color, font(20), 'lm') + sv_img.paste(bc, (0, 10), bc) + # sv_img = easy_alpha_composite(sv_img, bc, (0, 10)) + + # 开始绘制各个按钮 for index, tr in enumerate(sv_data): bt = deepcopy(button) bt_draw = ImageDraw.Draw(bt) - if len(tr['name']) > 8: + + # 限制长度 + if is_icon and len(tr['name']) > 7: tr_name = tr['name'][:5] + '..' + elif len(tr['name']) > 10: + tr_name = tr['name'][:8] + '..' else: tr_name = tr['name'] - bt_draw.text((105, 28), tr_name, text_color, font(26), 'mm') - bt_draw.text((105, 51), tr['eg'], sub_color, font(17), 'mm') - offset_x = 210 * (index % 4) - offset_y = 80 * (index // 4) - sv_img = easy_alpha_composite( - sv_img, bt, (26 + offset_x, 83 + offset_y) - ) - # sv_img.paste(bt, (26 + offset_x, 83 + offset_y), bt) + if is_icon: + f = 38 + icon = get_icon(tr['name'], ICON_PATH) + bt.paste(icon_mask, (13, 17), icon) + else: + f = 0 + + # 标题 + bt_draw.text((20 + f, 28), tr_name, text_color, font(26), 'lm') + # 使用范例 + bt_draw.text((20 + f, 50), tr['eg'], sub_color, font(17), 'lm') + # 简单介绍 + bt_draw.text((20, 78), tr['desc'], op_color, font(16), 'lm') + + offset_x = button_x * (index % column) + offset_y = button_y * (index // column) + sv_img.paste(bt, (25 + offset_x, 83 + offset_y), bt) sv_img_list.append(sv_img) img = crop_center_img(bg, w, h) + if is_gaussian: + img = img.filter(ImageFilter.GaussianBlur(gaussian_blur)) + img.paste(title, (0, 0), title) temp = 0 for _sm in sv_img_list: img.paste(_sm, (0, 600 + temp), _sm) temp += _sm.size[1] + img = img.convert('RGBA') + all_white = Image.new('RGBA', img.size, (255, 255, 255)) + img = Image.alpha_composite(all_white, img) + img = img.convert('RGB') help_path = get_res_path('help') / f'{name}.jpg' img.save( help_path, 'JPEG', - quality=85, + quality=89, subsampling=0, ) cache[name] = 1 + return await convert_img(img) diff --git a/gsuid_core/help/icon/介绍.png b/gsuid_core/help/icon/介绍.png new file mode 100644 index 0000000..4130185 Binary files /dev/null and b/gsuid_core/help/icon/介绍.png differ diff --git a/gsuid_core/help/icon/任务.png b/gsuid_core/help/icon/任务.png new file mode 100644 index 0000000..3fdd447 Binary files /dev/null and b/gsuid_core/help/icon/任务.png differ diff --git a/gsuid_core/help/icon/信息.png b/gsuid_core/help/icon/信息.png new file mode 100644 index 0000000..5cfeba4 Binary files /dev/null and b/gsuid_core/help/icon/信息.png differ diff --git a/gsuid_core/help/icon/公告.png b/gsuid_core/help/icon/公告.png new file mode 100644 index 0000000..945dd0d Binary files /dev/null and b/gsuid_core/help/icon/公告.png differ diff --git a/gsuid_core/help/icon/刀剑.png b/gsuid_core/help/icon/刀剑.png new file mode 100644 index 0000000..3df88a9 Binary files /dev/null and b/gsuid_core/help/icon/刀剑.png differ diff --git a/gsuid_core/help/icon/切换.png b/gsuid_core/help/icon/切换.png new file mode 100644 index 0000000..bbfeffc Binary files /dev/null and b/gsuid_core/help/icon/切换.png differ diff --git a/gsuid_core/help/icon/删除.png b/gsuid_core/help/icon/删除.png new file mode 100644 index 0000000..13df047 Binary files /dev/null and b/gsuid_core/help/icon/删除.png differ diff --git a/gsuid_core/help/icon/刷新.png b/gsuid_core/help/icon/刷新.png new file mode 100644 index 0000000..fc2cd1e Binary files /dev/null and b/gsuid_core/help/icon/刷新.png differ diff --git a/gsuid_core/help/icon/卡组.png b/gsuid_core/help/icon/卡组.png new file mode 100644 index 0000000..80a42f8 Binary files /dev/null and b/gsuid_core/help/icon/卡组.png differ diff --git a/gsuid_core/help/icon/哪里.png b/gsuid_core/help/icon/哪里.png new file mode 100644 index 0000000..0adb2ec Binary files /dev/null and b/gsuid_core/help/icon/哪里.png differ diff --git a/gsuid_core/help/icon/地图.png b/gsuid_core/help/icon/地图.png new file mode 100644 index 0000000..0adb2ec Binary files /dev/null and b/gsuid_core/help/icon/地图.png differ diff --git a/gsuid_core/help/icon/导入.png b/gsuid_core/help/icon/导入.png new file mode 100644 index 0000000..3f85543 Binary files /dev/null and b/gsuid_core/help/icon/导入.png differ diff --git a/gsuid_core/help/icon/导出.png b/gsuid_core/help/icon/导出.png new file mode 100644 index 0000000..a8621dd Binary files /dev/null and b/gsuid_core/help/icon/导出.png differ diff --git a/gsuid_core/help/icon/影.png b/gsuid_core/help/icon/影.png new file mode 100644 index 0000000..74b995c Binary files /dev/null and b/gsuid_core/help/icon/影.png differ diff --git a/gsuid_core/help/icon/拼图.png b/gsuid_core/help/icon/拼图.png new file mode 100644 index 0000000..a76a9d9 Binary files /dev/null and b/gsuid_core/help/icon/拼图.png differ diff --git a/gsuid_core/help/icon/探索.png b/gsuid_core/help/icon/探索.png new file mode 100644 index 0000000..6da2b44 Binary files /dev/null and b/gsuid_core/help/icon/探索.png differ diff --git a/gsuid_core/help/icon/推送.png b/gsuid_core/help/icon/推送.png new file mode 100644 index 0000000..8161773 Binary files /dev/null and b/gsuid_core/help/icon/推送.png differ diff --git a/gsuid_core/help/icon/收集.png b/gsuid_core/help/icon/收集.png new file mode 100644 index 0000000..5d3d5ae Binary files /dev/null and b/gsuid_core/help/icon/收集.png differ diff --git a/gsuid_core/help/icon/攻略.png b/gsuid_core/help/icon/攻略.png new file mode 100644 index 0000000..21202a1 Binary files /dev/null and b/gsuid_core/help/icon/攻略.png differ diff --git a/gsuid_core/help/icon/更新.png b/gsuid_core/help/icon/更新.png new file mode 100644 index 0000000..0796868 Binary files /dev/null and b/gsuid_core/help/icon/更新.png differ diff --git a/gsuid_core/help/icon/材料.png b/gsuid_core/help/icon/材料.png new file mode 100644 index 0000000..64df7fc Binary files /dev/null and b/gsuid_core/help/icon/材料.png differ diff --git a/gsuid_core/help/icon/查询.png b/gsuid_core/help/icon/查询.png new file mode 100644 index 0000000..041c6d2 Binary files /dev/null and b/gsuid_core/help/icon/查询.png differ diff --git a/gsuid_core/help/icon/校验.png b/gsuid_core/help/icon/校验.png new file mode 100644 index 0000000..2bb0fbf Binary files /dev/null and b/gsuid_core/help/icon/校验.png differ diff --git a/gsuid_core/help/icon/每月.png b/gsuid_core/help/icon/每月.png new file mode 100644 index 0000000..83c0a4f Binary files /dev/null and b/gsuid_core/help/icon/每月.png differ diff --git a/gsuid_core/help/icon/深渊.png b/gsuid_core/help/icon/深渊.png new file mode 100644 index 0000000..b18b175 Binary files /dev/null and b/gsuid_core/help/icon/深渊.png differ diff --git a/gsuid_core/help/icon/添加.png b/gsuid_core/help/icon/添加.png new file mode 100644 index 0000000..4427c69 Binary files /dev/null and b/gsuid_core/help/icon/添加.png differ diff --git a/gsuid_core/help/icon/清除.png b/gsuid_core/help/icon/清除.png new file mode 100644 index 0000000..8b0c002 Binary files /dev/null and b/gsuid_core/help/icon/清除.png differ diff --git a/gsuid_core/help/icon/状态.png b/gsuid_core/help/icon/状态.png new file mode 100644 index 0000000..fd32041 Binary files /dev/null and b/gsuid_core/help/icon/状态.png differ diff --git a/gsuid_core/help/icon/签到.png b/gsuid_core/help/icon/签到.png new file mode 100644 index 0000000..26683a5 Binary files /dev/null and b/gsuid_core/help/icon/签到.png differ diff --git a/gsuid_core/help/icon/绑定.png b/gsuid_core/help/icon/绑定.png new file mode 100644 index 0000000..d1b509a Binary files /dev/null and b/gsuid_core/help/icon/绑定.png differ diff --git a/gsuid_core/help/icon/表.png b/gsuid_core/help/icon/表.png new file mode 100644 index 0000000..065993a Binary files /dev/null and b/gsuid_core/help/icon/表.png differ diff --git a/gsuid_core/help/icon/表情.png b/gsuid_core/help/icon/表情.png new file mode 100644 index 0000000..4626b9e Binary files /dev/null and b/gsuid_core/help/icon/表情.png differ diff --git a/gsuid_core/help/icon/角色.png b/gsuid_core/help/icon/角色.png new file mode 100644 index 0000000..9488f4b Binary files /dev/null and b/gsuid_core/help/icon/角色.png differ diff --git a/gsuid_core/help/icon/记录.png b/gsuid_core/help/icon/记录.png new file mode 100644 index 0000000..308dc7c Binary files /dev/null and b/gsuid_core/help/icon/记录.png differ diff --git a/gsuid_core/help/icon/配置.png b/gsuid_core/help/icon/配置.png new file mode 100644 index 0000000..21925cc Binary files /dev/null and b/gsuid_core/help/icon/配置.png differ diff --git a/gsuid_core/help/icon/重启.png b/gsuid_core/help/icon/重启.png new file mode 100644 index 0000000..6f7bbf9 Binary files /dev/null and b/gsuid_core/help/icon/重启.png differ diff --git a/gsuid_core/utils/image/convert.py b/gsuid_core/utils/image/convert.py index bcff977..4c9f9ab 100644 --- a/gsuid_core/utils/image/convert.py +++ b/gsuid_core/utils/image/convert.py @@ -100,7 +100,7 @@ def get_str_size( line += i if hasattr(font, 'getsize'): - size, _ = font.getsize(line) + size, _ = font.getsize(line) # type: ignore else: bbox = font.getbbox(line) size, _ = bbox[2] - bbox[0], bbox[3] - bbox[1] diff --git a/gsuid_core/utils/image/image_tools.py b/gsuid_core/utils/image/image_tools.py index 90f1495..6330bba 100644 --- a/gsuid_core/utils/image/image_tools.py +++ b/gsuid_core/utils/image/image_tools.py @@ -44,7 +44,7 @@ def draw_center_text_by_line( x, y = pos if hasattr(font, 'getsize'): - _, h = font.getsize('X') + _, h = font.getsize('X') # type: ignore else: bbox = font.getbbox('X') _, h = 0, bbox[3] - bbox[1] @@ -54,7 +54,8 @@ def draw_center_text_by_line( anchor = 'la' if not_center else 'mm' for char in text: if hasattr(font, 'getsize'): - size, _ = font.getsize(char) # 获取当前字符的宽度 + # 获取当前字符的宽度 + size, _ = font.getsize(char) # type: ignore else: bbox = font.getbbox(char) size, _ = bbox[2] - bbox[0], bbox[3] - bbox[1] @@ -89,7 +90,7 @@ def draw_text_by_line( x, y = pos if hasattr(font, 'getsize'): - _, h = font.getsize('X') + _, h = font.getsize('X') # type: ignore else: bbox = font.getbbox('X') _, h = 0, bbox[3] - bbox[1] @@ -102,8 +103,9 @@ def draw_text_by_line( row = "" # 存储本行文字 length = 0 # 记录本行长度 for character in text: + # 获取当前字符的宽度 if hasattr(font, 'getsize'): - w, h = font.getsize(character) # 获取当前字符的宽度 + w, h = font.getsize(character) # type: ignore else: bbox = font.getbbox('X') w, h = bbox[2] - bbox[0], bbox[3] - bbox[1] @@ -115,7 +117,7 @@ def draw_text_by_line( row += character if center: if hasattr(font, 'getsize'): - font_size = font.getsize(row) + font_size = font.getsize(row) # type: ignore else: bbox = font.getbbox(character) font_size = bbox[2] - bbox[0], bbox[3] - bbox[1] @@ -127,7 +129,7 @@ def draw_text_by_line( if row != "": if center: if hasattr(font, 'getsize'): - font_size = font.getsize(row) + font_size = font.getsize(row) # type: ignore else: bbox = font.getbbox(row) font_size = bbox[2] - bbox[0], bbox[3] - bbox[1] diff --git a/poetry.lock b/poetry.lock index aed9e55..05c0d50 100644 --- a/poetry.lock +++ b/poetry.lock @@ -196,13 +196,13 @@ reference = "mirrors" [[package]] name = "apscheduler" -version = "3.10.3" +version = "3.10.4" description = "In-process task scheduler with Cron-like capabilities" optional = false python-versions = ">=3.6" files = [ - {file = "APScheduler-3.10.3-py3-none-any.whl", hash = "sha256:1611d207b095ff52d97884e90736c192bdd94dbd44ce27eb92c3f1da24a400d3"}, - {file = "APScheduler-3.10.3.tar.gz", hash = "sha256:3f17fd3915f14f4bfa597f552130a14a9d1cc74a002fa1d95dd671cb48dba70e"}, + {file = "APScheduler-3.10.4-py3-none-any.whl", hash = "sha256:fb91e8a768632a4756a585f79ec834e0e27aad5860bac7eaa523d9ccefd87661"}, + {file = "APScheduler-3.10.4.tar.gz", hash = "sha256:e6df071b27d9be898e486bc7940a7be50b4af2e9da7c08f0744a96d4bd4cef4a"}, ] [package.dependencies] @@ -605,13 +605,13 @@ reference = "mirrors" [[package]] name = "click" -version = "8.1.6" +version = "8.1.7" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.6-py3-none-any.whl", hash = "sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5"}, - {file = "click-8.1.6.tar.gz", hash = "sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd"}, + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, ] [package.dependencies] @@ -1996,17 +1996,17 @@ reference = "mirrors" [[package]] name = "setuptools" -version = "68.1.0" +version = "68.1.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-68.1.0-py3-none-any.whl", hash = "sha256:e13e1b0bc760e9b0127eda042845999b2f913e12437046e663b833aa96d89715"}, - {file = "setuptools-68.1.0.tar.gz", hash = "sha256:d59c97e7b774979a5ccb96388efc9eb65518004537e85d52e81eaee89ab6dd91"}, + {file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"}, + {file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] @@ -2708,4 +2708,4 @@ reference = "mirrors" [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "cf1907f9dba50e810dcf9bc81a81c79309a080aac345358c68a34b1dbd82d44e" +content-hash = "a57a5ae92fffd7da50ee98c76df4945223b2bf5636f1f6a84b2e38f0de05975f" diff --git a/pyproject.toml b/pyproject.toml index cb738d3..0245a52 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,8 +24,8 @@ aiosqlite = ">=0.17.0" aiofiles = ">=0.8.0" sqlmodel = ">=0.0.8" gitpython = ">=3.1.27" -fastapi-amis-admin = ">=0.5.0" -fastapi-user-auth = ">=0.5.0" +fastapi-amis-admin = "^0.5.8" +fastapi-user-auth = "^0.5.0" qrcode = {extras = ["pil"], version = "^7.3.1"} msgspec = ">= 0.13.1" uvicorn = ">=0.20.0" diff --git a/requirements.txt b/requirements.txt index d48f8aa..01b1b96 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ aiohttp==3.8.5 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0 aiosignal==1.3.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" aiosqlite==0.19.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" anyio==3.7.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -apscheduler==3.10.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +apscheduler==3.10.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" async-timeout==4.0.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" attrs==23.1.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" backports-zoneinfo==0.2.1 ; python_full_version >= "3.8.1" and python_version < "3.9" @@ -14,7 +14,7 @@ beautifulsoup4==4.12.2 ; python_full_version >= "3.8.1" and python_full_version certifi==2023.7.22 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" cffi==1.15.1 ; os_name == "nt" and implementation_name != "pypy" and python_full_version >= "3.8.1" and python_full_version < "4.0.0" charset-normalizer==3.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -click==8.1.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +click==8.1.7 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" colorama==0.4.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and (platform_system == "Windows" or sys_platform == "win32") dnspython==2.4.2 ; python_full_version >= "3.8.1" and python_version < "4.0" email-validator==2.0.0.post2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"