Command-Line Interface#

The command-line interface provides Unix-style tools for anonymizing iCalendar files from the terminal.

Installation#

Install the CLI with:

pip install icalendar-anonymizer[cli]

This installs the Click 8.3.1+ dependency and both command-line tools.

Commands#

Two commands are provided as aliases:

  • icalendar-anonymize - Full command name

  • ican - Short alias for convenience

Both commands work identically.

Basic Usage#

Anonymize a File#

Read from a file and write to another file:

icalendar-anonymize calendar.ics -o anonymized.ics
ican calendar.ics -o anonymized.ics

Write to stdout#

Omit the -o flag to write to stdout:

icalendar-anonymize calendar.ics
ican calendar.ics > anonymized.ics

Read from stdin#

Omit the input argument or use - to read from stdin:

cat calendar.ics | icalendar-anonymize > anonymized.ics
icalendar-anonymize - -o anonymized.ics

Unix-Style Piping#

Combine with other Unix tools:

# Download and anonymize
curl https://example.com/calendar.ics | ican > anonymized.ics

# Anonymize multiple files
for f in *.ics; do ican "$f" -o "anon-$f"; done

# Anonymize and compress
cat calendar.ics | ican | gzip > anonymized.ics.gz

Options Reference#

[INPUT]#

Input iCalendar file to anonymize. Optional positional argument.

  • Default: stdin (-)

  • Format: File path or - for stdin

  • Example: ican calendar.ics

-o <file>, --output <file>#

Output file for anonymized calendar.

  • Default: stdout (-)

  • Format: File path or - for stdout

  • Example: ican input.ics -o output.ics

-v, --verbose#

Show processing information on stderr. Displays input/output sources and processing steps.

  • Flag: No value required

  • Output: Messages written to stderr (not stdout)

  • Example: ican -v calendar.ics -o anonymized.ics

Example verbose output:

Reading from: calendar.ics
Parsing calendar...
Anonymizing calendar...
Writing to: anonymized.ics
Done.

Field Configuration Options#

Configure how individual fields are anonymized. Four modes: keep, remove, randomize, replace.

--summary <mode>#

Mode for SUMMARY field.

  • Choices: keep, remove, randomize, replace

  • Default: randomize

  • Example: ican --summary keep calendar.ics

--description <mode>#

Mode for DESCRIPTION field.

--location <mode>#

Mode for LOCATION field.

--comment <mode>#

Mode for COMMENT field.

--contact <mode>#

Mode for CONTACT field.

--resources <mode>#

Mode for RESOURCES field.

--categories <mode>#

Mode for CATEGORIES field.

--attendee <mode>#

Mode for ATTENDEE field.

--organizer <mode>#

Mode for ORGANIZER field.

--uid <mode>#

Mode for UID field. Note: remove mode not allowed.

  • Choices: keep, randomize, replace

  • Default: randomize

Examples:

# Keep summaries, remove locations
ican --summary keep --location remove calendar.ics

# Replace descriptions with placeholders
ican --description replace calendar.ics

# Combine multiple field modes
ican --summary keep --location remove --description replace calendar.ics
--version#

Display version information and exit.

$ ican --version
icalendar-anonymizer, version 0.1.0
--help#

Show usage information and exit.

ican --help

Examples#

Basic File Conversion#

# Anonymize a single file
ican calendar.ics -o anonymized.ics

# Verbose output shows progress
ican -v calendar.ics -o anonymized.ics

Pipeline Processing#

# Read from stdin, write to stdout
cat calendar.ics | ican > anonymized.ics

# Explicit stdin/stdout with -
ican - < calendar.ics > anonymized.ics

# Verbose output to stderr doesn't corrupt stdout
cat calendar.ics | ican -v > anonymized.ics

Batch Processing#

# Anonymize all ICS files in directory
for file in *.ics; do
    ican "$file" -o "anonymized-$file"
done

# Process files from a list
while read -r file; do
    ican "$file" -o "anon-$(basename "$file")"
done < file-list.txt

Remote Files#

# Download and anonymize
curl https://example.com/calendar.ics | ican > local-anon.ics

# With error checking
curl -f https://example.com/calendar.ics | ican -v > local-anon.ics

Combining with Other Tools#

# Anonymize and count events
ican calendar.ics | grep -c "BEGIN:VEVENT"

