A lightweight library for detecting system environment, GUI, and build properties.
Project description
pyhabitat ๐งญ
An Introspection Library for Python Environments and Builds
pyhabitat is a lightweight library for Python build and environment introspection. It accurately and securely determines the execution context of a running script by providing definitive checks for:
- OS and Environments: Operating Systems and common container/emulation environments (e.g., Termux, iSH).
- Build States: Application build systems (e.g., PyInstaller, pipx).
- GUI Backends: Availability of graphical toolkits (e.g., Matplotlib, Tkinter).
Stop writing verbose sys.platform and environment variable checks. Use pyhabitat to implement clean, architectural logic based on the execution habitat.
Read the code on github. ๐
๐ฆ Installation
pip install pyhabitat
๐ง Motivation
This library is especially useful for leveraging Python in mobile environments (Termux on Android and iSH on iOS), which often have particular limitations and require special handling. For example, it helps automate work-arounds like using localhost plotting when matplotlib is unavailable or web-based interfaces when tkinter is missing.
Our team is fundamentally driven by enabling mobile computing for true utility applications, leveraging environments like Termux (Android) and iSH (iOS). This includes highly practical solutions, such as deploying a lightweight Python web server (e.g., Flask, http.server, FastAPI) directly on a handset, or orchestrating full-stack, utility-grade applications that allow technicians to manage data and systems right from their mobile device in a way that is cross-platform and not overly catered to the App Store.
Another key goal of this project is to facilitate the orchestration of wider system installation for pipx CLI tools for additional touch points, like context menus and widgets.
Ultimately, City-of-Memphis-Wastewater aims to produce reference-quality code for the documented proper approach. We recognize that many people (and bots) are searching for ideal solutions, and our functions are built upon extensive research and testing to go beyond simple platform.system() checks.
๐ Features
- Definitive Environment Checks: Rigorous checks catered to Termux and iSH (iOS Alpine). Accurate, typical modern detection for Windows, macOS (Apple), Linux, FreeBSD, Android.
- GUI Availability: Rigorous, cached checks to determine if the environment supports a graphical popup window (Tkinter/Matplotlib TkAgg) or just headless image export (Matplotlib Agg).
- Build/Packaging Detection: Reliable detection of standalone executables (PyInstaller), Python zipapps (.pyz), Python source scripts (.py), and correct identification/exclusion of pipx-managed virtual environments.
- Executable Type Inspection: Uses file magic numbers (ELF, MZ, Mach-O) to confirm if the running script is a monolithic, frozen binary (non-pipx) or zipapp (.pyz).
๐ Function Reference
OS and Environment Checking
Key question: "What is this running on?"
| Function | Description |
|---|---|
on_windows() |
Returns True on Windows. |
on_apple() |
Returns True on macOS (Darwin). |
on_linux() |
Returns True on Linux in general. |
on_wsl() |
Returns True if running inside Windows Subsystem for Linux (WSL or WSL2). |
on_termux() |
Returns True if running in the Termux Android environment. |
on_freebsd() |
Returns True on FreeBSD. |
on_ish_alpine() |
Returns True if running in the iSH Alpine Linux iOS emulator. |
on_android() |
Returns True on any Android-based Linux environment. |
on_pydroid() |
Returns True Return True if running under the Pydroid 3 Android app (other versions untested). |
in_repl() |
Returns True is the user is currently in a Python REPL; hasattr(sys,'ps1'). |
Packaging and Build Checking
Key question: "What is the character of my executable or my build state?"
These functions accept an optional path argument (Path or str), defaulting to sys.argv[0] (e.g., pyhabitat/main.py for python -m pyhabitat, empty in REPL). Path.resolve() is used for stability.
| Function | Description |
|---|---|
as_frozen() |
Returns True if the script is running as a standalone executable (any bundler). |
as_pyinstaller() |
Returns True if the script is frozen and generated by PyInstaller (has _MEIPASS). |
is_python_script(path=None) |
Returns True if the script or specified path is a Python source file (.py). |
is_pipx(path=None) |
Returns True if the script or specified path is from a pipx-managed virtual environment. |
is_elf(path=None) |
Returns True if the script or specified path is an ELF binary (Linux standalone executable, non-pipx). |
is_pyz(path=None) |
Returns True if the script or specified path is a Python zipapp (.pyz, non-pipx). |
is_windows_portable_executable(path=None) |
Returns True if the script or specified path is a Windows PE binary (MZ header, non-pipx). |
is_msix() |
Returns True if the currently running software or the target path is an MSIX package, like distributed from the Microsoft Store. |
is_macos_executable(path=None) |
Returns True if the script or specified path is a macOS Mach-O binary (non-pipx). |
Capability Checking
Key Question: "What could I do next?"
| Function | Description |
|---|---|
tkinter_is_available() |
Checks if Tkinter is imported and can successfully create a window. |
matplotlib_is_available_for_gui_plotting(termux_has_gui=False) |
Checks for Matplotlib and its TkAgg backend, required for interactive plotting. Set termux_has_gui=True for Termux with GUI support; defaults to False. |
matplotlib_is_available_for_headless_image_export() |
Checks for Matplotlib and its Agg backend, required for saving images without a GUI. |
interactive_terminal_is_available() |
Checks if standard input and output streams are connected to a TTY (allows safe use of interactive prompts). |
web_browser_is_available() |
Check if a web browser can be launched in the current environment (allows safe use of web-based prompts and localhost plotting). |
Utility
| Function | Description |
|---|---|
edit_textfile(path) |
Opens a text file for editing using the default editor (Windows, Linux, macOS) or nano in Termux/iSH. Can be called from REPL mode. Path argument (str or Path) uses Path.resolve() for stability. |
interp_path() |
Returns the path to the Python interpreter binary (sys.executable). Returns empty string if unavailable. |
report() |
Prints a comprehensive environment report with sections: Interpreter Checks (sys.executable), Current Environment Check (sys.argv[0]), Current Build Checks (sys attributes), Operating System Checks (platform.system()), and Capability Checks. Run via python -m pyhabitat or import pyhabitat; pyhabitat.main() in the REPL. |
๐ป Usage Examples
The module exposes all detection functions directly for easy access.
0. Example of PyHabitat in Action
The pipeline-eds package uses the pyhabitat library to handle configuration and plotting, among other things.
1. Running the Environment Report
Run a comprehensive environment report from the command line or REPL to inspect the interpreter (sys.executable), running script (sys.argv[0]), build state, operating system, and capabilities.
# In the terminal
python -m pyhabitat
# In the Python REPL
import pyhabitat as ph
ph.main()
2. Checking Environment and Build Type
from pyhabitat import on_termux, on_windows, is_pipx, is_python_script, as_frozen
if is_pipx():
print("Running inside a pipx virtual environment. This is not a standalone binary.")
if as_frozen():
print("Running as a frozen executable (PyInstaller, cx_Freeze, etc.).")
if is_python_script():
print("Running as a Python source script (.py).")
if on_termux():
# Expected cases:
#- pkg install python-numpy python-cryptography
#- Avoiding matplotlib unless the user explicitly sets termux_has_gui=True in matplotlib_is_available_for_gui_plotting().
#- Auto-selection of 'termux-open-url' and 'xdg-open' in logic.
#- Installation on the system, like orchestrating the construction of Termux Widget entries in ~/.shortcuts.
print("Running in the Termux environment on Android.")
if on_windows():
print("Running on Windows.")
3. Checking GUI and Plotting Availability
Use these functions to determine if you can show an interactive plot or if you must save an image file.
from pyhabitat import matplotlib_is_available_for_gui_plotting, matplotlib_is_available_for_headless_image_export
if matplotlib_is_available_for_gui_plotting():
# We can safely call plt.show()
print("GUI plotting is available! Using TkAgg backend.")
import matplotlib.pyplot as plt
plt.figure()
plt.show()
elif matplotlib_is_available_for_headless_image_export():
# We must save the plot to a file or buffer
print("GUI unavailable, but headless image export is possible.")
# Code to use 'Agg' backend and save to disk...
else:
print("Matplotlib is not installed or the environment is too restrictive for plotting.")
4. Text Editing
Use this function to open a text file for editing. Ideal use case: Edit a configuration file, if prompted by a CLI command like 'config --textedit'.
from pathlib import Path
import pyhabitat as ph
ph.edit_textfile(path=Path('./config.json'))
๐๏ธ Build Instructions
Follow these steps to build PyHabitat for different distributions (PYZ, EXE, or Wheel):
- Activate the Virtual Environment
On Windows (PowerShell)
.venv\Scripts\Activate.ps1
Windows (cmd)
.venv\Scripts\activate.bat
On Unix/macOS
source .venv/bin/activate
- Install Build Dependencies
bash
pip install -U pip setuptools wheel pyinstaller
(Optional for .pyz: zipapp is included in the standard library.)
- Build Options
You can build PyHabitat in three ways:
| Output | Command | Notes |
|---|---|---|
| PYZ (Python Zipapp) | python build_pyz.py |
Cross-platform; requires a Python interpreter to run. |
| EXE (Windows Executable) | python build_executable.py |
Windows-only standalone executable with embedded Python. |
| ELF (Linux Executable) | python build_executable.py |
Linux-only standalone executable; generated by PyInstaller on Linux. |
| Mach-O (macOS Executable) | python build_executable.py |
macOS-only standalone executable; generated by PyInstaller on macOS. |
| Wheel / Source | python -m build |
Standard Python package for pip install. |
Build Process Diagram
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Source Code โ
โ pyhabitat โ
โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Build Outputs โ
โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโค
โ โ โ
โผ โผ โผ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ Python Zipappโ โ PyInstaller โ โ Wheel/Sourceโ โ build_pyz.py โ โ Executable โ โ python -m buildโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ dist/.pyz โ โ dist/.[exe,elf,macho] โ โ dist/*.whl โ โ Cross-plat. โ โ Platform-native standalone โ โ pip install โ โ Requires Python โ โ Requires no Python on host โ โ Source/wheelโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ Notes:
.pyz is cross-platform but requires Python on the host system.
.exe is Windows-only and contains a full Python runtime.
.elf is Linux-only and contains a full Python runtime.
.macho is macOS-only and contains a full Python runtime.
Standard python -m build creates a distributable wheel and source archive suitable for pip/pypi.
๐ค Contributing
Contributions are welcome! If there is an environment or build system that is not correctly detected, or that you would like to have added, please open an issue or submit a pull request with the relevant detection logic.
๐ License
This project is licensed under the MIT License. See the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyhabitat-1.1.2.tar.gz.
File metadata
- Download URL: pyhabitat-1.1.2.tar.gz
- Upload date:
- Size: 28.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8f3b7ec016374c30e0543e457fa24802107270592609d5b6e28f2c35a9799695
|
|
| MD5 |
fa219d2f7d56f5795377bd37a7906d95
|
|
| BLAKE2b-256 |
762b139a19de89ed28e65729539d3b8cc2e90b43b6f78432997b764ef7f3ca98
|
Provenance
The following attestation bundles were made for pyhabitat-1.1.2.tar.gz:
Publisher:
publish.yaml on City-of-Memphis-Wastewater/pyhabitat
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyhabitat-1.1.2.tar.gz -
Subject digest:
8f3b7ec016374c30e0543e457fa24802107270592609d5b6e28f2c35a9799695 - Sigstore transparency entry: 780452972
- Sigstore integration time:
-
Permalink:
City-of-Memphis-Wastewater/pyhabitat@4687a0ec6b839a8d209c424e4a43c6b319af0b0c -
Branch / Tag:
refs/tags/v1.1.2 - Owner: https://github.com/City-of-Memphis-Wastewater
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@4687a0ec6b839a8d209c424e4a43c6b319af0b0c -
Trigger Event:
release
-
Statement type:
File details
Details for the file pyhabitat-1.1.2-py3-none-any.whl.
File metadata
- Download URL: pyhabitat-1.1.2-py3-none-any.whl
- Upload date:
- Size: 25.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90665cf60e12876a419a5e596f46713273161f294a86e2e213afd5325197717f
|
|
| MD5 |
30e53fe20368e4745db34da99bb4712d
|
|
| BLAKE2b-256 |
5f4c063746f16d778d3b2a663ef52a63e5416774bf3e50888e1a67cdd9b0221a
|
Provenance
The following attestation bundles were made for pyhabitat-1.1.2-py3-none-any.whl:
Publisher:
publish.yaml on City-of-Memphis-Wastewater/pyhabitat
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyhabitat-1.1.2-py3-none-any.whl -
Subject digest:
90665cf60e12876a419a5e596f46713273161f294a86e2e213afd5325197717f - Sigstore transparency entry: 780452977
- Sigstore integration time:
-
Permalink:
City-of-Memphis-Wastewater/pyhabitat@4687a0ec6b839a8d209c424e4a43c6b319af0b0c -
Branch / Tag:
refs/tags/v1.1.2 - Owner: https://github.com/City-of-Memphis-Wastewater
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@4687a0ec6b839a8d209c424e4a43c6b319af0b0c -
Trigger Event:
release
-
Statement type: