mirror of
https://github.com/Paillat-dev/dismoji.git
synced 2026-01-02 00:56:19 +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