Did you know that some Python modules can double-up as handy command-line tools?
For example, you can run Python's webbrowser module from the command-line to open up a given URL in your default web browser:
$ python -m webbrowser https://pym.dev/p
Opening in existing browser session.
The Python standard library includes many such module-script hybrids.
Below is a complete list of every module in Python that can be run as a command-line script.
Feel free to jump right to the full list of all scripts in Python at the end.
-m worksRunning Python with the -m command-line argument tells Python to run a given Python module as if it were a Python script.
Some modules do something at import time.
For example the antigravity module will open up a web browser for an XKCD comic.
Running this module from the command-line would do the same thing as importing it:
$ python -m antigravity
This is called an "import side effect" and most modules avoid import side effects.
Fun Easter egg modules like antigravity and this are the exception.
Modules that avoid import side effects need a different mechanism to change their behavior when run as a command-line script or when imported as a module.
Python uses a __name__ variable to distinguish between importing a module and running a module as a script.
When Python runs a module as a script, it sets the module's name to the string "__main__" (normally __name__ would contain the module's actual name).
See more in defining a main function in Python.
For packages, Python also looks for a __main__.py file to run (there's one in the zipfile package for example).
This distinction between module versus script allows for some really nifty command-line tools.
The first tools we'll look at are tools that I use even when I'm not working with Python code.
These are Python's most helpful general-purpose command-line tools.
| Command | Purpose | More |
|---|---|---|
python -m http.server |
Start a simple web server | Video |
python -m webbrowser |
Launch your web browser | Docs |
python -m json.tool |
Nicely format JSON data | Docs |
python -m calendar |
Show a command-line calendar | Docs |
http.serverRunning the http.server module as a script will start a web server on port 8000 that hosts files from the current directory.
I use this all the time to preview Sphinx documentation sites (especially when using Sphinx's dirhtml option which is all about subdirectories of index.html files).
$ python -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
webbrowserRunning the webbrowser module as a script will open a given URL in your default web browser.
For example, this would open the page https://pseudorandom.name:
$ python -m webbrowser pseudorandom.name
json.toolPython's json.tool module can be run as a script to parse a JSON document and print out a version that's formatted nicely for human readability.
$ python -m json.tool /home/trey/Downloads/download.json
[
{
"title": "Python's walrus operator",
"is_premium": false,
"url": "/using-walrus-operator/"
},
{
"title": "Refactoring long boolean expressions",
"is_premium": true,
"url": "/refactoring-boolean-expressions/"
}
]
Note that in Python 3.14, you can now run python -m json instead of python -m json.tool.
calendarRunning the calendar module as a script will print a calendar of the current year by default.
It also accepts various arguments to customize its output.
Here's a calendar of just one month:
$ python -m calendar 2024 04
April 2024
Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Those 4 scripts are general-purpose tools that I find helpful on any machine. Python also includes a number of tools that are commonly available (or easily installable) on Linux and Mac machines.
Running Python on Windows?
Or running Python on a Linux/Mac machine without the ability to easily install common command-line utilities like uuid, sqlite3 and gzip?
These tools are all equivalent to command-line tools that are common on many Linux machines, though the equivalent Linux commands are usually more powerful and more user-friendly.
| Command | Purpose | More |
|---|---|---|
python3.12 -m uuid |
Like uuidgen CLI utility |
Docs |
python3.12 -m sqlite3 |
Like sqlite3 CLI utility |
Docs |
python -m zipfile |
Like zip & unzip CLI utilities |
Docs |
python -m gzip |
Like gzip & gunzip CLI utilities |
Docs |
python -m tarfile |
Like the tar CLI utility |
Docs |
python -m base64 |
Like the base64 CLI utility |
|
python -m ftplib |
Like the ftp utility |
|
python -m smtplib |
Like the sendmail utility |
|
python -m poplib |
Like using curl to read email |
|
python -m imaplib |
Like using curl to read email |
|
python -m telnetlib |
Like the telnetutility |
|
python3.13 -m random |
Random selection (a bit like shuf) |
Docs |
Note that the command-line interfaces for uuid and sqlite3 were both added in Python 3.12 and the command-line interface for random was added in Python 3.13.
I've found the sqlite3 module handy when in a Docker container that didn't have a sqlite3 program installed, but did have Python 3.12.
These tools are all handy when working with Python code.
| Command | Purpose | More |
|---|---|---|
python -m pip |
Install third-party Python packages | Docs |
python -m venv |
Create a virtual environment | Docs |
python -m pdb |
Run the Python Debugger | Docs |
python -m unittest |
Run unittest tests in a directory |
Docs |
python -m pydoc |
Show documentation for given string | Docs |
python -m doctest |
Run doctests for a given Python file | Docs |
python -m ensurepip |
Install pip if it's not installed |
Docs |
python -m idlelib |
Launch Python's IDLE graphical REPL | Docs |
python -m zipapp |
Turn Python module into runnable ZIP | Docs |
python -m compileall |
Pre-compile Python files to bytecode | Docs |
pipThe pip module can installs third-party Python packages.
venvThe venv module creates virtual environments.
pdbThe pdb module powers the Python debugger.
That's what the built-in breakpoint function starts.
Running pdb as a command-line script will set a PDB breakpoint on the first line of your program.
unittestThe unittest module can be used for writing automated tests in Python.
When running unittest as a command-line script will, all tests within the current directory will be identified and run automatically.
pydocRunning the pydoc module as a command-line script will show the documentation for a given module or object.
This is the same documentation you would see if you passed the same object name to the built-in help function.
doctestRunning doctest as a command-line script will evaluate all doctests (example code in docstrings) within a given Python file.
ensurepipThe ensurepip script is for folks who found that they've uninstalled pip and need a way to reinstall it (I did this once and it's not fun).
idlelibEver wondered how to launch Python's graphical IDLE tool from the command-line?
Run python -m idlelib.
zipappWant to bundle up a Python module into a ZIP file that can be run directly by Python?
Run python -m zipapp my_module.
compileallWant to warm up the compiled bytecode cache that Python uses to run your modules?
Run python -m compileall . to compile all Python files in the current directory to cached bytecode.
Python also includes a handful of other Python-related tools that are specifically for analyzing Python code.
If you wanted to analyze some Python code to see how it ticks, these tools can be useful.
| Command | Purpose | More |
|---|---|---|
python -m tokenize |
Break Python module into "tokens" | Docs |
python -m ast |
Show abstract syntax tree for code | Docs |
python -m dis |
Disassemble Python code to bytecode | Docs |
python -m inspect |
inspect source code of a Python object | Docs |
python -m pyclbr |
See overview of a module's objects |
You can think of the tokenize, ast, and dis modules as progressively deeper steps in the process of parsing the code in a Python module.
tokenizeThe tokenize module/script will break a Python file into a tree of "tokens":
$ python -m tokenize hello.py
0,0-0,0: ENCODING 'utf-8'
1,0-1,5: NAME 'print'
1,5-1,6: OP '('
1,6-1,19: STRING '"Hello world"'
1,19-1,20: OP ')'
1,20-1,21: NEWLINE '\n'
2,0-2,0: ENDMARKER ''
astThe ast module/script goes one step further, turning the tokens into an "abstract syntax tree":
$ python -m ast hello.py
Module(
body=[
Expr(
value=Call(
func=Name(id='print', ctx=Load()),
args=[
Constant(value='Hello world')],
keywords=[]))],
type_ignores=[])
disThe dis module/script disassembles the abstract syntax tree into Python's "bytecode":
$ python -m dis hello.py
0 0 RESUME 0
1 2 PUSH_NULL
4 LOAD_NAME 0 (print)
6 LOAD_CONST 0 ('Hello world')
8 CALL 1
16 POP_TOP
18 RETURN_CONST 1 (None)
I've used tokenize to see how Python initially parses a module.
I used the ast module along to create the undataclass tool, along with the ast script which helped me figure out how Python was parsing my file.
I've used the dis module to try confirming a claim like "comprehensions generate fewer operations than loops".
inspectThe inspect module can be used as a script to inspect the source code of a given Python object.
$ python -m inspect contextlib:redirect_stdout
class redirect_stdout(_RedirectStream):
"""Context manager for temporarily redirecting stdout to another file.
# How to send help() to stderr
with redirect_stdout(sys.stderr):
help(dir)
# How to write help() to a file
with open('help.txt', 'w') as f:
with redirect_stdout(f):
help(pow)
"""
_stream = "stdout"
Unfortunately, it only works on objects that are implemented in Python directly.
$ python -m inspect itertools:zip_longest
Can't get info for builtin modules.
Using the inspect module as a script seems helpful in theory, but I always find myself reaching for the actual code files instead.
This may be because it's often helpful to see a bit more context than just the code for an one object: seeing inherited classes, global module state, other functions/classes, and imports are often helpful.
pyclbrThe pyclbr module can be run as a script to get a quick overview of each class, method, and function in a specific Python module:
$ python -m pyclbr timeit
def reindent 81
class Timer [] 86
def __init__ 104
def print_exc 139
def timeit 166
def repeat 186
def autorange 212
def timeit 234
def repeat 240
def main 246
def callback 324
def format_time 344
That somewhat obfuscated pyclbr name stands for "Python class browser" (it was originally meant just for browsing classes and methods).
These are Python Easter Eggs that work as Python scripts.
| Command | Purpose |
|---|---|
python -m __hello__ |
Print Hello world! |
python -m this |
Display the Zen of Python (PEP 20) |
python -m antigravity |
Open XKCD 353 in a web browser |
python -m turtledemo |
See turtle module demos |
__hello__Want to implement "hello world" in Python?
It's already implemented in the __hello__ module!
$ python -m __hello__
Hello world!
thisWant to see the Zen of Python printed out in your terminal?
Either import this or run this as a script:
$ python -m this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
antigravityImporting the antigravity module in Python will open an XKCD comic on Python in your web browser (powered by the webbrowser module mentioned above).
Running antigravity as a script works too:
$ python -m antigravity
turtledemoIf you want to see a demo of different drawings you can make with Python's turtle module, run turtledemo as a script:
$ python -m turtledemo
Here are a number of other slightly advanced Python-related tools.
| Command | Purpose | More |
|---|---|---|
python -m asyncio |
Launch an asyncio-aware Python REPL | Docs |
python -m cProfile |
Profile a Python program | Docs |
python -m profile |
Profile Python program with pure Python | |
python -m pstats |
Show stats for profile/cProfile-generated file | |
python -m pickle |
Display contents of a pickle file (high-level) | Docs |
python -m pickletools |
Disassemble a pickle file (low-level) | Docs |
asyncioIf you find yourself working with async/await often in Python, you may find the asynchronous REPL handy.
$ python -m asyncio
asyncio REPL 3.12.0 (main, Nov 30 2023, 17:49:51) [GCC 11.4.0] on linux
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> await asyncio.sleep(1, result='hello')
'hello'
cProfile & pstatsThe cProfile script will profile your code by noting how long your code spent on various operations and within various functions.
$ python -m cProfile -s tottime -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
^C
Keyboard interrupt received, exiting.
41242 function calls (40547 primitive calls) in 1.111 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
3 1.075 0.358 1.075 0.358 {method 'poll' of 'select.poll' objects}
46 0.004 0.000 0.004 0.000 {built-in method marshal.loads}
213/211 0.003 0.000 0.005 0.000 {built-in method builtins.__build_class__}
16 0.002 0.000 0.002 0.000 {built-in method _imp.create_dynamic}
... [Over 750 more lines of output]
The pstat command can process and compute statistics on the output of a profile file that's generated by cProfile.
The profile script is equivalent to the cProfile script, but it's written entirely in Python and is slower, so cProfile is preferable over profile.
pickle & pickletoolsHave a pickle file and want to see what's in it?
Running the pickle module as a script will show the unpickled data:
$ python -m pickle data.pickle
{'color': 'purple', 'name': 'duck'}
Running the pickletools module as a script will show a detailed explanation of each piece of the pickled data:
$ python -m pickletools data.pickle
0: \x80 PROTO 4
2: \x95 FRAME 36
11: } EMPTY_DICT
12: \x94 MEMOIZE (as 0)
13: ( MARK
14: \x8c SHORT_BINUNICODE 'name'
20: \x94 MEMOIZE (as 1)
21: \x8c SHORT_BINUNICODE 'duck'
27: \x94 MEMOIZE (as 2)
28: \x8c SHORT_BINUNICODE 'color'
35: \x94 MEMOIZE (as 3)
36: \x8c SHORT_BINUNICODE 'purple'
44: \x94 MEMOIZE (as 4)
45: u SETITEMS (MARK at 13)
46: . STOP
highest protocol among opcodes = 4
Here are even more Python-related tools which are oddly meta.
| Command | Purpose |
|---|---|
python -m code |
Run a Python REPL |
python -m runpy |
Run a Python module as a script |
codeThe code module is used for making interactive Python interpreters, so running it will basically run a version of the interactive Python REPL:
$ python -m code
Python 3.12.0 (main, Nov 30 2023, 17:49:51) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
runpyThe runpy module is used for dynamically running a given Python module by its name.
The fact that it has a command-line interface is a bit odd, since it essentially does what Python already does for us!
Here's runpy running runpy running runpy running the unittest module:
$ python -m runpy runpy runpy unittest
----------------------------------------------------------------------
Ran 0 tests in 0.000s
NO TESTS RAN
The remaining tools are ones that are unlikely to be useful often.
| Command | Purpose |
|---|---|
python -m timeit |
Time a Python expression |
python -m site |
See "site" information about Python |
python -m sysconfig |
Show Python configuration details |
python -m platform |
Display current platform information |
python -m mimetypes |
Show file mimetype/extension details |
python -m quopri |
Encode/decode raw email data |
python -m filecmp |
Compare contents of 2 directories |
python -m encodings.rot_13 |
ROT-13 encode/decode text |
python -m tabnanny |
Check Python file for mixed tabs & spaces |
timeitIf you need time how long a single Python expression takes to run, you could use timeit as a script:
$ python -m timeit 'sum([list(range(1000))] * 50, [])'
100 loops, best of 5: 2.2 msec per loop
$ python -m timeit 'import itertools; itertools.chain.from_iterable([list(range(1000))] * 50)'
20000 loops, best of 5: 10.5 usec per loop
You may find it surprising that I include timeit in the list of rarely useful tools.
I actually find the timeit module very useful, but I find that I pretty much always need to use it as a module rather than a script.
More on using timeit in the documentation.
siteRunning the site module as a script will show a bit of information about your current Python environment, including sys.path (which shows the directories in your PYTHONPATH).
$ python -m site
sys.path = [
'/home/trey/repos/business/screencasts',
'/home/trey/.pyenv/versions/3.12.0/lib/python312.zip',
'/home/trey/.pyenv/versions/3.12.0/lib/python3.12',
'/home/trey/.pyenv/versions/3.12.0/lib/python3.12/lib-dynload',
'/home/trey/.local/lib/python3.12/site-packages',
'/home/trey/.pyenv/versions/3.12.0/lib/python3.12/site-packages',
]
USER_BASE: '/home/trey/.local' (exists)
USER_SITE: '/home/trey/.local/lib/python3.12/site-packages' (exists)
ENABLE_USER_SITE: True
The --user-base or --user-site arguments can be passed to the site script to see just the location of those two directories:
$ python -m site --user-base
/home/trey/.local
$ python -m site --user-site
/home/trey/.local/lib/python3.12/site-packages
sysconfigRunning the sysconfig module as a script will show a huge amount of information about your Python installation.
$ python3.12 -m sysconfig | less
Platform: "linux-x86_64"
Python version: "3.12"
Current installation scheme: "posix_prefix"
Paths:
data = "/home/trey/.pyenv/versions/3.12.0"
include = "/home/trey/.pyenv/versions/3.12.0/include/python3.12"
platinclude = "/home/trey/.pyenv/versions/3.12.0/include/python3.12"
platlib = "/home/trey/.pyenv/versions/3.12.0/lib/python3.12/site-packages"
platstdlib = "/home/trey/.pyenv/versions/3.12.0/lib/python3.12"
purelib = "/home/trey/.pyenv/versions/3.12.0/lib/python3.12/site-packages"
scripts = "/home/trey/.pyenv/versions/3.12.0/bin"
stdlib = "/home/trey/.pyenv/versions/3.12.0/lib/python3.12"
Variables:
ABIFLAGS = ""
AC_APPLE_UNIVERSAL_BUILD = "0"
... [Over 1000 more lines of output]
platformThe platform script will tell you information about your operating system kernel:
$ python -m platform
Linux-6.5.0-1023-oem-x86_64-with-glibc2.35
mimetypesYou can use mimetypes to find the file extension for a given file type:
$ python -m mimetypes -e 'text/markdown'
.md
Or you can use mimetypes to discover the type of a given file:
$ python -m mimetypes README.md
type: text/markdown encoding: None
quopriThe quopri command encode/decode quoted-printable data for raw email data:
$ echo 'Hi! 👋' | python -m quopri
Hi! =F0=9F=91=8B
filecmpThe filecmp script accepts two directories and notes which files are different or the same between them.
It has a very primitive command-line interface.
$ python -m filecmp dir1 dir2
diff dir1 dir2
Only in dir1 : ['c', 'sub2']
Only in dir2 : ['d', 'sub3']
Identical files : ['a']
Differing files : ['b']
Common subdirectories : ['sub1']
It's similar to the command-line diff utility but it only works on directories and its output is less readable.
encodings.rot_13Need to ROT-13 encode/decode some text? Probably not. But Python has a command-line tool for that.
$ echo 'Hello!' | python -m encodings.rot_13
Uryyb!
$ echo 'Uryyb!' | python -m encodings.rot_13
Hello!
tabnannyNeed to check whether a Python file mixes tabs and spaces? Hopefully not!
$ python -m tabnanny example.py
example.py 3 "\tprint('Hi')"
This used to be legal syntax in Python 2, but in Python 3 it's not valid anymore, so a SyntaxError will usually tell you something is wrong without needing to deliberately check.
Here's a quick summary of every command-line tool in Python:
| Module/Script | Purpose | Category |
|---|---|---|
http.server |
Start a simple web server | General |
webbrowser |
Launch your web browser | General |
json.tool |
Nicely format JSON data | General |
calendar |
Show a command-line calendar | General |
uuid |
Like uuidgen CLI utility |
Linux-like |
sqlite3 |
Like sqlite3 CLI utility |
Linux-like |
zipfile |
Like zip & unzip CLI utilities |
Linux-like |
gzip |
Like gzip & gunzip CLI utilities |
Linux-like |
tarfile |
Like the tar CLI utility |
Linux-like |
base64 |
Like the base64 CLI utility |
Linux-like |
ftplib |
Like the ftp utility |
Linux-like |
smtplib |
Like the sendmail utility |
Linux-like |
poplib |
Like using curl to read email |
Linux-like |
imaplib |
Like using curl to read email |
Linux-like |
telnetlib |
Like the telnetutility |
Linux-like |
pip |
Install third-party Python packages | Python |
venv |
Create a virtual environment | Python |
pdb |
Run the Python Debugger | Python |
unittest |
Run unittest tests in a directory |
Python |
pydoc |
Show documentation for given string | Python |
doctest |
Run doctests for a given Python file | Python |
ensurepip |
Install pip if it's not installed |
Python |
idlelib |
Launch Python's IDLE graphical REPL | Python |
zipapp |
Turn Python module into runnable ZIP | Python |
python -m compileall |
Pre-compile Python files to bytecode | Python |
tokenize |
Break Python module into "tokens" | Inspect code |
ast |
Show abstract syntax tree for code | Inspect code |
dis |
Disassemble Python code to bytecode | Inspect code |
inspect |
inspect source code of a Python object | Inspect code |
pyclbr |
See overview of a module's objects | Inspect code |
asyncio |
Launch an asyncio-aware REPL | Deep Python |
cProfile |
Profile a Python program | Deep Python |
profile |
Profile Python program with Python | Deep Python |
pstats |
Show stats on cProfile-generated file | Deep Python |
pickle |
Readably display pickle file contents | Deep Python |
pickletools |
Disassemble a pickle file | Deep Python |
tabnanny |
Check file for mixed tabs & spaces | Deep Python |
this |
Display the Zen of Python (PEP 20) | Fun |
__hello__ |
Print Hello world! |
Fun |
antigravity |
Open XKCD 353 in a web browser | Fun |
turtledemo |
See turtle module demos |
Fun |
code |
Run a Python REPL | Python |
runpy |
Run a Python module as a script | Python |
timeit |
Time a Python expression | Python |
site |
See "site" information about Python | Deep Python |
sysconfig |
Show Python configuration details | Deep Python |
platform |
Display current platform information | General |
mimetypes |
Show file mimetype/extension details | General |
quopri |
Encode/decode raw email data | General |
filecmp |
Compare contents of 2 directories | General |
encodings.rot_13 |
ROT-13 encode/decode text | General |
I discovered the command-line interface for many of these modules by using this script, which looks for command-line interfaces among all Python standard library modules.
Note that older versions included even more modules that could be run as scripts.
The standard library also included scripts for a uu module before Python 3.12 and formatter, binhex, test.pystone, and hotshot.stones existed in Python 2.
These are just the Python scripts included in the Python standard library.
Any third-party module that can be run as a script can also be launched via python -m MODULE_NAME as well.
Need to fill-in gaps in your Python skills?
Sign up for my Python newsletter where I share one of my favorite Python tips every week.
Need to fill-in gaps in your Python skills? I send weekly emails designed to do just that.
Sign in to your Python Morsels account to track your progress.
Don't have an account yet? Sign up here.