Metadata-Version: 2.4
Name: pymojis
Version: 1.0.0
Summary: A lightweight, type-safe Python library for emoji search, transformation, and detection.
Author-email: Pallandir <pallandir2@gmail.com>
Maintainer-email: Pallandir <pallandir2@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/pallandir/pymojis
Project-URL: Repository, https://github.com/pallandir/pymojis
Project-URL: Issues, https://github.com/pallandir/pymojis/issues
Project-URL: Changelog, https://github.com/pallandir/pymojis/releases
Keywords: emoji,unicode,text,utilities
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Processing
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Classifier: Natural Language :: English
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: full
Requires-Dist: pymojis-fulldata==1.0.0; extra == "full"
Provides-Extra: dev
Requires-Dist: build~=1.2; extra == "dev"
Requires-Dist: pre-commit~=4.2; extra == "dev"
Requires-Dist: pytest~=8.4; extra == "dev"
Requires-Dist: pytest-cov~=6.0; extra == "dev"
Requires-Dist: pytest-mock~=3.10; extra == "dev"
Requires-Dist: twine~=6.1; extra == "dev"
Requires-Dist: mypy~=1.0; extra == "dev"
Requires-Dist: ruff~=0.8; extra == "dev"
Provides-Extra: test
Requires-Dist: pytest~=8.4; extra == "test"
Requires-Dist: pytest-cov~=6.0; extra == "test"
Requires-Dist: pytest-mock~=3.10; extra == "test"
Dynamic: license-file

# pymojis

[![PyPI version](https://img.shields.io/pypi/v/pymojis.svg)](https://pypi.org/project/pymojis/)
[![Python versions](https://img.shields.io/pypi/pyversions/pymojis.svg)](https://pypi.org/project/pymojis/)
[![License: MIT](https://img.shields.io/pypi/l/pymojis.svg)](https://github.com/pallandir/pymojis/blob/main/LICENSE)
[![CI](https://github.com/pallandir/pymojis/actions/workflows/github_ci.yaml/badge.svg)](https://github.com/pallandir/pymojis/actions/workflows/github_ci.yaml)

A small, type-safe Python library for working with emojis: search them by
name / code / character, transform text, detect emojis in strings, and
convert to HTML.

- **Zero runtime dependencies.**
- **Two install sizes**: a tiny default (~230 KB of data) or the full
  Unicode dataset (~1 MB) via the `[full]` extra.
- **Strict typing** — `py.typed`, full mypy strict compliance.
- **Fail-fast API** — bad input raises immediately, no silent `None`
  returns or warnings.

## Install

```bash
pip install pymojis              # lightweight: ~1900 emojis
pip install 'pymojis[full]'      # full Unicode coverage: ~3790 emojis
```

Requires **Python 3.12+**.

## Quick start

```python
from pymojis import PymojisManager

manager = PymojisManager()

# Pick random emojis
print([e.emoji for e in manager.get_random(length=3)])
# → ['😊', '🎉', '🌟']

# Look up by name / code / character
manager.get_by_name("grinning face with smiling eyes")  # → '😄'
manager.get_by_code("1F604")                            # → '😄'
manager.get_by_emoji("😊")                              # → Emoji(...)

# Replace whole-word matches in text
manager.emojifie("I'm sleepy")
# → "I'm 😪"

# Detection
manager.contains_emojis("hello 👋")    # → True
manager.is_emoji("😄")                 # → True
manager.is_emoji("😄😊")               # → False

# HTML hex references
manager.to_html("😵‍💫")
# → "&#x1F635;&#x200D;&#x1F4AB;"
```

To use the full Unicode dataset:

```python
manager = PymojisManager(use_full_dataset=True)
# Requires `pip install 'pymojis[full]'`. Raises DatasetNotFoundError
# with installation instructions otherwise.
```

## API

| Method | Returns | Notes |
|---|---|---|
| `get_random(categories=None, length=1, exclude=None)` | `list[Emoji]` | `categories` takes precedence over `exclude`. |
| `get_all_emojis(exclude=None)` | `list[Emoji]` | `exclude` accepts `"complex"` or a list of categories. |
| `get_by_code(code)` | `str \| None` | Single-codepoint lookup. Case-insensitive. |
| `get_by_name(name)` | `str \| None` | Full-name lookup. Case-insensitive. |
| `get_by_category(category)` | `list[str]` | All emojis in a category. |
| `get_by_emoji(emoji)` | `Emoji \| None` | Reverse lookup from character to record. |
| `contains_emojis(text)` | `bool` | True if `text` contains at least one known emoji. |
| `is_emoji(text)` | `bool` | True if `text.strip()` is a single known emoji. |
| `emojifie(text)` | `str` | Replace whole words with emojis (whose name *contains* that word). |
| `to_html(emoji)` | `str` | Encode each codepoint as `&#xHEX;`. |

All methods raise `TypeError` on non-`str` arguments — no silent `None`.

### Categories

```python
from pymojis import Categories

Categories  # type alias of all valid categories:
#   "Smileys & Emotion", "People & Body", "Animals & Nature",
#   "Food & Drink", "Activities", "Travel & Places", "Objects",
#   "Symbols", "Flags", "Component"
```

### `Emoji` data model

```python
from pymojis import Emoji

@dataclass-like
class Emoji:
    id: str            # auto-generated UUID
    emoji: str         # the character itself, e.g. "😄"
    name: str          # e.g. "grinning face with smiling eyes"
    code: list[str]    # one or more Unicode codepoints, e.g. ["1F604"]
                       #   (multi-codepoint emojis like ZWJ sequences have len > 1)
    category: str      # e.g. "Smileys & Emotion"
    sub_category: str  # e.g. "face-smiling"
```

## Notes on `emojifie`

`emojifie` does whole-word matching. Each word in the input is looked up in
an index of emoji-name tokens. Tokens shorter than 3 characters are skipped
(otherwise pronouns like "I" and "m" would be replaced by ℹ and Ⓜ). When a
word matches multiple emojis, the first one (in dataset order) wins.

```python
manager.emojifie("I'm sleepy")           # → "I'm 😪"  (sleepy → "sleepy face")
manager.emojifie("zzzz xyzzy")           # → "zzzz xyzzy"  (no match, unchanged)
```

## Releases (maintainer notes)

This repo publishes **two** packages on every git tag: `pymojis` and
`pymojis-fulldata`. Both must share the same version.

To cut a release:

```bash
# 1. Bump version in BOTH pyproject files
$EDITOR pyproject.toml                                  # version = "X.Y.Z"
$EDITOR packages/pymojis-fulldata/pyproject.toml        # version = "X.Y.Z"
# Also bump the [full] extra dependency pin in pyproject.toml.

# 2. Commit, tag, push
git commit -am "Release vX.Y.Z"
git tag vX.Y.Z
git push origin main --tags
```

CI runs `scripts/verify_versions.py` to ensure the tag and both pyproject
versions agree, builds both wheels, and publishes via PyPI Trusted
Publishing (OIDC — no API tokens). One-time setup: register both projects
as Trusted Publishers on https://pypi.org pointing at this repo and the
workflow `.github/workflows/github_ci.yaml`.

## Development

```bash
uv sync --all-extras --dev
uv run ruff check .
uv run ruff format --check .
uv run mypy src
uv run pytest
./scripts/build_all.sh
```

`pre-commit` is configured: `uv run pre-commit install` once, and the same
checks run on every commit.

## Contributing

Issues and PRs welcome. Please run the full check suite above before
opening a PR.

## License

MIT — see [LICENSE](LICENSE).

The bundled emoji metadata derives from the work of
[Chalda Pnuzig](https://github.com/chalda-pnuzig/emojis.json) (ISC License,
see `third_party/`).
