Before we talk about Python documentation, let me show you something that will be useful even if you never write another line of Python. (We'll merge the two later.)
from IPython.display import HTML # We'll use this later
HTML(open("../include/notes.css", "r").read())
allowExceptions = True # enable to allow interruption of Jupyter "Restart"
Documentation is a necessary part of any software development process and very Pythonic.
multiple audiences:
end users
evaluators
developers
multiple destinations:
the Web
hard copy (mostly PDF)
presentations
output quality (readability, etc.)
tracking changes to the code
proprietary input file formats
compatibility
comparing and merging revisions
WYSINWYP: "What You See Is Not What You Print"
pydoc
(actually, pydoc3
)¶General idea: Put Python strings ("docstrings") at strategic places at the start of:
modules
classes
functions
methods
They appear as __doc__
attributes.
polar
Module¶Here's a module that implements polar coordinates. Recall we map $(r, \theta) \rightarrow (x, y)$ via
$$
x = r \cos{\theta} \\
y = r \sin{\theta}
$$
and we can map $(x, y)$ to a complex number $z$ via
$$
z = x + j y
$$
Here's the contents of polar.py
:
%%file polar.py
# docstring for the module
"""
The PolarPoint Class
"""
from math import cos, sin
class PolarPoint:
# docstring for the class
"""
This class represents a 2D point in polar coordinates defined
by its distance from the center of the reference system and
an angle (in radians) from the positive x-axis.
"""
def __init__(self, rho=0.0, theta=0.0):
# docstring for the constructor
"""
specifies a ``polar`` point by a `rho` (`magnitude`), its
distance from the origin, and `theta` (`argument`) its
polar angle (in radians)
"""
self.rho = rho
self.theta = theta
def rect(self):
# docstring for rect()
"""
returns rectangular (Cartesian) coords of the PolarPoint
as an (x, y) tuple
"""
return (self.rho*cos(self.theta), self.rho*sin(self.theta))
def __complex__(self):
# docstring for __complex__() (which is a ?)
"""
returns the polar point as a complex number
"""
(real, imag) = self.rect()
return complex(real, imag)
def __str__(self):
return "({}, {})".format(self.rho, self.theta)
Overwriting polar.py
from math import pi
from polar import PolarPoint
p = PolarPoint(2, pi/4)
print(' p:', p)
print(' p.rect():', p.rect())
print('complex(p):', complex(p))
p: (2, 0.7853981633974483) p.rect(): (1.4142135623730951, 1.414213562373095) complex(p): (1.4142135623730951+1.414213562373095j)
Here's what happens if you use the pydoc3
command on this module.
%%sh
pydoc3 polar
Help on module polar: NAME polar - The PolarPoint Class CLASSES builtins.object PolarPoint class PolarPoint(builtins.object) | PolarPoint(rho=0.0, theta=0.0) | | This class represents a 2D point in polar coordinates defined | by its distance from the center of the reference system and | an angle (in radians) from the positive x-axis. | | Methods defined here: | | __complex__(self) | returns the polar point as a complex number | | __init__(self, rho=0.0, theta=0.0) | specifies a ``polar`` point by a `rho` (`magnitude`), its | distance from the origin, and `theta` (`argument`) its | polar angle (in radians) | | __str__(self) | Return str(self). | | rect(self) | returns rectangular (Cartesian) coords of the PolarPoint | as an (x, y) tuple | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) FUNCTIONS cos(x, /) Return the cosine of x (measured in radians). sin(x, /) Return the sine of x (measured in radians). FILE /home/bobl/Dropbox/cpts481/u12_documenting/polar.py
Actually, pydoc3
is actually shorthand for python3 -m pydoc
. We could have just as easily entered:
%%sh
python3 -m pydoc polar
Help on module polar: NAME polar - The PolarPoint Class CLASSES builtins.object PolarPoint class PolarPoint(builtins.object) | PolarPoint(rho=0.0, theta=0.0) | | This class represents a 2D point in polar coordinates defined | by its distance from the center of the reference system and | an angle (in radians) from the positive x-axis. | | Methods defined here: | | __complex__(self) | returns the polar point as a complex number | | __init__(self, rho=0.0, theta=0.0) | specifies a ``polar`` point by a `rho` (`magnitude`), its | distance from the origin, and `theta` (`argument`) its | polar angle (in radians) | | __str__(self) | Return str(self). | | rect(self) | returns rectangular (Cartesian) coords of the PolarPoint | as an (x, y) tuple | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) FUNCTIONS cos(x, /) Return the cosine of x (measured in radians). sin(x, /) Return the sine of x (measured in radians). FILE /home/bobl/Dropbox/cpts481/u12_documenting/polar.py
(A ", /
" in a function prototype indicates that all of the
preceding arguments are "positional only": You can't pass them by keyword. This is a new feature of
Python 3.8. You can use this in your own function and method definitions.)
Or we can generate HTML output:
%%sh
pydoc3 -w polar
wrote polar.html
HTML(open("polar.html").read()) # jupyter notebook lets us insert HTML inline like this
polar | index /home/bobl/Dropbox/cpts481/u12_documenting/polar.py |
The PolarPoint Class
Classes | ||||||||||
|
Functions | ||
|
Or we can start a small HTTP server. (Do this in a shell window, not Jupyter.)
% pydoc3 -b
Note that, except for magic methods, functions and methods whose names begin with a leading underscore (e.g., _hiddenFunction()
) won't appear in the documentation. (We'll demonstrate this.)
You'll notice that the documentation included that of sin()
and cos()
, even though they weren't defined in the module. This is because we imported them into the module's namespace. If you don't want them to appear in the documentation, you can use the "_
" prefix when you import them:
from
module import
function as
_
function.
sphinx
¶Current Python documentation standard. Used for:
Here's an enhanced version of polar.py
:
# %load demos/2_sphinx_annotated_polar/polar_for_sphinx_annotated.py
"""
The ``polar`` Module
"""
from math import sin, cos, atan2, pi
__version__ = "1.0"
class Polar:
"""
specifies a 2D position or velocity in polar coordinates
This class represents a 2D position or velocity measured in polar
coordinates and defined by its `distance` (or speed) and an angle
(`bearing`) (in radians) from the positive y ('North') direction.
We follow the conventions of navigation, not mathematics, so 0
degrees is North and bearings increase in a clockwise fashion.
"""
DEGREES_TO_RADIANS = pi / 180
"multiplicative constant to convert degrees to radians"
#: multiplicative constant to convert radians to degrees
RADIANS_TO_DEGREES = 180 / pi
def __init__(self,
distance: float = 0.0 ,
bearing: float = 0.0):
"""
specifies a polar point by `distance` and `bearing`
"""
self.distance = distance
self.bearing = bearing
def rect(self) -> ('float', 'float'):
"""
returns the rectangular (Cartesian) coords as an (x, y) tuple
"""
return (self.distance*sin(self.bearing),
self.distance*cos(self.bearing))
def __add__(self, other: 'Polar') -> 'Polar':
"""
returns the result of adding two Polar
"""
(x0, y0) = self.rect()
(x1, y1) = other.rect()
dx = x1 + x0
dy = y1 + y0
mag = (dx**2 + dy**2)**0.5
return Polar(mag, atan2(dy, dx) if mag > 0 else 0)
def __repr__(self) -> str:
"""
returns a 'lossless' string representation of a PolarCoordinate
"""
return "Polar({}, {})".format(self.distance, self.bearing)
if __name__ == '__main__':
# test1: with a 3-4-5 right triangle
a = Polar(3, 0)
print(' a:', a)
b = Polar(4, pi/2)
print(' b:', b)
print('a+b:', a+b)
# test2: zero relative distance
c = Polar(2, Polar.DEGREES_TO_RADIANS * 30)
print(' c:', c)
d = Polar(2, Polar.DEGREES_TO_RADIANS * 210)
print(' d:', d)
print('c+d:', c+d)
a: Polar(3, 0) b: Polar(4, 1.5707963267948966) a+b: Polar(5.0, 0.6435011087932845) c: Polar(2, 0.5235987755982988) d: Polar(2, 3.6651914291880923) c+d: Polar(4.002966042486721e-16, 2.5535900500422257)
Additional work will be in the demonstration directories.