ez
A cross-platform Python utility library for easy shell interaction and common programming tasks on Linux, macOS, and Windows.
Installation
pip install ez
Requires Python 3.11+.
For packages used by external scripts (Flask and its extensions, Gunicorn, cachelib, DuckDB, parse, PyYAML, xmltodict, and macOS-only imessage_reader):
pip install 'ez[extra]'
These packages are optional and are not installed with plain ez.
Quick Start
from ez import *
# File operations
files = ls('~/Documents', r'\.py$')
cp('source.txt', '~/backup/')
mv('old_name.txt', 'new_name.txt')
rm('temp/')
# Path utilities
print(cwd()) # current working directory
print(jp('~', 'Documents', 'file')) # join path components
print(sp('/path/to/file.txt')) # => ['/path/to', 'file', '.txt']
# Execute shell commands
execute('ls -la')
output = execute2('echo hello')
esp('echo %s', 'world')
# Read/write spreadsheets
data = readx('data.xlsx')
savex('output.xlsx', data, header=['Name', 'Age'])
Function Catalog
Generated by ez/prepublish.py from the same source as ez.__doc__.
Runtime and Errors
| Function | Aliases | Description |
|---|---|---|
ShellDebug |
debug |
Set the shell debug mode used by file and process operations. |
HTTP and Retries
| Function | Aliases | Description |
|---|---|---|
retry |
Retry a callable with a timeout and randomized waiting intervals. | |
rget |
Fetch an HTTP response as JSON when possible, otherwise as text. | |
rgetraw |
Make a retrying HTTP GET request and return its response. | |
rgetfile |
Download an HTTP response body to a file, retrying failed requests. |
Paths
| Function | Aliases | Description |
|---|---|---|
pwd |
cwd |
Imported from os.getcwd. |
fullpath |
fp |
Resolve an absolute path, expanding variables, user directories, and wildcards. |
csd |
Return the running script directory, or the working directory in interactive mode. | |
stepfolder |
Change to a sibling folder selected by step or regular expression. | |
csf |
Return the running script filename without its extension. | |
parentdir |
pr |
Return the parent directory of a path. |
joinpath |
jp |
Join path components, supporting vectorized arguments. |
splitpath |
sp |
Split a path into directory, filename, and extension. |
extpath |
ep |
Replace a path's filename extension, supporting vectorized arguments. |
cleanpath |
xp |
Clean the filename component of a path. |
Strings and Regular Expressions
| Function | Aliases | Description |
|---|---|---|
trim |
Normalize spaces and trim leading or trailing characters. | |
quote |
Wrap a value in double quotes. | |
join |
Join strings or a sequence using a separator. | |
sprintf |
Format a string using supplied values or the caller's local variables. | |
regexp |
Find regular expression matches, split text, or match from the start. | |
regexpi |
Find regular expression matches without case sensitivity. | |
regexprep |
Replace regular expression matches in a string. | |
regexprepi |
Replace regular expression matches without case sensitivity. |
Directories and Files
| Function | Aliases | Description |
|---|---|---|
cd |
Change the working directory. | |
ce |
Changes to working directory in Finder | |
cf |
Changes to working directory in Path Finder, QSpace, or Finder (auto-detected) | |
ls |
List matching files in a directory. | |
lsd |
List matching subdirectories. | |
fls |
List matching files recursively from a directory tree. | |
flsd |
List matching folders recursively from a directory tree. | |
clorox |
clx |
Find or delete operating-system metadata files. |
mkdir |
Create a directory and any missing parents. | |
exists |
Test whether a path or wildcard pattern exists. | |
rn |
Rename a file or folder. | |
trash |
Move a file or folder to trash. Requires: pip install Send2Trash | |
rm |
Deletes a file or folder. | |
cp |
Copies a source file or folder to destination. | |
mv |
Moves a source file or folder to destination. | |
lns |
Creates a soft link/symbolic link/shortcut. | |
gapfile |
Finds missing and extra files based on a regex pattern. | |
tree |
Print a directory tree, optionally including files or saving the output. | |
lines |
Count lines in matching source files. |
Shell and Processes
| Function | Aliases | Description |
|---|---|---|
execute0 |
Run a shell command and capture its output. | |
execute |
Run a shell command without capturing its output. | |
esp0 |
Run a formatted shell command and capture its output. | |
esp |
Run a formatted shell command without capturing its output. | |
espR0 |
Run formatted R code and capture its output. | |
espR |
Run formatted R code without capturing its output. | |
espA |
Execute formatted AppleScript through a temporary script file. | |
contextmanager |
Imported from contextlib.contextmanager. | |
nooutput |
Temporarily suppress stdout, stderr in a context |
Console, System and Logging
| Function | Aliases | Description |
|---|---|---|
ppprint |
Imported from pprint.pprint. | |
error |
Raise an exception with the supplied message. | |
pprint |
Print colored text to the terminal. | |
beep |
Beeps to notify user. | |
where |
Print the location of a module, function, or Python interpreter. | |
which |
Imported from shutil.which. | |
doc |
help |
Print the docstring of a named module, class, or function. |
getos |
Return the operating system name. | |
ver |
version |
Print the installed version of Python or a package. |
require |
Ensure a package is installed at the latest compatible or a specified version via pip or Conda. | |
evaluate |
Evaluate a Python expression or execute a statement in the caller's scope. | |
who |
whos |
List imported names in the requested scope. |
_setlog |
Enable or disable redirecting stdout to both a file and the terminal. | |
logon |
Enable logging stdout to both a file and the terminal. | |
clear |
Remove a module, optionally including submodules, from sys.modules. | |
logoff |
Disable file logging and restore stdout. |
Randomness
| Function | Aliases | Description |
|---|---|---|
Randomize |
randomize |
Imported from random.seed. |
RandomizeArray |
randomizearray |
Imported from random.shuffle. |
Random |
Imported from random.randint. | |
RandomChoice |
randomchoice |
Imported from random.choice. |
keygen |
Generate a random key. | |
Permute |
permute |
Return all permutations of an iterable as a list. |
Time and Waiting
| Function | Aliases | Description |
|---|---|---|
sleep |
wait |
Imported from time.sleep. |
pause |
Wait for Enter; return False if interrupted with Ctrl+C. | |
daylight |
Test whether a datetime is in daylight saving time in a timezone. |
Numbers and General Helpers
| Function | Aliases | Description |
|---|---|---|
iff |
ifelse |
Return one of two values according to an expression. |
round2 |
Round a number with a small adjustment for halfway values. | |
num |
Convert a value to a number, optionally returning pandas.NA on failure. | |
isempty |
Test for None, an empty value, or a missing numeric value. |
Collections
| Function | Aliases | Description |
|---|---|---|
replace |
Replace matching items in a list. | |
remove |
Remove matching items from a list. | |
sort |
Return a sorted copy of an iterable. | |
chunk |
Split the list, xs, into n chunks. | |
chunk2 |
Split a list into chunks of a requested size. | |
is_iterable |
Test for an iterable, treating strings and tuples as atomic values. | |
unique |
Return unique sequence elements in their original order. | |
union |
Return the ordered union of two sequences. | |
intersect |
Return the ordered intersection of two sequences. | |
setdiff |
Return elements of the first sequence absent from the second, in order. | |
setdiff2 |
Return the elements of seq1 that are absent from seq2. | |
compare |
Print union, intersection, and uniqueness counts for two sequences. | |
duplicated |
Find repeated list items or candidate duplicate files in a directory. |
Hashing
| Function | Aliases | Description |
|---|---|---|
hashes |
Hash or verify text with PBKDF2, or calculate a file's digest values. |
Data and File Formats
| Function | Aliases | Description |
|---|---|---|
readt |
Read a text file as a list of lines. | |
xlcolconv |
Convert between Excel column numbers and letters. | |
readx |
Read an Excel or CSV file into lists. | |
savex |
writex |
Write tabular data to an Excel or CSV file. |
savexlist |
writexlist |
Write multiple pandas dataframes to sheets in an Excel workbook. |
readp |
Read a Parquet file into a pandas object. | |
readplist |
Read and concatenate multiple Parquet files. | |
mergep |
Merge matching Parquet files into one file. | |
savep |
writep |
Save a pandas object as a Parquet file. |
savek |
writek |
Serialize an object to a pickle file. |
readk |
Load and return an object from a pickle file. | |
readj |
Load JSON from a file. | |
savej |
writej |
Save a value as JSON, encoding datetime values as ISO strings. |
savet |
writet |
Write a list of lines to a text file. |
savew |
writew |
Write lines and an optional heading to a Word document. |
Text and Encoding
| Function | Aliases | Description |
|---|---|---|
hanzifreq |
Count Chinese character frequencies in a text file. | |
pinyinauthor |
Format author names as surname and initials for APA references. | |
encoding_detect |
Guess the encoding of text or a file. | |
encoding_convert |
Convert a file to UTF-8. |
Desktop and Keyboard Maestro
| Function | Aliases | Description |
|---|---|---|
opens |
Open files with their default application. | |
vx |
Open a pandas dataframe in a spreadsheet application. | |
getkmvar |
Read a Keyboard Maestro environment variable. | |
setkmvar |
Set a Keyboard Maestro variable using AppleScript. | |
runkm |
Run a Keyboard Maestro macro by UUID. | |
playfirefoxmacro |
Run a UI.Vision browser macro in Firefox. | |
msgbox |
Display a message using Keyboard Maestro. | |
menubar |
Set Keyboard Maestro's menubar text. |
Office-to-Markdown Conversion
| Function | Aliases | Description |
|---|---|---|
_md_paths |
Resolve and validate input and output paths for document conversion. | |
_md_write |
Write converted Markdown to a file or standard output. | |
_md_ranges |
Parse a one-based comma-separated list of values and ranges. | |
_md_load_office |
Load an Office document and normalize missing-member errors. | |
pptx2md |
Convert a PowerPoint presentation to Markdown using MarkItDown. | |
docx2md |
Convert a Word .docx document to Markdown using MarkItDown. | |
xlsx2md |
Convert Excel .xlsx worksheets to Markdown tables using openpyxl. | |
pdf2md |
Convert text-based PDF pages to Markdown using PyMuPDF and MarkItDown. | |
_cli_input_files |
Resolve and validate input files for a batch conversion. | |
_cli_output_files |
Build safe Markdown output paths for batch input files. | |
_cli_batch |
Run a document conversion over the selected batch of input files. | |
_cli |
Run an explicitly registered CLI tool; return an integer exit status. |
Office and PDF Utilities
| Function | Aliases | Description |
|---|---|---|
office_pptx_replace_font |
Replace fonts in a PowerPoint presentation. | |
office_pptx_replace |
Replace matching text in a PowerPoint presentation. | |
office_docx_replace |
Replace matching text in a Word document. | |
office_pdf_from_docx |
Convert a Word document or folder of documents to PDF. | |
office_pdf_from |
Convert documents to PDF using headless LibreOffice. | |
office_doc2docx |
Convert documents to DOCX using headless LibreOffice. | |
office_pdf_unlock |
Remove PDF password restrictions using Ghostscript. | |
office_pdf_crop |
Crop PDF page margins. | |
office_pdf_bookmarkrm |
Remove PDF bookmarks. | |
office_pdf_compress |
Compress PDF files using Ghostscript. | |
office_pdf_merge |
Merge PDF files in the requested order. | |
office_pdf_autoname |
Rename PDFs using bibliographic metadata extracted from their text. |
AppleScript and Applications
| Function | Aliases | Description |
|---|---|---|
applescript_pages_replace |
Replace text in the active Pages document using AppleScript. | |
applescript_pages_pdfactive |
Export the active Pages document to PDF using AppleScript. | |
applescript_preview_moveactive |
Save and move the active Preview PDF using AppleScript. | |
applescript_finder_alias |
Create a Finder alias using AppleScript. | |
applescript_mail |
Compose or send an Apple Mail message using AppleScript. | |
applescript_outlook |
Compose or send an Outlook message using AppleScript. |
Clipboard
| Function | Aliases | Description |
|---|---|---|
SetClip |
setclip |
Copy content to the clipboard. |
GetClip |
getclip |
Read and return the current clipboard contents. |
Mail and Microsoft Authentication
| Function | Aliases | Description |
|---|---|---|
Mail |
mail, gmail |
Send an email using yagmail. |
imapget |
Retrieve emails via IMAP using imap-tools. | |
gmailget |
Retrieve Gmail messages matching the supplied filters. | |
ymailget |
Retrieve Yahoo Mail messages matching the supplied filters. | |
o365auth |
Authenticate to Microsoft 365 and return the account. | |
outlook |
Send or draft a Microsoft 365 email. | |
outlookget |
Retrieve Microsoft 365 messages from a folder. |
OneDrive
| Function | Aliases | Description |
|---|---|---|
onedrive_connect |
Resolve a OneDrive file or folder path to its remote object. | |
onedrive_move |
Move a OneDrive file or folder to another folder. | |
onedrive_copy |
Copy a OneDrive file or folder to another folder. | |
onedrive_delete |
Move a OneDrive file or folder to the recycle bin. | |
onedrive_rename |
Rename a OneDrive file or folder. | |
onedrive_download |
Download a OneDrive file or folder. | |
onedrive_upload |
Upload a local file to OneDrive, replacing an existing file if needed. | |
onedrive_share |
Create a sharing link for a OneDrive item. | |
onedrive_lsfile |
List files in a OneDrive folder. | |
onedrive_lsfolder |
List subfolders in a OneDrive folder. | |
onedrive_excel |
Open a OneDrive Excel workbook session and select a worksheet. | |
onedrive_readx |
Read the used range of a OneDrive Excel worksheet. |
Password Management
| Function | Aliases | Description |
|---|---|---|
setpassword |
Store an account password in the km.py keyring service. | |
getpassword |
Read an account password from the km.py keyring service. | |
getpasswordbw |
Retrieve a Bitwarden item or selected field using its CLI. |
Keyboard and Mouse
| Function | Aliases | Description |
|---|---|---|
send |
Send keyboard keys or text with configurable delays and repetitions. | |
_mouse |
Return randomized Bezier path points between two mouse positions. | |
_move |
Move the mouse along a randomized Bezier path. | |
moveclick |
Move to a point or randomized area location, then click the left mouse button. | |
click |
Click the left mouse button the requested number of times. | |
rclick |
Click the right mouse button the requested number of times. | |
scroll |
Scroll the mouse by the supplied horizontal and vertical amounts. | |
position |
Return the current mouse position. | |
size |
Return the available display monitor bounds. |
Dropbox
| Function | Aliases | Description |
|---|---|---|
dropbox_spaceusage |
Return available, used, and total Dropbox space in gigabytes. | |
upload |
Upload a local file to Dropbox. | |
download |
Download a Dropbox file to a local path. | |
_files_list_folder_all |
List all Dropbox entries in a folder, following continuation cursors. | |
lsfile |
List Dropbox files in a folder, optionally recursively. | |
lsfolder |
List Dropbox subfolders, optionally recursively. | |
delfilefolder |
Delete a Dropbox file or folder. |
Google Drive
| Function | Aliases | Description |
|---|---|---|
_gdrive_save_private |
Atomically save private Google credentials with owner-only permissions. | |
_gdrive_authenticate |
Return an authorized v3 service, caching credentials beside the package. | |
_gdrive_query_literal |
Quote a Drive query literal without treating names as query syntax. | |
_gdrive_list_files |
Collect all Drive result pages in server order. | |
_gdrive_parent_changes |
Translate a Drive destination into v3 parent update parameters. | |
gauth |
Authenticate to Google Drive and return the native Drive API v3 service. | |
gdownload |
Export or download a Google Drive file. | |
gupload |
Upload a file to Google Drive, updating the first matching title if present. | |
gdelete |
Permanently delete a Drive file by its ID or name. | |
gcopy |
Copy a Google Drive file. | |
gmove |
Move a Google Drive file to another folder. | |
gls |
List non-trashed files and folders in a Google Drive folder. | |
gfileid |
Return the Drive file ID for the first file matching filename in folderid. |
Images and PDF Annotations
| Function | Aliases | Description |
|---|---|---|
gif |
Create an animated GIF from image files. | |
pdf2gif |
Create an animated GIF from cropped PDF pages. | |
pdfannot |
Extract PDF highlights and annotations into Markdown. |
Usage Details
Installing Packages
import ez
ez.require("gTTS", confirm=False, quiet=True)
ez.require("ffmpeg", confirm=False, channel="conda", quiet=True)
quiet=True hides routine helper and installer output; confirmation prompts and
errors remain visible, including captured installer output on failure. The
default quiet=False preserves live output. Use confirm=False to skip prompts.
Documents to Markdown
import ez
markdown = ez.pptx2md('talk.pptx') # prints to stdout and returns the Markdown
markdown = ez.pptx2md(
'talk.pptx', note=True, slides='1-3,5', markers=False,
images=True, output='talk.md', overwrite=True,
)
All four converters return the Markdown string and print it when output=None.
With output='file.md', they write UTF-8 instead of printing. Existing output files
raise FileExistsError unless overwrite=True; replacing the input document is
always rejected, including symlink/hard-link aliases.
PowerPoint
| Argument (default) | CLI flag | Effect |
|---|---|---|
note=False |
-n, --note |
Include speaker notes. |
slides=None |
-s, --slides |
Select 1-based slides, e.g. 1-3,5; default is all slides. |
markers=True |
--no-markers |
Remove <!-- Slide number: N --> comments and separate slides with ---. |
images=False |
--images |
Embed images as base64 data URIs instead of filename references. |
output=None |
-o, --output |
Write UTF-8 Markdown to a file instead of stdout. |
overwrite=False |
-f, --force |
Allow replacing an existing output file. |
Selections retain presentation order, ignore duplicates, and preserve original
slide numbers. Invalid or out-of-range selections raise ValueError. Existing
output files raise FileExistsError unless overwriting is enabled. The input
presentation is never overwritten. Filename image references do not extract
image files; use images=True for self-contained Markdown.
pptx2md talk.pptx -n -s 1-3,5 --images -o talk.md
pptx2md --help
Word
markdown = ez.docx2md('report.docx', images=True, output='report.md')
images=False is the default. Use --images to preserve complete base64 image
URIs; otherwise MarkItDown abbreviates them into unusable image references.
Supported headings, lists, tables, and links are converted, not exact page layout.
docx2md report.docx --images -o report.md
Excel
markdown = ez.xlsx2md(
'data.xlsx', sheets=['Annual Sales', 'Summary'], formulas=False,
headers=True, output='data.md',
)
| Argument (default) | CLI flag | Effect |
|---|---|---|
sheets=None |
-s, --sheets NAME [NAME ...] |
Select exact worksheet names; default is all worksheets, including hidden ones. |
formulas=False |
--formulas |
Emit formula strings instead of cached values. |
headers=True |
--no-headers |
Generate column-letter headers and include the first row as data. |
Selections retain workbook order and ignore duplicates; unknown names raise
ValueError. Each worksheet has a heading and a Markdown table; empty worksheets
have only a heading. Trailing empty rows/columns are omitted. Images, charts,
styles, and macros are not extracted; merged cells are not expanded.
Formulas are not evaluated. Missing cached formula values produce a warning
and empty cells. Calculate and save the workbook in Excel/LibreOffice first, or
use formulas=True to emit the formulas themselves.
xlsx2md data.xlsx --sheets "Annual Sales" Summary -o data.md
xlsx2md data.xlsx --formulas --no-headers
markdown = ez.pdf2md('paper.pdf', pages='1-3,5', markers=False, output='paper.md')
| Argument (default) | CLI flag | Effect |
|---|---|---|
pages=None |
-p, --pages |
Select 1-based page ranges; default is all pages. |
markers=True |
--no-markers |
Remove <!-- Page number: N --> comments and separate pages with ---. |
Selections retain document order and original page numbers. This is text-based extraction, not OCR: scanned/blank pages can have no text. Images are not extracted; exact layout/table reconstruction is not guaranteed. Decrypt PDFs requiring a password before conversion.
pdf2md paper.pdf -p 1-3,5 -o paper.md
Batch conversion
The installed commands accept multiple files, folders, and wildcard patterns. Each Python converter still processes one file per call.
pptx2md *.pptx --output-dir markdown --images
docx2md first.docx second.docx --output-dir markdown
pdf2md reports --recursive --output-dir markdown
pdf2md "reports/**/*.pdf" --recursive --output-dir markdown
xlsx2md workbooks --output-dir markdown --sheets Summary
- More than one distinct input requires
--output-dir DIR;-o FILEis only for one input and cannot be combined with--output-dir. - A single input without
--output-dirretains the original stdout/-obehavior. - Folders are scanned for the command's file extension, case-insensitively.
Use
--recursivefor nested folders or quoted**patterns. Recursive discovery does not follow directory symlinks. - Output folders are created as needed. Structure is preserved relative to the
common ancestor of input roots: a folder's root is itself, an explicit file's
root is its parent, and a wildcard's root is its non-wildcard directory prefix.
For example,
pdf2md reports --recursive --output-dir markdownmapsreports/a/report.pdftomarkdown/a/report.md. Explicit inputsa/report.pdf b/report.pdfmap tomarkdown/a/report.mdandmarkdown/b/report.md, rather than overwriting one another. - Repeated files and file aliases are converted once. Outputs colliding with
another destination or any source document are rejected, even with
--force. - All conversion options apply to every input. Discovery/conversion/output failures are reported to stderr while other files continue. A final summary reports succeeded/failed counts; any failure produces a nonzero exit status. Unmatched patterns and folders with no matching files are errors, not silent successes. Unexpected programming errors remain visible.
--forceallows replacing existing output files; otherwise they are reported as failures. Batch Markdown goes to files, not stdout.
Installed commands and future CLI tools
Install this version of the package to generate all four commands:
python -m pip install .
# Or, for local development:
python -m pip install -e .
Activate the Python environment containing ez, or put its executable directory
on PATH. All commands support -o/--output, -f/--force, and -h/--help.
Running any converter command without arguments shows help and exits successfully.
Importing or directly running ez/ez.py does not launch a converter CLI.
_CLI_COMMANDS in ez/ez.py is the single registry of exported tools. To expose
another tool, add its function and a registry entry with function, description,
arguments, notes, and examples; optional groups reuse argument groups.
Each argument is a pair of flag/name strings and an argparse-options dictionary.
Use the strings "str", "int", or "float" for typed arguments. Unspecified
options are omitted from the function call, preserving the function's defaults.
Command names may differ from function names; registered targets must accept the
parsed arguments as keywords. The dispatcher ignores normal return values and
exits successfully after a successful call.
Batch support is opt-in: the converter entries also specify batch metadata
(input parameter, supported extension, and expected document errors) and
use the shared batch argument group. Tools without this metadata retain normal
single-call dispatch.
ez/prepublish.py reads the literal registry without importing
runtime dependencies and generates the marked [project.scripts] table in
pyproject.toml, targeting the general _cli dispatcher. Run
the hook and reinstall the package after adding a command. No new wrapper files or shell functions are
needed. Converter dependencies (MarkItDown, openpyxl, PyMuPDF, and python-pptx)
are already declared in the package.
Google Drive
The Drive helpers use Google's native Drive API v3 client and OAuth libraries:
file_id = ez.gfileid("book.docx", folderid)
ez.gdownload(file_id, "/tmp/book.docx") # download the existing file; no remote creation
name, uploaded_id = ez.gupload("/tmp/book.docx", folderid)
files = ez.gls(folderid) # [(name, id), ...], across all result pages
Uploaded files are downloaded unchanged. Native Google Docs/Sheets/Slides are
exported according to the destination extension supported by gdownload.
gdelete deletes permanently; gcopy copies files and gmove moves them between
folders. Upload updates the first non-trashed matching
name anywhere in Drive, rather than limiting that search to the destination folder.
ez.gauth() returns Google's native v3 service. Use ez.gdownload(file_id, path)
for downloads, or access the service directly:
service = ez.gauth()
metadata = service.files().get(fileId=file_id, fields="id,name,mimeType").execute()
ez.gauth() requires GDRIVE_KEY imported from the package's private
pysecrets.py module. It does not read or write gdrive_secrets.json.
Client settings must contain an installed/web Google OAuth client configuration.
The cached token is reused and refreshed as needed.
Authentication does not change the working directory.
When no token is cached, the call opens your browser for Google login and consent,
then saves gdrive_token.json beside the installed module after authorization
succeeds. It does not create a separate token.json. Browser authorization requires
OAuth client settings in GDRIVE_KEY. Subsequent calls reuse the token and refresh it
when expired. Malformed tokens, failed refreshes, and write errors
are reported rather than silently restarting authorization. New credential files
are written atomically with owner-only permissions; never commit or share them.
Credential cache files are excluded from built source archives and wheels.
The helper requests full Drive access for its read/write/delete
operations. The package directory must be writable for credential caching.
Existing Web application OAuth clients can be reused without creating a new client.
Browser login selects the first supported entry in the client's redirect_uris:
http://localhost:PORT/ or http://127.0.0.1:PORT/ (also supported without the
trailing slash). The host, port, and trailing slash are preserved exactly.
The selected port must be free. If no supported entry exists, add one such as
http://localhost:8080/ to the same client's authorized redirect URIs in
Google Cloud Console, then update GDRIVE_KEY to include
it. Desktop clients continue to use an automatically selected local port.
ez.GCal() similarly requires GCAL_KEY imported from pysecrets.py and passes
the settings directly to Google's OAuth flow without writing gcal_secrets.json.
It preserves the existing gcal_token.pickle cache beside the installed module,
reuses valid tokens, and saves refreshed tokens. Initial Calendar login uses
local port 8080. Neither helper changes the working directory. Existing
client-settings files are left untouched but are no longer used. Only load
Calendar pickle tokens from a trusted source.
Classes
JDict() is a custom ordered dictionary with convenient attribute access and
helper methods. Use help(JDict) for details. Moment(timezone) returns the
current datetime in a specified timezone, or a local naive datetime if omitted.
Pipe
Chain operations using a pipe-style syntax:
# Basic pipe
[1, 2, 3, 0] > ez.pipe | len | str
# Countdown example
ez.pipe | (range, -1) | reversed | ez.pipetools.foreach('{0}...') | ' '.join | '{0} boom'
General Notes
- Almost all path-related commands support
~,..,.,?, and*. The exceptions arelsandfls, which use regular expressions for filtering. - File operations target symbolic links themselves, not the underlying files they point to.
Maintaining the Function Catalog
The topic regions and function docstrings in ez/ez.py are the source
of truth for both the generated ez.__doc__ catalog and the README function
catalog. Both list the same topics, functions, aliases, and summaries.
Each module-level function belongs
to a topic region and a nested region named after the function. Keep a concise
description on the first line of its docstring; existing parameter details and
examples follow it. Keep function aliases inside the same topic. Imported
convenience functions inside topic regions are listed with their source module.
Class methods and nested functions are not cataloged.
ez/prepublish.py reads this structure using only the Python
standard library, without importing ez or its optional runtime dependencies.
It replaces only the module's __doc__ assignment and the README section between
the BEGIN GENERATED FUNCTION CATALOG and END GENERATED FUNCTION CATALOG
markers. Do not edit either generated catalog by hand; edit the source docstrings
or regions instead. Usage details outside the markers remain hand-maintained.
python ez/prepublish.py --docs-only # regenerate both catalogs; do not bump the version
python ez/prepublish.py --check-docs # exit nonzero if either catalog is stale or invalid
python ez/prepublish.py --help
Running the hook without flags, or with --docs-only, regenerates both catalogs
and the marked CLI entry points in pyproject.toml. --check-docs
checks all three generated outputs without writing. All outputs are validated
before any are written. The hook no longer increments the version; version changes
belong to the publishing workflow below. Paths are relative to the hook, not the
current working directory.
Run the focused maintenance tests with:
python -m unittest discover -s tests
Building and Publishing
Install uv for release
work. The project uses the native uv_build backend; setuptools and Twine are no
longer needed. Package identity, dependencies, and the authoritative release
version live in pyproject.toml. ez/version.py
reads that version in a source checkout or uses installed distribution metadata.
To regenerate metadata and build without publishing or bumping the version:
uv run --no-project --python '>=3.11' ez/prepublish.py --docs-only
uv build
The build produces an sdist (.tar.gz) and a py3-none-any.whl wheel. The wheel
contains pure Python and works with supported Python versions on Windows, Linux,
Intel Macs, and ARM Macs, regardless of the build machine. Dependencies still need
compatible releases for the target platform, and OS-specific features retain
their existing limitations and dependency markers.
PyPI authentication
The publishers prefer UV_PUBLISH_TOKEN. Otherwise they automatically read
~/.pypirc, using only its [pypi] section:
[pypi]
username = __token__
password = YOUR_PYPI_API_TOKEN
repository = https://upload.pypi.org/legacy/
Reuse an existing PyPI API token, preferably scoped to the ez project, or create
one in your PyPI account settings.
repository is optional but must point to the standard PyPI upload URL if set.
Protect the file with chmod 600 ~/.pypirc; never commit it or the token.
Missing, malformed, or non-token credentials stop the release before preparation.
The token is passed to uv through its process environment, not command-line
arguments or release logs.
This .pypirc support is implemented by the shared
scripts/publish.py helper, not by uv itself. Standalone
uv publish needs uv-native credentials, such as UV_PUBLISH_TOKEN.
A Finder-launched app normally does not inherit terminal exports; the .pypirc
fallback lets both entry points use the same existing credentials.
Full release
From a terminal, run:
bash publish.sh
bash publish.sh --help
The shell script can also be run directly as ./publish.sh.
Alternatively, open Publish.app in the checkout. Its
resource script contains a separate,
manually maintained copy of publish.sh, matching the original app
arrangement. It does not invoke or require the external shell script, but still
requires the checkout's publishing helper, prepublish hook, and package files.
When changing either shell script, update the other copy too; a regression test
checks their current parity. Both resolve the checkout from their own locations,
including paths with spaces.
The publisher loads ~/.bash_profile if present and checks for uv, Git, and your
existing ezupdate command/function/alias before preparing a release. It then:
- Validates credentials and the version format.
- Runs prepublish to update catalogs and CLI entry points.
- Uses
uv version --bump COMPONENT --frozen, preserving the existing numbering: patch normally (11.8.8 → 11.8.9), minor when patch is 9 (11.8.9 → 11.9.0), and major when both minor and patch are 9 (11.9.9 → 12.0.0). Minor and patch must remain single digits. uv updates the version without locking or syncing. - Builds both artifacts in a fresh temporary directory, retains them in
dist/, then deletes olderezsource archives and wheels so only the latest release's two artifacts remain. Cleanup occurs only after a successful build and copy; unrelated files and directories are not removed. It publishes only the new files withuv publish. Existing files for the new version are not overwritten. - Stages all checkout changes, commits, pushes to
origin master, then runsezupdatethree times, preserving the existing post-release workflow. - Prints the distribution version and files in
dist/, followed by the locally installedezversion and installation location fromuv pip show ez. This reports uv's selected Python environment, which may differ from the environment yourezupdatecommand upgrades. A missing package or reporting error is shown explicitly and stops the script rather than reporting success.
Errors stop subsequent steps. A failed build/upload may leave the version bumped
and artifacts in dist/; inspect the state before retrying. A partial upload or a
later Git/upgrade failure does not undo files already published to PyPI.
To retry an upload, use the exact retained artifacts and provide uv-native
authentication; do not blindly rerun the full publisher, which bumps again.
Use prepublish's check/docs-only modes, not the publisher, for documentation work.
License
Metadata
Release files for ez 11.9.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ez-11.9.5.tar.gz | 146.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ez-11.9.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 258.1 kB
Release files / ez-11.9.5.tar.gz
| Download URL | ez-11.9.5.tar.gz |
|---|---|
| Size | 146.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
88402f2b0dd307a308fd8a356c77ae63ba99a4a7b2793523da80780e79629413
|
|
BLAKE2b-256 checksum How to use checksums |
a8d3806c35c1c91f9bac103b06693c4e02fdcc1d8b0370296dd23fc8fa293c39
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / ez-11.9.5-py3-none-any.whl
| Download URL | ez-11.9.5-py3-none-any.whl |
|---|---|
| Size | 111.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e1ad1901b7a4387f21ab8abae938065113edc93371d93a13af5f1f22fbf32db1
|
|
BLAKE2b-256 checksum How to use checksums |
b5e29ab37a88607679b1c3ad7e8921f3d41d003263858d59f05fabb676b3c6ff
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|