EmbedDesire - Professional Python Asset Embedding
embdes is a production-ready tool for embedding static resources (images, sounds, text files, folders) directly into Python applications and building standalone executables with PyInstaller.
Features
- Embed resources into Python applications with optional compression
- Automatic extraction with built-in caching (100% cache hit rate)
- Development/Runtime modes — swap between reading from disk and reading from embedded data with one call
- PyInstaller integration — automated build process via
embdesCLI - Persistent storage — save/load embedded data manually if needed
- Production-ready — comprehensive logging, validation, error handling
- Cross-platform — Windows, macOS, Linux support
- Global CLI — callable from any directory as
embdescommand
Installation
pip install embdes
How It Works
embed() always returns the original file path. What changes between modes is what happens under the hood:
| Mode | set_runtime_mode(...) |
embed() behavior |
|---|---|---|
| Runtime mode | True |
Skips embedding — just returns the path so you read from disk as normal |
| Embedded mode | False |
Reads and stores the file in memory — the returned path is used to access embedded data in the built exe |
This means your app code stays identical in both modes — you always just open(embed(...)).
Basic Usage
from embeddesire import embed, set_runtime_mode
set_runtime_mode(True) # Read from disk (development)
embedded = embed(".\\hello.txt", id="hello", compress=True)
with open(embedded, "r") as f:
print(f.read())
Switch to set_runtime_mode(False) when you want to work with embedded data (e.g. inside a built exe where the original files no longer exist on disk).
Building a Standalone Exe
Using embdes (Recommended)
embdes automates everything. Write your app normally, then build with one command.
app.py
from embeddesire import embed, set_runtime_mode
set_runtime_mode(True) # During dev, reads from disk
config = embed("config.json", id="config", compress=False)
sprites = embed("assets/sprites/",id="sprites", compress=True)
sounds = embed("assets/sounds/", id="sounds", compress=True)
with open(config, "r") as f:
print(f.read())
# Use sprites and sounds paths however your app needs them
Build
embdes app.py
embdes will:
- Validate all paths passed to
embed()exist on disk - Execute your script to collect all
embed()calls - Save the embedded data to
embedded_data.pkl - Call PyInstaller with the pickle bundled in automatically
- Clean up temporary files
The resulting exe in dist/ has all your assets baked in — no external files needed.
Manual Build (Full Control)
Use this if you have an existing PyInstaller setup, a .spec file, or prefer not to use embdes.
Step 1 — Generate the pickle
Run a small preparation script once before building:
# prepare.py
from embeddesire import embed, save_embedded, set_runtime_mode
set_runtime_mode(False) # Must be False so embed() actually stores the data
embed("config.json", id="config", compress=False)
embed("assets/sprites/",id="sprites", compress=True)
embed("assets/sounds/", id="sounds", compress=True)
save_embedded("embedded_data.pkl")
python prepare.py
Step 2 — Pass the pickle to PyInstaller yourself
pyinstaller app.py --onefile --add-data "embedded_data.pkl;."
Step 3 — Load it inside the exe
# app.py
import sys, os
from embeddesire import embed, set_runtime_mode, load_embedded, extract
if getattr(sys, "frozen", False):
# Inside the exe — load the bundled pickle, then use extract() to get files out
load_embedded(os.path.join(sys._MEIPASS, "embedded_data.pkl"))
config_dir = extract("config")
config_path = os.path.join(config_dir, "config.json")
with open(config_path, "r") as f:
print(f.read())
else:
# Development — read from disk as normal
set_runtime_mode(True)
config = embed("config.json", id="config", compress=False)
with open(config, "r") as f:
print(f.read())
Note:
extract()only works on data already in memory fromload_embedded(). It does not read from disk on its own.
Embedding Options
Disable compression for pre-compressed formats
Compression (compress=True) is on by default. Turn it off for files already compressed to avoid wasted CPU and larger output:
embed("photo.jpg", id="photo", compress=False)
embed("music.mp3", id="music", compress=False)
embed("archive.zip", id="archive", compress=False)
Extract to a specific location (manual builds)
path = extract("sprites", output_path="./runtime/sprites")
Managing Embedded Resources
from embeddesire import get_embedded_resources, remove_embedded_resource, get_cache_stats, clear_cache
# See all IDs currently embedded in memory
print(get_embedded_resources())
# ['config', 'sprites', 'sounds']
# Remove one to free memory
remove_embedded_resource("sounds")
# How many extract() calls were served from cache vs freshly written to disk
print(get_cache_stats())
# {'hits': 8, 'misses': 3, 'current_size': 0}
# Delete all temp extraction directories (next extract() call will re-extract)
clear_cache()
Error Handling
from embeddesire import embed, extract, load_embedded
from embeddesire import EmbedError, ExtractError, PersistenceError, ValidationError
try:
embed("nonexistent/path/file.txt", id="data")
except EmbedError as e:
print(f"Embed failed: {e}")
try:
extract("id_that_was_never_embedded")
except ExtractError as e:
print(f"Extract failed: {e}")
try:
load_embedded("missing_or_corrupt.pkl")
except PersistenceError as e:
print(f"Load failed: {e}")
Logging
from embeddesire import configure_logging, LogLevel
configure_logging(LogLevel.DEBUG) # Full trace — sizes, cache hits, paths
configure_logging(LogLevel.WARNING) # Quiet — only problems reported
configure_logging(LogLevel.INFO, format_string="%(levelname)s | %(message)s")
CLI Reference
embdes <script.py> [pyinstaller_args...]
Arguments after the script are passed directly to PyInstaller:
embdes app.py # Basic build
embdes app.py --windowed # No console window
embdes app.py --windowed --icon=app.ico # With custom icon
embdes app.py --name=MyApp # Custom exe name
embdes app.py --add-data "extra.db;." # Bundle extra files too
API Reference
| Function | Description |
|---|---|
embed(path, id, compress=True) |
Embed a file or folder; always returns the original path |
extract(id, output_path=None) |
Extract an in-memory resource to disk (cached) |
set_runtime_mode(value) |
True = read from disk, False = read from embedded data |
save_embedded(file_path) |
Save all embedded data to a pickle file |
load_embedded(file_path) |
Load embedded data from a pickle file into memory |
clear_cache() |
Delete all temp extraction directories |
get_cache_stats() |
Return {hits, misses, current_size} dict |
get_embedded_resources() |
List all currently embedded IDs |
remove_embedded_resource(id) |
Remove a resource from memory |
configure_logging(level, format_string) |
Set log level and format |
Configuration
export EMBEDDESIRE_COMPRESSION_LEVEL=9 # zlib level 0-9 (default 6)
export EMBEDDESIRE_MAX_FILE_SIZE=50000000 # bytes (default 100 MB)
export EMBEDDESIRE_MAX_CACHE_SIZE=250000000 # bytes (default 500 MB)
Requirements
- Python 3.7+
- PyInstaller (required only for
embdesCLI builds)
License
MIT License — See LICENSE file
Release files for embdes 1.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| embdes-1.0.2.tar.gz | 9.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| embdes-1.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 19.6 kB
Release files / embdes-1.0.2.tar.gz
| Download URL | embdes-1.0.2.tar.gz |
|---|---|
| Size | 9.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3c3fcbe3e828cad6f10eb16583d0d10306a1b200016b82d3c2cddede49784f89
|
|
BLAKE2b-256 checksum How to use checksums |
f4604cec7f9cebbd5f75aee4a648fe14d9968992f14ded98da2cde678c7d1311
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Release files / embdes-1.0.2-py3-none-any.whl
| Download URL | embdes-1.0.2-py3-none-any.whl |
|---|---|
| Size | 9.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
480de7fc59111de98830f461467f0eee548497ff866eeb9f36f6bc961dcddc89
|
|
BLAKE2b-256 checksum How to use checksums |
a80c2b9c8c0e7f09111bb35d0d06937580b4d217eaafd0bd4cd48e434e71f32a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|