mirror of
https://github.com/Paillat-dev/dismoji.git
synced 2026-01-01 16:46:20 +00:00
First commit
This commit is contained in:
17
.copywrite.hcl
Normal file
17
.copywrite.hcl
Normal file
@@ -0,0 +1,17 @@
|
||||
schema_version = 1
|
||||
|
||||
project {
|
||||
license = "MIT"
|
||||
copyright_year = 2025
|
||||
copyright_holder = "Paillat-dev"
|
||||
header_ignore = [
|
||||
".venv/**",
|
||||
"logs/**",
|
||||
".idea/**",
|
||||
".git/**",
|
||||
".vscode/**",
|
||||
"__pycache__/**",
|
||||
"*.pyc",
|
||||
"src/dismoji/raw/**",
|
||||
]
|
||||
}
|
||||
25
.github/workflows/CI.yaml
vendored
Normal file
25
.github/workflows/CI.yaml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master", "dev" ]
|
||||
# Publish semver tags as releases.
|
||||
tags: [ 'v*.*.*' ]
|
||||
pull_request:
|
||||
branches: ["master", "dev"]
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
quality:
|
||||
uses: ./.github/workflows/quality.yaml
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
publish:
|
||||
needs: quality
|
||||
if: github.event_name == 'release'
|
||||
uses: ./.github/workflows/publish.yaml
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
31
.github/workflows/publish.yaml
vendored
Normal file
31
.github/workflows/publish.yaml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: Quality Checks
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Publish to PyPI
|
||||
runs-on: ubuntu-latest
|
||||
environment: pypi
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: "Install uv"
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
enable-cache: true
|
||||
|
||||
- name: "Set up Python"
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version-file: "pyproject.toml"
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync
|
||||
|
||||
- name: Build
|
||||
run: uv build
|
||||
|
||||
- name: Publish
|
||||
run: uv publish
|
||||
87
.github/workflows/quality.yaml
vendored
Normal file
87
.github/workflows/quality.yaml
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
name: Quality Checks
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
check-license-header:
|
||||
name: License Header Check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Copywrite
|
||||
uses: hashicorp/setup-copywrite@5e3e8a26d7b9f8a508848ad0a069dfd2f7aa5339
|
||||
- name: Check Header Compliance
|
||||
run: copywrite headers --plan --config .copywrite.hcl
|
||||
|
||||
tests:
|
||||
name: Tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: [3.9, 3.10, 3.11, 3.12, 3.13]
|
||||
include:
|
||||
- python-version: 3.9
|
||||
name: "Python 3.9"
|
||||
- python-version: 3.10
|
||||
name: "Python 3.10"
|
||||
- python-version: 3.11
|
||||
name: "Python 3.11"
|
||||
- python-version: 3.12
|
||||
name: "Python 3.12"
|
||||
- python-version: 3.13
|
||||
name: "Python 3.13"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: "Set up Python"
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync --no-managed-python --no-python-downloads
|
||||
|
||||
- name: Run tests
|
||||
run: uv run pytest ./tests
|
||||
|
||||
quality:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
check: [format, lint, basedpyright]
|
||||
include:
|
||||
- check: format
|
||||
name: "Format Check"
|
||||
command: "uv run ruff format --check ."
|
||||
- check: lint
|
||||
name: "Lint Check"
|
||||
command: "uv run ruff check ."
|
||||
- check: basedpyright
|
||||
name: "Type Check"
|
||||
command: "uv run basedpyright ."
|
||||
|
||||
name: ${{ matrix.name }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: "Install uv"
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
enable-cache: true
|
||||
|
||||
- name: "Set up Python"
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version-file: "pyproject.toml"
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync
|
||||
|
||||
- name: ${{ matrix.name }}
|
||||
run: ${{ matrix.command }}
|
||||
175
.gitignore
vendored
Normal file
175
.gitignore
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
./build/ # so hatch includes discord-emojis' build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
#uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||
.pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
.idea/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
_version.py
|
||||
|
||||
node_modules/
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "src/dismoji/raw"]
|
||||
path = src/dismoji/raw
|
||||
url = git@github.com:Paillat-dev/discord-emojis.git
|
||||
34
.pre-commit-config.yaml
Normal file
34
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
# Copyright (c) NiceBots
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
ci:
|
||||
autoupdate_commit_msg: ":construction_worker: pre-commit autoupdate"
|
||||
autofix_commit_msg: ":art: auto fixes from pre-commit.com hooks"
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
exclude: \.(po|pot|yml|yaml)$
|
||||
- id: end-of-file-fixer
|
||||
exclude: \.(po|pot|yml|yaml)$
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: v4.0.0-alpha.8
|
||||
hooks:
|
||||
- id: prettier
|
||||
args: [--prose-wrap=always, --print-width=88]
|
||||
exclude: \.(po|pot|yml|yaml)$
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.9.10
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
args: [ --fix ]
|
||||
# Run the formatter.
|
||||
- id: ruff-format
|
||||
- repo: https://github.com/bhundven/copywrite # waiting for https://github.com/hashicorp/copywrite/pull/120 to be merged
|
||||
rev: 937f17f09c46992447dfa8977bb96eda512588c4
|
||||
hooks:
|
||||
- id: add-headers
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Paillat-dev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
343
README.md
Normal file
343
README.md
Normal file
@@ -0,0 +1,343 @@
|
||||
<div align="center">
|
||||
<h1>Discord Progress Bar</h1>
|
||||
|
||||
<!-- badges -->
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
[](https://results.pre-commit.ci/latest/github/Paillat-dev/dismoji/main)
|
||||
|
||||
<!-- end badges -->
|
||||
|
||||
A Python library for creating customizable progress bars with Discord emojis in your
|
||||
Discord bot messages.
|
||||
|
||||
</div>
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Installation](#installation)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Core Concepts](#core-concepts)
|
||||
- [How It Works](#how-it-works)
|
||||
- [Key Components](#key-components)
|
||||
- [Features](#features)
|
||||
- [Type Safety](#type-safety)
|
||||
- [Usage Examples](#usage-examples)
|
||||
- [Basic Progress Bar](#basic-progress-bar)
|
||||
- [Different Progress Bar States](#different-progress-bar-states)
|
||||
- [Custom Progress Bar Length](#custom-progress-bar-length)
|
||||
- [Configuration](#configuration)
|
||||
- [Bot Configuration](#bot-configuration)
|
||||
- [Progress Bar Manager Initialization](#progress-bar-manager-initialization)
|
||||
- [Custom Progress Bar Styles](#custom-progress-bar-styles)
|
||||
- [Limitations](#limitations)
|
||||
- [Getting Help](#getting-help)
|
||||
- [Development](#development)
|
||||
- [Local Testing](#local-testing)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
|
||||
## Overview
|
||||
|
||||
Discord Progress Bar is a Python library that allows you to create visually appealing
|
||||
progress bars in your Discord bot messages using custom emojis. It provides a simple API
|
||||
to generate progress bars of different styles and lengths, making it easy to display
|
||||
progress, loading states, or completion percentages in your Discord applications.
|
||||
|
||||
Built on:
|
||||
|
||||
- [py-cord](https://github.com/Pycord-Development/pycord) - A modern, easy-to-use,
|
||||
feature-rich, and async-ready API wrapper for Discord
|
||||
- Custom Discord emojis - Used to create visually consistent progress bar segments
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install discord-progress-bar --pre
|
||||
```
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
> [!NOTE]
|
||||
> The package is currently in pre-release.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<!-- quick-start -->
|
||||
<!-- prettier-ignore -->
|
||||
> [!TIP]
|
||||
> Create beautiful progress bars in your Discord bot with just a few lines of code!
|
||||
|
||||
```python
|
||||
import discord
|
||||
from discord_progress_bar import ProgressBarManager
|
||||
|
||||
# Create a Discord bot with emoji caching enabled
|
||||
bot = discord.Bot(cache_app_emojis=True)
|
||||
|
||||
progress_bar_manager = None
|
||||
progress_bar = None
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
"""Initialize the ProgressBarManager when the bot is ready."""
|
||||
global progress_bar_manager, progress_bar
|
||||
|
||||
# Initialize the progress bar manager
|
||||
progress_bar_manager = await ProgressBarManager(bot)
|
||||
# Get a progress bar with the "green" style
|
||||
progress_bar = await progress_bar_manager.progress_bar("green")
|
||||
|
||||
@bot.slash_command()
|
||||
async def show_progress(ctx, percent: float = 0.5):
|
||||
"""Display a progress bar with the specified percentage."""
|
||||
|
||||
await ctx.respond(f"Progress: {progress_bar.partial(percent)}")
|
||||
|
||||
# Run your bot
|
||||
bot.run("YOUR_TOKEN")
|
||||
```
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
> [!NOTE]
|
||||
> For a complete example, check the [examples directory](/examples).
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### How It Works
|
||||
|
||||
Discord Progress Bar works by using custom Discord emojis to create visually appealing
|
||||
progress bars in your bot messages. Here's how it works:
|
||||
|
||||
1. **Progress Bar Structure**: Each progress bar consists of multiple emoji segments:
|
||||
|
||||
- Left edge (filled or empty)
|
||||
- Middle sections (filled or empty)
|
||||
- Right edge (filled or empty)
|
||||
|
||||
2. **Emoji Management**: The `ProgressBarManager` class handles:
|
||||
|
||||
- Loading existing emojis from your bot
|
||||
- Creating new emojis from URLs or files if needed
|
||||
- Providing the appropriate emojis to the `ProgressBar` class
|
||||
|
||||
3. **Progress Bar Rendering**: The `ProgressBar` class handles:
|
||||
|
||||
- Rendering full progress bars (100%)
|
||||
- Rendering empty progress bars (0%)
|
||||
- Rendering partial progress bars (any percentage)
|
||||
|
||||
4. **Default Styles**: The library comes with a default "green" style, but you can
|
||||
create custom styles by providing your own emoji images.
|
||||
|
||||
### Key Components
|
||||
|
||||
- **ProgressBarManager**: Initializes with your Discord bot and manages emoji resources
|
||||
- **ProgressBar**: Renders progress bars with different percentages
|
||||
- **ProgressBarPart**: Enum defining the different parts of a progress bar (LEFT_EMPTY,
|
||||
LEFT_FILLED, etc.)
|
||||
- **Default Bars**: Pre-configured progress bar styles that can be used out of the box
|
||||
|
||||
## Features
|
||||
|
||||
- **Easy Integration**: Seamlessly integrates with Discord bots built using py-cord
|
||||
- **Customizable Progress Bars**: Create progress bars with different styles and lengths
|
||||
- **Default Styles**: Comes with a pre-configured "green" style ready to use
|
||||
- **Custom Styles**: Create your own progress bar styles using custom emoji images
|
||||
- **Flexible Rendering**: Render progress bars at any percentage (0-100%)
|
||||
- **Async Support**: Fully supports asynchronous operations for Discord bots
|
||||
- **Emoji Management**: Automatically handles emoji creation and management
|
||||
|
||||
### Type Safety
|
||||
|
||||
Discord Progress Bar is fully type-annotated and type-safe. It uses `basedpyright` for
|
||||
type checking.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
> [!NOTE]
|
||||
> While Discord Progress Bar itself is fully typed, the underlying py-cord library has limited type annotations, which may affect type checking in some areas.
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Basic Progress Bar
|
||||
|
||||
```python
|
||||
@discord.slash_command()
|
||||
async def show_progress(self, ctx: discord.ApplicationContext, percent: float = 0.5) -> None:
|
||||
"""Display a progress bar with the specified percentage."""
|
||||
# Get a progress bar with the default "green" style
|
||||
progress_bar = await self.progress_bar_manager.progress_bar("green", length=10)
|
||||
# Render the progress bar at the specified percentage
|
||||
await ctx.respond(f"Progress: {progress_bar.partial(percent)}")
|
||||
```
|
||||
|
||||
### Different Progress Bar States
|
||||
|
||||
```python
|
||||
@discord.slash_command()
|
||||
async def show_progress_states(self, ctx: discord.ApplicationContext) -> None:
|
||||
"""Display different progress bar states."""
|
||||
progress_bar = await self.progress_bar_manager.progress_bar("green", length=10)
|
||||
|
||||
# Empty progress bar (0%)
|
||||
empty = progress_bar.empty()
|
||||
|
||||
# Partial progress bar (50%)
|
||||
half = progress_bar.partial(0.5)
|
||||
|
||||
# Full progress bar (100%)
|
||||
full = progress_bar.full()
|
||||
|
||||
await ctx.respond(f"Empty: {empty}\nHalf: {half}\nFull: {full}")
|
||||
```
|
||||
|
||||
### Custom Progress Bar Length
|
||||
|
||||
```python
|
||||
@discord.slash_command()
|
||||
async def show_different_lengths(self, ctx: discord.ApplicationContext) -> None:
|
||||
"""Display progress bars with different lengths."""
|
||||
# Short progress bar (5 segments)
|
||||
short_bar = await self.progress_bar_manager.progress_bar("green", length=5)
|
||||
|
||||
# Medium progress bar (10 segments)
|
||||
medium_bar = await self.progress_bar_manager.progress_bar("green", length=10)
|
||||
|
||||
# Long progress bar (20 segments)
|
||||
long_bar = await self.progress_bar_manager.progress_bar("green", length=20)
|
||||
|
||||
await ctx.respond(
|
||||
f"Short (5): {short_bar.partial(0.7)}\n"
|
||||
f"Medium (10): {medium_bar.partial(0.7)}\n"
|
||||
f"Long (20): {long_bar.partial(0.7)}"
|
||||
)
|
||||
```
|
||||
|
||||
For more examples, check the [examples directory](/examples) in the repository.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Bot Configuration
|
||||
|
||||
When creating your Discord bot, make sure to enable emoji caching:
|
||||
|
||||
```python
|
||||
bot = discord.Bot(cache_app_emojis=True)
|
||||
```
|
||||
|
||||
This is required for the `ProgressBarManager` to properly load and manage emojis.
|
||||
|
||||
### Progress Bar Manager Initialization
|
||||
|
||||
Initialize the `ProgressBarManager` after your bot is ready:
|
||||
|
||||
```python
|
||||
@discord.Cog.listener()
|
||||
async def on_ready(self) -> None:
|
||||
self.progress_bar_manager = await ProgressBarManager(self.bot)
|
||||
```
|
||||
|
||||
### Custom Progress Bar Styles
|
||||
|
||||
You can create custom progress bar styles by providing your own emoji images:
|
||||
|
||||
#### From URLs
|
||||
|
||||
```python
|
||||
from discord_progress_bar import ProgressBarPart
|
||||
|
||||
# Define URLs for each part of the progress bar
|
||||
custom_style = {
|
||||
ProgressBarPart.LEFT_EMPTY: "https://example.com/left_empty.png",
|
||||
ProgressBarPart.LEFT_FILLED: "https://example.com/left_filled.png",
|
||||
ProgressBarPart.MIDDLE_EMPTY: "https://example.com/middle_empty.png",
|
||||
ProgressBarPart.MIDDLE_FILLED: "https://example.com/middle_filled.png",
|
||||
ProgressBarPart.RIGHT_EMPTY: "https://example.com/right_empty.png",
|
||||
ProgressBarPart.RIGHT_FILLED: "https://example.com/right_filled.png",
|
||||
}
|
||||
|
||||
# Create emojis from URLs
|
||||
await self.progress_bar_manager.create_emojis_from_urls("custom_style", custom_style)
|
||||
```
|
||||
|
||||
#### From Files
|
||||
|
||||
```python
|
||||
import pathlib
|
||||
from discord_progress_bar import ProgressBarPart
|
||||
|
||||
# Define file paths for each part of the progress bar
|
||||
custom_style = {
|
||||
ProgressBarPart.LEFT_EMPTY: pathlib.Path("path/to/left_empty.png"),
|
||||
ProgressBarPart.LEFT_FILLED: pathlib.Path("path/to/left_filled.png"),
|
||||
ProgressBarPart.MIDDLE_EMPTY: pathlib.Path("path/to/middle_empty.png"),
|
||||
ProgressBarPart.MIDDLE_FILLED: pathlib.Path("path/to/middle_filled.png"),
|
||||
ProgressBarPart.RIGHT_EMPTY: pathlib.Path("path/to/right_empty.png"),
|
||||
ProgressBarPart.RIGHT_FILLED: pathlib.Path("path/to/right_filled.png"),
|
||||
}
|
||||
|
||||
# Create emojis from files
|
||||
await self.progress_bar_manager.create_emojis_from_files("custom_style", custom_style)
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
> [!WARNING]
|
||||
> Please be aware of the following limitations:
|
||||
>
|
||||
> - **Python Version**: Supports Python 3.12 only
|
||||
> - **Discord Bot Framework**: Currently only supports py-cord, not discord.py or other Discord API wrappers
|
||||
> - **Emoji Limits**: Subject to Discord's app emoji limits (2'000 emojis per app - should be plenty for most use cases)
|
||||
> - **Pre-release Status**: This package is currently in alpha stage and may have unexpected behaviors or breaking changes in future versions
|
||||
> - **Custom Styles**: Creating custom styles requires providing all six emoji parts (LEFT_EMPTY, LEFT_FILLED, MIDDLE_EMPTY, MIDDLE_FILLED, RIGHT_EMPTY, RIGHT_FILLED)
|
||||
|
||||
## Getting Help
|
||||
|
||||
If you encounter issues or have questions about discord-progress-bar:
|
||||
|
||||
- **GitHub Issues**:
|
||||
[Submit a bug report or feature request](https://github.com/Paillat-dev/discord-progress-bar/issues)
|
||||
- **Discord Support**:
|
||||
- For py-cord related questions: Join the
|
||||
[Pycord Official Server](https://discord.gg/pycord)
|
||||
- For discord-progress-bar specific help: Join the
|
||||
[Pycord Official Server](https://discord.gg/pycord) and mention `@paillat`
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
> [!TIP]
|
||||
> Before asking for help, check if your question is already answered in the [examples directory](/examples) or existing GitHub issues.
|
||||
|
||||
## Development
|
||||
|
||||
### Contributing
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch
|
||||
3. Make your changes
|
||||
4. Run linter, formatter and type checker: `ruff check .`,`ruff format .`,
|
||||
`basedpyright .`
|
||||
5. Submit a pull request
|
||||
|
||||
**Development Tools**:
|
||||
|
||||
- **uv**: For dependency management
|
||||
- **Ruff**: For linting and formatting
|
||||
- **HashiCorp Copywrite**: For managing license headers
|
||||
- **basedpyright**: For type checking
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
> [!CAUTION]
|
||||
> This is an early-stage project and may have unexpected behaviors or bugs. Please report any issues you encounter.
|
||||
|
||||
## License
|
||||
|
||||
MIT License - Copyright (c) 2025 Paillat-dev
|
||||
|
||||
---
|
||||
|
||||
Made with ❤ by Paillat-dev
|
||||
158
pyproject.toml
Normal file
158
pyproject.toml
Normal file
@@ -0,0 +1,158 @@
|
||||
[build-system]
|
||||
requires = ["hatchling", "hatch-vcs", "hatch-fancy-pypi-readme"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "dismoji"
|
||||
dynamic = ["version", "urls", "readme"]
|
||||
description = "***"
|
||||
authors = [
|
||||
{ name = "Paillat-dev", email = "me@paillat.dev" }
|
||||
]
|
||||
license = "MIT"
|
||||
requires-python = "==3.12.*"
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Typing :: Typed",
|
||||
"Operating System :: OS Independent",
|
||||
]
|
||||
keywords = ["discord", "bot", "emojis", "emoji"]
|
||||
dependencies = [
|
||||
"json5>=0.12.0",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"basedpyright>=1.28.1",
|
||||
"pytest>=8.3.5",
|
||||
"python-dotenv>=1.0.1",
|
||||
"ruff>=0.9.9",
|
||||
]
|
||||
|
||||
[tool.hatch.version]
|
||||
source = "vcs"
|
||||
|
||||
[tool.hatch.build.hooks.vcs]
|
||||
version-file = "src/dismoji/_version.py"
|
||||
|
||||
[tool.hatch.metadata.hooks.vcs.urls]
|
||||
Homepage = "https://github.com/Paillat-dev/dismoji"
|
||||
source_archive = "https://github.com/Paillat-dev/dismoji/archive/{commit_hash}.zip"
|
||||
|
||||
[tool.hatch.metadata.hooks.fancy-pypi-readme]
|
||||
content-type = "text/markdown"
|
||||
|
||||
[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
|
||||
path = "README.md"
|
||||
start-after = "<!-- badges -->\n"
|
||||
end-before = "\n<!-- end badges -->"
|
||||
|
||||
[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
|
||||
text = "\n\n---\n"
|
||||
|
||||
[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
|
||||
path = "README.md"
|
||||
start-after = "## Overview\n"
|
||||
end-before = "\n## Installation"
|
||||
|
||||
[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
|
||||
path = "README.md"
|
||||
start-after = "<!-- quick-start -->"
|
||||
|
||||
[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]]
|
||||
pattern = '\[(.+?)\]\(((?!https?://)\S+?)\)'
|
||||
replacement = '[\1](https://github.com/Paillat-dev/dismoji/tree/main\g<2>)'
|
||||
|
||||
[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]]
|
||||
pattern = '\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]'
|
||||
replacement = '**\1**:'
|
||||
|
||||
[tool.hatchling]
|
||||
name = "dismoji"
|
||||
|
||||
[tool.hatch.build]
|
||||
include = [
|
||||
"src/dismoji/",
|
||||
"src/dismoji/raw/build/emojis.json",
|
||||
]
|
||||
exclude = [
|
||||
".copywrite.hcl",
|
||||
".github",
|
||||
".python-version",
|
||||
"uv.lock",
|
||||
"src/dismoji/raw/*.*",
|
||||
"src/dismoji/raw/.*/",
|
||||
"src/dismoji/raw/src/"
|
||||
]
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/dismoji"]
|
||||
|
||||
[tool.pyright]
|
||||
pythonVersion = "3.9"
|
||||
typeCheckingMode = "all"
|
||||
reportUnusedCallResult = false
|
||||
reportAny = false
|
||||
executionEnvironments = [
|
||||
{ root = "src/dismoji/_version.py", reportDeprecated = false },
|
||||
{ root = "examples", reportExplicitAny = false, reportUnknownMemberType = false, reportUnusedParameter = false, reportImplicitOverride = false }
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py39"
|
||||
line-length = 120
|
||||
indent-width = 4
|
||||
|
||||
[tool.ruff.format]
|
||||
quote-style = "double"
|
||||
indent-style = "space"
|
||||
skip-magic-trailing-comma = false
|
||||
line-ending = "auto"
|
||||
docstring-code-format = false
|
||||
docstring-code-line-length = "dynamic"
|
||||
exclude = [
|
||||
"src/dismoji/_version.py"
|
||||
]
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["ALL"]
|
||||
per-file-ignores = { "examples/**/*" = ["INP001", "ARG002", "T201"], "tests/**/*" = ["S101"], "src/dismoji/_version.py" = ["I001", "Q000", "UP005", "UP006", "UP035"] }
|
||||
extend-ignore = [
|
||||
"N999",
|
||||
"D104",
|
||||
"D100",
|
||||
"D103",
|
||||
"D102",
|
||||
"D101",
|
||||
"D107",
|
||||
"D105",
|
||||
"D106",
|
||||
"ANN401",
|
||||
"TRY003",
|
||||
"EM101",
|
||||
"EM102",
|
||||
"G004",
|
||||
"PTH",
|
||||
"D211",
|
||||
"D213",
|
||||
"COM812",
|
||||
"ISC001",
|
||||
"D203",
|
||||
"FBT001",
|
||||
"FBT002",
|
||||
"PLR2004",
|
||||
"PLR0913",
|
||||
"C901",
|
||||
"ISC003" # conflicts with basedpyright reportImplicitStringConcatenation
|
||||
]
|
||||
|
||||
[tool.uv.sources]
|
||||
py-cord = { git = "https://github.com/Pycord-Development/pycord", rev = "c0c0b7c58f7b489983a159f5e0eea2c0dab0b0c8" }
|
||||
25
renovate.json
Normal file
25
renovate.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:recommended"],
|
||||
"baseBranches": ["master"],
|
||||
"labels": ["deps"],
|
||||
"ignorePaths": ["requirements.txt"],
|
||||
"commitMessagePrefix": "⬆️",
|
||||
"commitMessageAction": "Upgrade",
|
||||
"packageRules": [
|
||||
{
|
||||
"updateTypes": ["pin"],
|
||||
"commitMessagePrefix": "📌",
|
||||
"commitMessageAction": "Pin"
|
||||
},
|
||||
{
|
||||
"updateTypes": ["rollback"],
|
||||
"commitMessagePrefix": "⬇️",
|
||||
"commitMessageAction": "Downgrade"
|
||||
},
|
||||
{
|
||||
"matchDatasources": ["pypi"],
|
||||
"addLabels": ["pypi"]
|
||||
}
|
||||
]
|
||||
}
|
||||
37
src/dismoji/__init__.py
Normal file
37
src/dismoji/__init__.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# Copyright (c) Paillat-dev
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
EMOJIS_PATH = Path(__file__).parent / "raw" / "build" / "emojis.json"
|
||||
|
||||
with EMOJIS_PATH.open("r", encoding="utf-8") as f:
|
||||
EMOJIS = json.load(f)
|
||||
|
||||
EMOJI_MAPPING: dict[str, str] = {k: EMOJIS["emojis"][v]["surrogates"] for k, v in EMOJIS["nameToEmoji"].items()}
|
||||
|
||||
EMOJI_PATTERN = re.compile(r"(?<!\w):([a-zA-Z0-9_-]+):(?!\w)")
|
||||
|
||||
|
||||
def emojize(s: str) -> str:
|
||||
"""Convert a string with emoji names to a string with emoji characters.
|
||||
|
||||
Args:
|
||||
s (str): The input string containing emoji names.
|
||||
|
||||
Returns:
|
||||
str: The input string with emoji names replaced by emoji characters.
|
||||
|
||||
"""
|
||||
|
||||
def replace(match: re.Match[str]) -> str:
|
||||
emoji_name = match.group(1)
|
||||
if emoji_name in EMOJI_MAPPING:
|
||||
return EMOJI_MAPPING[emoji_name]
|
||||
return match.group(0)
|
||||
|
||||
return EMOJI_PATTERN.sub(replace, s)
|
||||
0
src/dismoji/py.typed
Normal file
0
src/dismoji/py.typed
Normal file
1
src/dismoji/raw
Submodule
1
src/dismoji/raw
Submodule
Submodule src/dismoji/raw added at f4c3abf844
2
tests/__init__.py
Normal file
2
tests/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# Copyright (c) Paillat-dev
|
||||
# SPDX-License-Identifier: MIT
|
||||
43
tests/emoji_test.py
Normal file
43
tests/emoji_test.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# Copyright (c) Paillat-dev
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from dismoji import emojize
|
||||
|
||||
|
||||
def test_basic() -> None:
|
||||
"""Test basic functionality of emojize function."""
|
||||
assert emojize("Hello :smile:") == "Hello 😄"
|
||||
|
||||
|
||||
def test_no_match() -> None:
|
||||
"""Test emojize function with no matches."""
|
||||
assert emojize("Hello world") == "Hello world"
|
||||
|
||||
|
||||
def test_not_emoji() -> None:
|
||||
"""Test emojize function with non-emoji input."""
|
||||
assert emojize("Hello :not_an_emoji:") == "Hello :not_an_emoji:"
|
||||
|
||||
|
||||
def test_surrogate() -> None:
|
||||
"""Test emojize function with surrogate pairs."""
|
||||
surrogate_pairs = [
|
||||
(":handshake_light_skin_tone_dark_skin_tone:", "🫱🏻🫲🏿"),
|
||||
(":handshake_dark_skin_tone_light_skin_tone:", "🫱🏿🫲🏻"),
|
||||
(":handshake_medium_skin_tone_light_skin_tone:", "🫱🏽🫲🏻"),
|
||||
(":handshake_medium_light_skin_tone_dark_skin_tone:", "🫱🏼🫲🏿"),
|
||||
(":handshake_medium_dark_skin_tone_light_skin_tone:", "🫱🏾🫲🏻"),
|
||||
]
|
||||
|
||||
for emoji_name, surrogate in surrogate_pairs:
|
||||
assert emojize(emoji_name) == surrogate
|
||||
|
||||
|
||||
def test_multiple_emojis() -> None:
|
||||
"""Test emojize function with multiple emojis."""
|
||||
assert emojize(":smile: :wave:") == "😄 👋"
|
||||
|
||||
|
||||
def test_complex_sentence() -> None:
|
||||
"""Test emojize function with a complex sentence."""
|
||||
assert emojize("Hello :wave:, what's up? :smile: :white_check_mark: :smile:") == "Hello 👋, what's up? 😄 ✅ 😄"
|
||||
151
uv.lock
generated
Normal file
151
uv.lock
generated
Normal file
@@ -0,0 +1,151 @@
|
||||
version = 1
|
||||
revision = 1
|
||||
requires-python = "==3.12.*"
|
||||
|
||||
[[package]]
|
||||
name = "basedpyright"
|
||||
version = "1.29.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "nodejs-wheel-binaries" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b9/18/f5e488eac4960ad9a2e71b95f0d91cf93a982c7f68aa90e4e0554f0bc37e/basedpyright-1.29.1.tar.gz", hash = "sha256:06bbe6c3b50ab4af20f80e154049477a50d8b81d2522eadbc9f472f2f92cd44b", size = 21773469 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/95/1b/1bb837bbb7e259928f33d3c105dfef4f5349ef08b3ef45576801256e3234/basedpyright-1.29.1-py3-none-any.whl", hash = "sha256:b7eb65b9d4aaeeea29a349ac494252032a75a364942d0ac466d7f07ddeacc786", size = 11397959 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dismoji"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "json5" },
|
||||
]
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "basedpyright" },
|
||||
{ name = "pytest" },
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "ruff" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "json5", specifier = ">=0.12.0" }]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
{ name = "basedpyright", specifier = ">=1.28.1" },
|
||||
{ name = "pytest", specifier = ">=8.3.5" },
|
||||
{ name = "python-dotenv", specifier = ">=1.0.1" },
|
||||
{ name = "ruff", specifier = ">=0.9.9" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "json5"
|
||||
version = "0.12.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/12/be/c6c745ec4c4539b25a278b70e29793f10382947df0d9efba2fa09120895d/json5-0.12.0.tar.gz", hash = "sha256:0b4b6ff56801a1c7dc817b0241bca4ce474a0e6a163bfef3fc594d3fd263ff3a", size = 51907 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/41/9f/3500910d5a98549e3098807493851eeef2b89cdd3032227558a104dfe926/json5-0.12.0-py3-none-any.whl", hash = "sha256:6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db", size = 36079 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodejs-wheel-binaries"
|
||||
version = "22.14.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d7/c7/4fd3871d2b7fd5122216245e273201ab98eda92bbd6fe9ad04846b758c56/nodejs_wheel_binaries-22.14.0.tar.gz", hash = "sha256:c1dc43713598c7310d53795c764beead861b8c5021fe4b1366cb912ce1a4c8bf", size = 8055 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/61/b6/66ef4ef75ea7389ea788f2d5505bf9a8e5c3806d56c7a90cf46a6942f1cf/nodejs_wheel_binaries-22.14.0-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:d8ab8690516a3e98458041286e3f0d6458de176d15c14f205c3ea2972131420d", size = 50326597 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/78/023d91a293ba73572a643bc89d11620d189f35f205a309dd8296aa45e69a/nodejs_wheel_binaries-22.14.0-py2.py3-none-macosx_11_0_x86_64.whl", hash = "sha256:b2f200f23b3610bdbee01cf136279e005ffdf8ee74557aa46c0940a7867956f6", size = 51158258 },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/86/324f6342c79e5034a13319b02ba9ed1f4ac8813af567d223c9a9e56cd338/nodejs_wheel_binaries-22.14.0-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0877832abd7a9c75c8c5caafa37f986c9341ee025043c2771213d70c4c1defa", size = 57180264 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/9f/42bdaab26137e31732bff00147b9aca2185d475b5752b57a443e6c7ba93f/nodejs_wheel_binaries-22.14.0-py2.py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fded5a70a8a55c2135e67bd580d8b7f2e94fcbafcc679b6a2d5b92f88373d69", size = 57693251 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/d7/94f8f269aa86cf35f9ed2b70d09aca48dc971fb5656fdc4a3b69364b189f/nodejs_wheel_binaries-22.14.0-py2.py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c1ade6f3ece458b40c02e89c91d5103792a9f18aaad5026da533eb0dcb87090e", size = 58841717 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/a0/43b7316eaf22b4ee9bfb897ee36c724efceac7b89d7d1bedca28057b7be1/nodejs_wheel_binaries-22.14.0-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:34fa5ed4cf3f65cbfbe9b45c407ffc2fc7d97a06cd8993e6162191ff81f29f48", size = 59808791 },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/0a/814491f751a25136e37de68a2728c9a9e3c1d20494aba5ff3c230d5f9c2d/nodejs_wheel_binaries-22.14.0-py2.py3-none-win_amd64.whl", hash = "sha256:ca7023276327455988b81390fa6bbfa5191c1da7fc45bc57c7abc281ba9967e9", size = 40478921 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/5c/cab444afaa387dceac8debb817b52fd00596efcd2d54506c27311c6fe6a8/nodejs_wheel_binaries-22.14.0-py2.py3-none-win_arm64.whl", hash = "sha256:fd59c8e9a202221e316febe1624a1ae3b42775b7fb27737bf12ec79565983eaf", size = 36206637 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "25.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.5.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.3.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
{ name = "iniconfig" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pluggy" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.11.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d9/11/bcef6784c7e5d200b8a1f5c2ddf53e5da0efec37e6e5a44d163fb97e04ba/ruff-0.11.6.tar.gz", hash = "sha256:bec8bcc3ac228a45ccc811e45f7eb61b950dbf4cf31a67fa89352574b01c7d79", size = 4010053 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/1f/8848b625100ebcc8740c8bac5b5dd8ba97dd4ee210970e98832092c1635b/ruff-0.11.6-py3-none-linux_armv6l.whl", hash = "sha256:d84dcbe74cf9356d1bdb4a78cf74fd47c740bf7bdeb7529068f69b08272239a1", size = 10248105 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/47/c44036e70c6cc11e6ee24399c2a1e1f1e99be5152bd7dff0190e4b325b76/ruff-0.11.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9bc583628e1096148011a5d51ff3c836f51899e61112e03e5f2b1573a9b726de", size = 11001494 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/5b/170444061650202d84d316e8f112de02d092bff71fafe060d3542f5bc5df/ruff-0.11.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f2959049faeb5ba5e3b378709e9d1bf0cab06528b306b9dd6ebd2a312127964a", size = 10352151 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/91/f02839fb3787c678e112c8865f2c3e87cfe1744dcc96ff9fc56cfb97dda2/ruff-0.11.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63c5d4e30d9d0de7fedbfb3e9e20d134b73a30c1e74b596f40f0629d5c28a193", size = 10541951 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/f3/c09933306096ff7a08abede3cc2534d6fcf5529ccd26504c16bf363989b5/ruff-0.11.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a4b9a4e1439f7d0a091c6763a100cef8fbdc10d68593df6f3cfa5abdd9246e", size = 10079195 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/0d/a87f8933fccbc0d8c653cfbf44bedda69c9582ba09210a309c066794e2ee/ruff-0.11.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5edf270223dd622218256569636dc3e708c2cb989242262fe378609eccf1308", size = 11698918 },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/7d/8eac0bd083ea8a0b55b7e4628428203441ca68cd55e0b67c135a4bc6e309/ruff-0.11.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f55844e818206a9dd31ff27f91385afb538067e2dc0beb05f82c293ab84f7d55", size = 12319426 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/dc/d0c17d875662d0c86fadcf4ca014ab2001f867621b793d5d7eef01b9dcce/ruff-0.11.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d8f782286c5ff562e4e00344f954b9320026d8e3fae2ba9e6948443fafd9ffc", size = 11791012 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/f3/81a1aea17f1065449a72509fc7ccc3659cf93148b136ff2a8291c4bc3ef1/ruff-0.11.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01c63ba219514271cee955cd0adc26a4083df1956d57847978383b0e50ffd7d2", size = 13949947 },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/9f/a3e34de425a668284e7024ee6fd41f452f6fa9d817f1f3495b46e5e3a407/ruff-0.11.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15adac20ef2ca296dd3d8e2bedc6202ea6de81c091a74661c3666e5c4c223ff6", size = 11471753 },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/c5/4a57a86d12542c0f6e2744f262257b2aa5a3783098ec14e40f3e4b3a354a/ruff-0.11.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4dd6b09e98144ad7aec026f5588e493c65057d1b387dd937d7787baa531d9bc2", size = 10417121 },
|
||||
{ url = "https://files.pythonhosted.org/packages/58/3f/a3b4346dff07ef5b862e2ba06d98fcbf71f66f04cf01d375e871382b5e4b/ruff-0.11.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:45b2e1d6c0eed89c248d024ea95074d0e09988d8e7b1dad8d3ab9a67017a5b03", size = 10073829 },
|
||||
{ url = "https://files.pythonhosted.org/packages/93/cc/7ed02e0b86a649216b845b3ac66ed55d8aa86f5898c5f1691797f408fcb9/ruff-0.11.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bd40de4115b2ec4850302f1a1d8067f42e70b4990b68838ccb9ccd9f110c5e8b", size = 11076108 },
|
||||
{ url = "https://files.pythonhosted.org/packages/39/5e/5b09840fef0eff1a6fa1dea6296c07d09c17cb6fb94ed5593aa591b50460/ruff-0.11.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:77cda2dfbac1ab73aef5e514c4cbfc4ec1fbef4b84a44c736cc26f61b3814cd9", size = 11512366 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/4c/1cd5a84a412d3626335ae69f5f9de2bb554eea0faf46deb1f0cb48534042/ruff-0.11.6-py3-none-win32.whl", hash = "sha256:5151a871554be3036cd6e51d0ec6eef56334d74dfe1702de717a995ee3d5b287", size = 10485900 },
|
||||
{ url = "https://files.pythonhosted.org/packages/42/46/8997872bc44d43df986491c18d4418f1caff03bc47b7f381261d62c23442/ruff-0.11.6-py3-none-win_amd64.whl", hash = "sha256:cce85721d09c51f3b782c331b0abd07e9d7d5f775840379c640606d3159cae0e", size = 11558592 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/6a/65fecd51a9ca19e1477c3879a7fda24f8904174d1275b419422ac00f6eee/ruff-0.11.6-py3-none-win_arm64.whl", hash = "sha256:3567ba0d07fb170b1b48d944715e3294b77f5b7679e8ba258199a250383ccb79", size = 10682766 },
|
||||
]
|
||||
Reference in New Issue
Block a user