# Anonymize and validate
ican calendar.ics | ics-validator

# Compress anonymized output
ican calendar.ics | gzip > anonymized.ics.gz

# Keep summaries for debugging, pipe to file
ican --summary keep calendar.ics | gzip > debug-anon.ics.gz

What Gets Anonymized?#

Note

This is a quick reference. See Python API for the complete property reference table.

The CLI uses the same anonymization as the Python API:

Anonymized (hashed with SHA-256):

  • Event summaries, descriptions, locations

  • Attendee and organizer names (CN parameter)

  • Comments, categories, resources

  • UIDs (uniqueness preserved)

Preserved for bug reproduction:

  • All dates and times (DTSTART, DTEND, DUE)

  • Recurrence rules (RRULE, RDATE, EXDATE)

  • Status, priority, sequence numbers

  • Timezones (complete VTIMEZONE)

See Python API for complete property reference.

Error Handling#

The CLI provides clear error messages for common issues.

File Not Found#

$ ican nonexistent.ics
Error: Could not open 'nonexistent.ics': No such file or directory

Exit code: 2

Invalid ICS File#

$ echo "invalid content" | ican
Error: Invalid ICS file - Expected instance of <class 'icalendar.cal.Component'>

Exit code: 1

Empty Input#

$ echo "" | ican
Error: Input is empty

Exit code: 1

Permission Denied#

$ ican protected.ics -o /root/output.ics
Error: [Errno 13] Permission denied: '/root/output.ics'

Exit code: 1

Keyboard Interrupt#

$ ican large-file.ics
^C
Interrupted

Exit code: 130

Exit Codes#

The CLI follows Unix conventions for exit codes:

Code

Meaning

When Used

0

Success

Anonymization completed successfully

1

General error

Invalid ICS, empty input, I/O errors, unexpected errors

2

File error

Input file not found or cannot be opened

130

Interrupted

User pressed Ctrl+C (SIGINT)

Troubleshooting#

Command Not Found#

If you get command not found after installation:

  1. Verify the CLI extra is installed:

    pip show icalendar-anonymizer | grep cli
    
  2. Check your PATH includes pip’s script directory:

    python -m site --user-base
    
  3. Reinstall with CLI extra:

    pip install --force-reinstall icalendar-anonymizer[cli]
    
  4. Use the full Python module path:

    python -m icalendar_anonymizer.cli calendar.ics
    

Binary Mode on Windows#

The CLI automatically handles binary mode on Windows. You don’t need to worry about CRLF line endings.

If you encounter encoding issues on Windows:

# Use binary mode with PowerShell
Get-Content calendar.ics -Raw | ican > anonymized.ics

Large Files#

The CLI loads the entire file into memory. For very large files (>100MB):

  1. Monitor memory usage: Use verbose mode to track progress

    ican -v large-file.ics -o output.ics
    
  2. Process in chunks: Split large calendars before anonymizing

    # Example: Split by year, then anonymize
    grep -A 100 "DTSTART:2024" calendar.ics | ican > 2024-anon.ics
    
  3. Use the Python API: For programmatic control over memory usage

Hyphen as Filename#

To use a file literally named -:

# Use ./ prefix to treat - as a filename
ican ./- -o output.ics

Debugging#

Enable verbose mode to see processing steps:

ican -v calendar.ics -o anonymized.ics

Check the exit code after running:

ican calendar.ics
echo $?  # Unix/macOS/Linux
echo %ERRORLEVEL%  # Windows cmd
echo $LASTEXITCODE  # Windows PowerShell

Getting Help#

If you encounter issues with the CLI:

  • Use ican --help for usage information

  • Check the Issue Tracker

  • Open a new issue with: - Your command - Error message - Operating system - Python version (python --version) - Package version (ican --version)

Integration Examples#

Git Pre-Commit Hook#

Automatically anonymize calendars before committing:

#!/bin/bash
# .git/hooks/pre-commit

for file in *.ics; do
    if [ -f "$file" ]; then
        ican "$file" -o "anon-$file"
        git add "anon-$file"
    fi
done

Cron Job#

Periodically anonymize shared calendars:

# Crontab entry: Anonymize daily at 2 AM
0 2 * * * /usr/bin/ican /path/to/calendar.ics -o /path/to/anon.ics

See Also#