*.pyx: Add some rather laconic docstrings.
authorMark Wooding <mdw@distorted.org.uk>
Fri, 28 Jul 2017 23:57:03 +0000 (00:57 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Wed, 16 Aug 2017 03:31:32 +0000 (04:31 +0100)
25 files changed:
atom.pyx
bres.pyx
codec.pyx
codec.pyx.in
conn.pyx
crc32.pyx
fdutils.pyx
fwatch.pyx
ident.pyx
lbuf.pyx
mapping.pyx
mdup.pyx
pkbuf.pyx
report.pyx
sel-base.pyx
sel-file.pyx
sel-timer.pyx
selbuf.pyx
selpk.pyx
sig.pyx
str.pyx
stuff.pyx
sym.pyx
unihash.pyx
url.pyx

index cee88b9..5c63722 100644 (file)
--- a/atom.pyx
+++ b/atom.pyx
@@ -37,6 +37,7 @@ cdef class AtomIter:
     return me
 
 def atoms():
+  """atoms() -> ITER: return iterator over known atoms"""
   return AtomIter()
 
 ###----- That's all, folks --------------------------------------------------
index cd2d16c..8097855 100644 (file)
--- a/bres.pyx
+++ b/bres.pyx
@@ -24,6 +24,7 @@
 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 cdef class SelResolve:
+  """Abstract superclass for background name resolution."""
   cdef bres_client r
   cdef int _activep
   cdef _resolved
@@ -35,9 +36,11 @@ cdef class SelResolve:
       me._dead()
       bres_abort(&me.r)
   property activep:
+    """BR.activep: is lookup still waiting?"""
     def __get__(me):
       return _tobool(me._activep)
   def kill(me):
+    """BR.kill(): cancel in-progress lookup"""
     if not me._activep:
       raise ValueError, 'already dead'
     me._dead()
@@ -47,8 +50,10 @@ cdef class SelResolve:
     me._activep = 0
     me.dead()
   def dead(me):
+    """BR.dead(): called when lookup completes or is cancelled"""
     pass
   property resolvedproc:
+    """BR.resolvedproc -> FUNC: call FUNC(NAME, ALIASES, ADDRS) when ok"""
     def __get__(me):
       return me._resolved
     def __set__(me, proc):
@@ -56,6 +61,7 @@ cdef class SelResolve:
     def __del__(me):
       me._resolved = None
   property failedproc:
+    """BR.failedproc -> FUNC: call FUNC() when lookup fails"""
     def __get__(me):
       return me._failed
     def __set__(me, proc):
@@ -63,11 +69,21 @@ cdef class SelResolve:
     def __del__(me):
       me._failed = None
   def resolved(me, name, aliases, addrs):
+    """BR.resolved(NAME, ALIASES, ADDRS): called when lookup completes"""
     return _maybecall(me._resolved, (name, aliases, addrs))
   def failed(me):
+    """BR.failed(): called when lookup fails"""
     return _maybecall(me._failed, ())
 
 cdef class SelResolveByName (SelResolve):
+  """
+  Resolve a hostname to an IP address, asynchronously.
+
+  SelResolveByName(NAME, [resolvedproc = None], [failedproc = None])
+
+  Calls RESOLVEDPROC(NAME, ALIASES, ADDRS) on success, or FAILEDPROC() on
+  failure.
+  """
   def __cinit__(me, char *name, resolvedproc = None, failedproc = None,
               *hunoz, **hukairz):
     me._resolved = _checkcallable(resolvedproc, 'resolved proc')
@@ -78,6 +94,14 @@ cdef class SelResolveByName (SelResolve):
     pass
 
 cdef class SelResolveByAddr (SelResolve):
+  """
+  Resolve an IPv4 address to a hostname, asynchronously.
+
+  SelResolveByAddr(ADDR, [resolvedproc = None], [failedproc = None])
+
+  Calls RESOLVEDPROC(NAME, ALIASES, ADDRS) on success, or FAILEDPROC() on
+  failure.
+  """
   def __cinit__(me, char *addr, resolvedproc = None, failedproc = None,
               *hunoz, **hukairz):
     cdef in_addr ia
index b9f910f..1274afd 100644 (file)
--- a/codec.pyx
+++ b/codec.pyx
@@ -81,6 +81,11 @@ class CDCERR:
   INVZPAD = CDCERR_INVZPAD
 
 class CodecError (Exception):
+  """
+  Exception from decoding operation.
+
+  Attributes: err = CDCERR.* code, msg = message string
+  """
   def __init__(me, err):
     me.err = err
     me.msg = _codec_strerror(err)
@@ -88,6 +93,7 @@ class CodecError (Exception):
     return me.msg
 
 def codec_strerror(err):
+  """codec_strerror(ERR) -> STR: message for CDCERR.* code"""
   return _codec_strerror(err)
 
 cdef int code(codec *c, void *p, size_t len, dstr *d) except -1:
@@ -98,6 +104,7 @@ cdef int code(codec *c, void *p, size_t len, dstr *d) except -1:
   return 0
 
 cdef class _BaseCodec:
+  """Abstract superclass for codecs."""
   cdef codec *c
   def __cinit__(me, *hunoz, **hukairz):
     me.c = NULL
@@ -125,14 +132,17 @@ cdef class _BaseCodec:
     finally:
       dstr_destroy(&d)
   def done(me):
+    """C.done() -> OUT: final output"""
     me.code('', True)
 
 cdef class _BaseEncoder (_BaseCodec):
   def encode(me, text, finishp = False):
+    """C.encode(IN, [finishp = False]) -> OUT: continue/finish encoding"""
     return me.code(text, finishp)
 
 cdef class _BaseDecoder (_BaseCodec):
   def decode(me, text, finishp = False):
+    """C.decode(IN, [finishp = False]) -> OUT: continue/finish decoding"""
     return me.code(text, finishp)
 
 ###--------------------------------------------------------------------------
@@ -144,26 +154,60 @@ cdef extern from 'mLib/base64.h':
   codec_class base64url_class
 
 cdef class Base64Encoder (_BaseEncoder):
+  """
+  Base64Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+
+  Base64 encoder.
+  """
   def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
     me.c = base64_class.encoder(flags, indent, maxline)
 
 cdef class Base64Decoder (_BaseDecoder):
+  """
+  Base64Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+
+  Base64 decoder.
+  """
   def __init__(me, flags = CDCF_IGNJUNK):
     me.c = base64_class.decoder(flags)
 
 cdef class File64Encoder (_BaseEncoder):
+  """
+  File64Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+
+  Base64 encoder, using `%' instead of `/', so encoded strings are safe as
+  filenames.
+  """
   def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
     me.c = file64_class.encoder(flags, indent, maxline)
 
 cdef class File64Decoder (_BaseDecoder):
+  """
+  File64Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+
+  Base64 encoder, using `%' instead of `/', so encoded strings are safe as
+  filenames.
+  """
   def __init__(me, flags = CDCF_IGNJUNK):
     me.c = file64_class.decoder(flags)
 
 cdef class Base64URLEncoder (_BaseEncoder):
+  """
+  Base64URLEncoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+
+  Base64 encoder, using `-' and `_' instead of `+' and `/', so encoded
+  strings are safe as URL components.
+  """
   def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
     me.c = base64url_class.encoder(flags, indent, maxline)
 
 cdef class Base64URLDecoder (_BaseDecoder):
+  """
+  Base64URLDecoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+
+  Base64 decoder, using `-' and `_' instead of `+' and `/', so encoded
+  strings are safe as URL components.
+  """
   def __init__(me, flags = CDCF_IGNJUNK):
     me.c = base64url_class.decoder(flags)
 
@@ -175,18 +219,40 @@ cdef extern from 'mLib/base32.h':
   codec_class base32hex_class
 
 cdef class Base32Encoder (_BaseEncoder):
+  """
+  Base32Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+
+  Base32 encoder.
+  """
   def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
     me.c = base32_class.encoder(flags, indent, maxline)
 
 cdef class Base32Decoder (_BaseDecoder):
+  """
+  Base32Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+
+  Base32 decoder.
+  """
   def __init__(me, flags = CDCF_IGNJUNK):
     me.c = base32_class.decoder(flags)
 
 cdef class Base32HexEncoder (_BaseEncoder):
+  """
+  Base32Encoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+
+  Base32 encoder, using digits and letters in ascending order, rather than
+  avoiding digits which visually resemble letters.
+  """
   def __init__(me, indent = '\n', maxline = 72, flags = CDCF_IGNJUNK):
     me.c = base32hex_class.encoder(flags, indent, maxline)
 
 cdef class Base32HexDecoder (_BaseDecoder):
+  """
+  Base32Decoder([indent = '\\n'], [maxline = 72], [flags = CDCF.IGNJUNK])
+
+  Base32 decoder, using digits and letters in ascending order, rather than
+  avoiding digits which visually resemble letters.
+  """
   def __init__(me, flags = CDCF_IGNJUNK):
     me.c = base32hex_class.decoder(flags)
 
@@ -197,11 +263,23 @@ cdef extern from 'mLib/hex.h':
   codec_class hex_class
 
 cdef class HexEncoder (_BaseEncoder):
+  """
+  HexEncoder([indent = '\\n'], [maxline = 72],
+             [flags = CDCF.IGNJUNK | CDCF.LOWERC])
+
+  Hexadecimal encoder.
+  """
   def __init__(me, indent = '\n', maxline = 72,
                flags = CDCF_IGNJUNK | CDCF_LOWERC):
     me.c = hex_class.encoder(flags, indent, maxline)
 
 cdef class HexDecoder (_BaseDecoder):
+  """
+  HexDecoder([indent = '\\n'], [maxline = 72],
+             [flags = CDCF.IGNJUNK | CDCF.LOWERC])
+
+  Hexadecimal decoder.
+  """
   def __init__(me, flags = CDCF_IGNJUNK | CDCF_LOWERC):
     me.c = hex_class.decoder(flags)
 
index 2ea5255..3da1b83 100644 (file)
@@ -34,6 +34,11 @@ cdef extern from 'mLib/%PREFIX%.h':
                                          void *p, size_t sz, dstr *d)
 
 cdef class %CLASS%Encode:
+  """
+  %CLASS%([indent = '\\n'], [maxline = 72])
+
+  Obsolete %CLASS% encoder.
+  """
   cdef %PREFIX%_ctx ctx
   def __cinit__(me, *hunoz, **hukairz):
     _%PREFIX%_init(&me.ctx)
@@ -47,6 +52,7 @@ cdef class %CLASS%Encode:
     if me.ctx.indent:
       xfree(<void *>me.ctx.indent)
   property indent:
+    """E.indent -> INT: indent level for new lines"""
     def __get__(me):
       return me.ctx.indent
     def __set__(me, indent):
@@ -54,11 +60,13 @@ cdef class %CLASS%Encode:
         xfree(<void *>me.ctx.indent)
       me.ctx.indent = xstrdup(indent)
   property maxline:
+    """E.maxline -> INT: maximum length of line, or 0 to prevent splitting"""
     def __get__(me):
       return me.ctx.maxline
     def __set__(me, maxline):
       me.ctx.maxline = maxline
   def encode(me, text):
+    """E.encode(IN) -> OUT: continue encoding"""
     cdef void *p
     cdef Py_ssize_t len
     cdef dstr d
@@ -71,6 +79,7 @@ cdef class %CLASS%Encode:
       dstr_destroy(&d)
     return rc
   def done(me):
+    """E.done() -> OUT: finish encoding, returning final output"""
     cdef dstr d
     DCREATE(&d)
     try:
@@ -81,15 +90,22 @@ cdef class %CLASS%Encode:
     return rc
 
 def %PREFIX%_encode(text, *arg, **kw):
+  """%PREFIX%_encode(IN, [ARGS...]) -> OUT: %CLASS%-encode the string IN"""
   e = %CLASS%Encode(*arg, **kw)
   return e.encode(text) + e.done()
 
 cdef class %CLASS%Decode:
+  """
+  %CLASS%()
+
+  Obsolete %CLASS% decoder.
+  """
   cdef %PREFIX%_ctx ctx
   def __cinit__(me, *hunoz, **hukairz):
     _%PREFIX%_init(&me.ctx)
     me.ctx.indent = NULL
   def decode(me, text):
+    """D.encode(IN) -> OUT: continue decoding"""
     cdef void *p
     cdef Py_ssize_t len
     cdef dstr d
@@ -102,6 +118,7 @@ cdef class %CLASS%Decode:
       dstr_destroy(&d)
     return rc
   def done(me):
+    """D.done() -> OUT: finish decoding, returning final output"""
     cdef dstr d
     DCREATE(&d)
     try:
@@ -112,6 +129,7 @@ cdef class %CLASS%Decode:
     return rc
 
 def %PREFIX%_decode(text, *arg, **kw):
+  """%PREFIX%_decode(IN) -> OUT: %CLASS%-decode the string IN"""
   d = %CLASS%Decode(*arg, **kw)
   return d.decode(text) + d.done()
 
index 2b3e0bc..2f5d493 100644 (file)
--- a/conn.pyx
+++ b/conn.pyx
 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 cdef class SelConnect:
+  """
+  SelConnect(SK, [connectedproc = FUNC], [errorproc = FUNC])
+
+  When socket SK connects, call CONNECTEDPROC(); if connection fails, call
+  ERRORPROC(ERRNO, MESSAGE).
+
+  Attributes: C.socket, C.activep, C.connectedproc, C.errorproc.
+  """
   cdef conn c
   cdef int _activep
   cdef readonly object socket
@@ -40,9 +48,11 @@ cdef class SelConnect:
     if me._activep:
       conn_kill(&me.c)
   property activep:
+    """C.activep -> BOOL: is connection still in progress?"""
     def __get__(me):
       return _tobool(me._activep)
   property connectedproc:
+    """C.connectedproc -> FUNC: call FUNC() when connection completes"""
     def __get__(me):
       return me._connected
     def __set__(me, proc):
@@ -50,6 +60,9 @@ cdef class SelConnect:
     def __del__(me):
       me._connected = None
   property errorproc:
+    """
+    C.errorproc -> FUNC: call FUNC(ERRNO, MSG) if connection fails
+    """
     def __get__(me):
       return me._error
     def __set__(me, proc):
@@ -57,6 +70,7 @@ cdef class SelConnect:
     def __del__(me):
       me._error = None
   def kill(me):
+    """C.kill(): give up on connection"""
     if not me._activep:
       raise ValueError, 'already dead'
     conn_kill(&me.c);
@@ -66,10 +80,13 @@ cdef class SelConnect:
     me._activep = 0
     me.dead()
   def dead(me):
+    """C.dead(): called when connection completes or fails"""
     pass
   def connected(me):
+    """C.connected(): called when connection completes successfully"""
     return _maybecall(me._connected, ())
   def error(me, errno, strerror):
+    """C.error(ERRNO, MSG): called when connection fails"""
     return _maybecall(me._error, ())
 
 cdef void _connfunc(int fd, void *arg):
index c1f3b82..f4072a0 100644 (file)
--- a/crc32.pyx
+++ b/crc32.pyx
 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 cdef class CRC32:
+  """CRC32(): calculate CRC32 of a stream"""
   cdef uint32 _a
   def __cinit__(me, *hunoz, **hukairz):
     me._a = 0
   def __init__(me):
     pass
   def chunk(me, data):
+    """C.chunk(STR): process another chunk of input"""
     cdef void *p
     cdef Py_ssize_t n
     PyObject_AsReadBuffer(data, <cvp *>&p, &n)
     me._a = c_crc32(me._a, p, n)
     return me
   def done(me):
+    """C.done() -> INT: return CRC of data"""
     return _u32(me._a)
 
 def crc32(data):
+  """crc32(STR) -> INT"""
   cdef void *p
   cdef Py_ssize_t n
   cdef uint32 c
index bb28188..55c8ca1 100644 (file)
 def fdflags(file,
             unsigned fbic = 0, unsigned fxor = 0,
             unsigned fdbic = 0, unsigned fdxor = 0):
+  """
+  fdflags(FILE, [fbic = 0], [fxor = 0], [fdbic = 0], [fdxor = 0])
+
+  Set fcntl(2) file and descriptor flags.  If these are FL and FD, then
+  update:
+
+    * FL = (FL & ~FBIC) ^ FXOR
+    * FD = (FD & ~FDBIC) ^ FDXOR
+
+  FILE may be integer file descriptor or an object with `fileno' method.
+  """
   cdef int rc
   rc = _fdflags(_getfd(fd), fbix, fxor, fdbic, fdxor)
   if rc < 0:
@@ -33,6 +44,10 @@ def fdflags(file,
   return rc
 
 def fdsend(sock, file, buffer):
+  """
+  fdsend(SOCK, FILE, BUFFER) -> RC:
+    send FILE over Unix-domain socket SOCK, along with BUFFER
+  """
   cdef void *p
   cdef Py_ssize_t len
   cdef int rc
@@ -43,6 +58,10 @@ def fdsend(sock, file, buffer):
   return rc
 
 def fdrecv(sock, unsigned size):
+  """
+  fdrecv(SOCK, SIZE) -> FD, BUFFER
+    receive file FD and BUFFER of length up to SIZE from Unix-domain SOCK
+  """
   cdef void *p
   cdef buf
   cdef Py_ssize_t len
index 2e484cd..eedb872 100644 (file)
 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 cdef class FWatch:
+  """
+  FWatch(FILE): watch FILE for changes
+
+  FILE may be a string, file descriptor, or an object with a `fileno' method.
+  """
   cdef fwatch fw
   cdef public file
   def __cinit__(me, file):
@@ -37,6 +42,7 @@ cdef class FWatch:
       fwatch_initfd(&me.fw, _getfd(file))
     me.file = file
   def update(me):
+    """FW.update() -> RC: nonzero if the file has changed state"""
     cdef int rc
     if isinstance(me.file, str):
       rc = fwatch_update(&me.fw, me.file)
index 1c2789e..9a522bd 100644 (file)
--- a/ident.pyx
+++ b/ident.pyx
@@ -41,6 +41,12 @@ cdef _inaddr_topy(sockaddr_in *sin):
   return inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)
 
 cdef class SelIdentify:
+  """
+  SelIdentify(SK, [userproc = None], [bogusproc = None],
+                  [badproc = None], [errorproc = None],)
+
+  Asynchronously enquire about remote user of socket SK.
+  """
   cdef ident_request irq
   cdef int _activep
   cdef readonly localaddr
@@ -80,9 +86,11 @@ cdef class SelIdentify:
     if me._activep:
       ident_abort(&me.irq)
   property activep:
+    """I.activep -> BOOL: query still in progress?"""
     def __get__(me):
       return _tobool(me._activep)
   property userproc:
+    """I.userproc -> FUNC: call FUNC(OS, USER) if server replied"""
     def __get__(me):
       return me._user
     def __set__(me, proc):
@@ -90,6 +98,7 @@ cdef class SelIdentify:
     def __del__(me):
       me._user = None
   property badproc:
+    """I.badproc -> FUNC: call FUNC() if server's reply was broken"""
     def __get__(me):
       return me._bad
     def __set__(me, proc):
@@ -97,6 +106,7 @@ cdef class SelIdentify:
     def __del__(me):
       me._bad = None
   property errorproc:
+    """I.errorproc -> FUNC: call FUNC(ERR) if server reported error"""
     def __get__(me):
       return me._error
     def __set__(me, proc):
@@ -104,6 +114,7 @@ cdef class SelIdentify:
     def __del__(me):
       me._error = None
   property bogusproc:
+    """I.bogusproc -> FUNC: call FUNC() on failure if no specific handler"""
     def __get__(me):
       return me._bogus
     def __set__(me, proc):
@@ -111,6 +122,7 @@ cdef class SelIdentify:
     def __del__(me):
       me._bogus = None
   def kill(me):
+    """I.kill(): cancel ident query"""
     if not me._activep:
       raise ValueError, 'already disabled'
     ident_abort(&me.irq)
@@ -119,18 +131,23 @@ cdef class SelIdentify:
     me._activep = 0
     me.dead()
   def dead(me):
+    """I.dead(): called when operation completes or fails"""
     pass
   def user(me, os, user):
+    """I.user(OS, USER): called if server returns user name"""
     return _maybecall(me._user, (os, user))
   def bad(me):
+    """I.bad(): called if server's reply is invalid"""
     if me._bad is not None:
       return me._bad()
     return me.bogus()
   def error(me, error):
+    """I.error(ERR): called if server returns an error"""
     if me._error is not None:
       return me._error(error)
     return me.bogus()
   def bogus(me):
+    """I.bogus(): called on failure if there's no more specific handler"""
     return _maybecall(me._bogus, ())
 
 cdef void _identfunc(ident_reply *i, void *arg):
index 2793e47..c5f2688 100644 (file)
--- a/lbuf.pyx
+++ b/lbuf.pyx
@@ -27,6 +27,11 @@ LBUF_CRLF = _LBUF_CRLF
 LBUF_STRICTCRLF = _LBUF_STRICTCRLF
 
 cdef class LineBuffer:
+  """
+  LineBuffer([lineproc = None], [eofproc = None])
+
+  Split an incoming stream into lines.
+  """
   cdef lbuf b
   cdef _line
   cdef _eof
@@ -37,9 +42,11 @@ cdef class LineBuffer:
   def __dealloc__(me):
     lbuf_destroy(&me.b)
   property activep:
+    """LB.activep -> BOOL: is the buffer still active?"""
     def __get__(me):
       return _tobool(me.b.f & LBUF_ENABLE)
   property delim:
+    """LB.delim -> CHAR | LBUF_...: line-end delimiter"""
     def __get__(me):
       if me.b.delim == _LBUF_CRLF or me.b.delim == _LBUF_STRICTCRLF:
         return me.b.delim
@@ -51,6 +58,7 @@ cdef class LineBuffer:
       else:
         me.b.delim = ord(d)
   property size:
+    """LB.size -> INT: buffer size limit"""
     def __get__(me):
       return me.b.sz
     def __set__(me, sz):
@@ -58,6 +66,7 @@ cdef class LineBuffer:
         raise TypeError, 'size must be positive'
       lbuf_setsize(&me.b, sz)
   property lineproc:
+    """LB.lineproc -> FUNC: call FUNC(LINE) on each line"""
     def __get__(me):
       return me._line
     def __set__(me, proc):
@@ -65,6 +74,7 @@ cdef class LineBuffer:
     def __del__(me):
       me._line = None
   property eofproc:
+    """LB.eofproc -> FUNC: call FUNC() at end-of-file"""
     def __get__(me):
       return me._eof
     def __set__(me, proc):
@@ -72,27 +82,32 @@ cdef class LineBuffer:
     def __del__(me):
       me._eof = None
   def enable(me):
+    """LB.enable(): enable the buffer, allowing lines to be emitted"""
     if me.b.f & LBUF_ENABLE:
       raise ValueError, 'already enabled'
     me.b.f = me.b.f | LBUF_ENABLE
     me.enabled()
     return me
   def disable(me):
+    """LB.disable(): disable the buffer, suspending line emission"""
     if not (me.b.f & LBUF_ENABLE):
       raise ValueError, 'already disabled'
     me.b.f = me.b.f & ~LBUF_ENABLE
     me.disabled()
     return me
   def close(me):
+    """LB.close(): report the end of the input stream"""
     if not (me.b.f & LBUF_ENABLE):
       raise ValueError, 'buffer disabled'
     lbuf_close(&me.b)
     return me
   property free:
+    """LB.free -> INT: amount of space remaining in buffer"""
     def __get__(me):
       cdef char *p
       return lbuf_free(&me.b, &p)
   def flush(me, str):
+    """LB.flush(STR) -> insert STR into the buffer and emit lines"""
     cdef Py_ssize_t len
     cdef char *p
     cdef char *q
@@ -110,12 +125,16 @@ cdef class LineBuffer:
       lbuf_flush(&me.b, q, n)
     return PyString_FromStringAndSize(p, len)
   def enabled(me):
+    """LB.enabled(): called when buffer is enabled"""
     pass
   def disabled(me):
+    """LB.disabled(): called when buffer is disabled"""
     pass
   def line(me, line):
+    """LB.line(LINE): called for each completed line"""
     return _maybecall(me._line, (line,))
   def eof(me):
+    """LB.eof(): called at end-of-file"""
     return _maybecall(me._eof, ())
 
 cdef void _lbfunc(char *s, size_t n, void *arg):
index f99de34..b044ed6 100644 (file)
@@ -55,6 +55,7 @@ cdef class Mapping:
 
   ## Bulk update
   def update(me, stuff = None, **kw):
+    """D.update([MAP], **KW): insert mappings from MAP and KW"""
     cdef unsigned f
     if stuff is None:
       pass
@@ -89,12 +90,16 @@ cdef class Mapping:
       raise KeyError, key
     me._del(e)
   def get(me, key, default = None):
+    """D.get(KEY, [default = None]) -> VALUE: value at KEY, or DEFAULT"""
     cdef void *e
     e = me._find(key, NULL)
     if not e:
       return default
     return me._value(e)
   def setdefault(me, key, default = None):
+    """
+    D.setdefault(KEY, [default = None]) -> VALUE:
+      return value at key, or store DEFAULT at key and return that"""
     cdef void *e
     cdef unsigned f
     e = me._find(key, &f)
@@ -104,6 +109,9 @@ cdef class Mapping:
       me._setval(e, default)
       return default
   def pop(me, key, default = None):
+    """
+    D.pop(KEY, [default = None]) -> VALUE:
+      return value at key or DEFAULT, and remove KEY"""
     cdef void *e
     e = me._find(key, NULL)
     if not e:
@@ -112,6 +120,7 @@ cdef class Mapping:
     me._del(e)
     return rc
   def popitem(me):
+    """D.popitem() -> KEY, VALUE: return and remove an association pair"""
     cdef _MapIterator i
     cdef void *e
     i = me._iter()
@@ -134,13 +143,17 @@ cdef class Mapping:
     return l
 
   def keys(me):
+    """D.keys() -> LIST: return a list of known keys"""
     return me._list(_map_key)
   def values(me):
+    """D.values() -> LIST: return a list of known values"""
     return me._list(_map_value)
   def items(me):
+    """D.values() -> LIST: return a list of known (KEY, VALUE) pairs"""
     return me._list(_map_item)
 
   def clear(me):
+    """D.clear(): remove all mappings"""
     cdef _MapIterator i
     cdef void *e
     i = me._iter()
@@ -155,10 +168,13 @@ cdef class Mapping:
   def __iter__(me):
     return MapKeyIter(me)
   def iterkeys(me):
+    """D.iterkeys() -> ITER: return iterator over keys"""
     return MapKeyIter(me)
   def itervalues(me):
+    """D.itervalues() -> ITER: return iterator over values"""
     return MapValueIter(me)
   def iteritems(me):
+    """D.iteritems() -> ITER: return iterator over (KEY, VALUE) pairs"""
     return MapItemIter(me)
 
 cdef class MapIterBase:
index cf3a3c0..7256211 100644 (file)
--- a/mdup.pyx
+++ b/mdup.pyx
 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 def mdup(v):
+  """
+  mdup(LIST) -> LIST:
+    LIST is a list (mutable sequence) of pairs (CUR, WANT).  Duplicate each
+    CUR file descriptor as WANT (may be -1 to mean `don't care'), closing
+    original CUR.  Works even if there are cycles.  LIST is updated in place
+    with CUR reflecting the new file descriptors even on error.  Returns the
+    same LIST on success.
+  """
   cdef mdup_fd *vv
   cdef size_t n
   cdef int i
index 2544aaa..fe296f3 100644 (file)
--- a/pkbuf.pyx
+++ b/pkbuf.pyx
 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 cdef class PacketBuffer:
+  """
+  PacketBuffer([packetproc = None], [eofproc = None])
+
+  Split an incoming stream into packets.
+  """
   cdef pkbuf pk
   cdef _packet
   cdef _eof
@@ -34,9 +39,11 @@ cdef class PacketBuffer:
   def __dealloc__(me):
     pkbuf_destroy(&me.pk)
   property activep:
+    """PK.activep -> BOOL: is the buffer still active?"""
     def __get__(me):
       return _tobool(me.pk.f & PKBUF_ENABLE)
   property want:
+    """PK.want -> INT: size of next packet to return"""
     def __get__(me):
       return me.pk.want
     def __set__(me, want):
@@ -44,6 +51,7 @@ cdef class PacketBuffer:
         raise TypeError, 'want must be positive'
       pkbuf_want(&me.pk, pk)
   property packetproc:
+    """PK.packetproc -> FUNC: call FUNC(PACKET) on each packet"""
     def __get__(me):
       return me._packet
     def __set__(me, proc):
@@ -51,6 +59,7 @@ cdef class PacketBuffer:
     def __del__(me):
       me._line = None
   property eofproc:
+    """PK.eofproc -> FUNC: call FUNC() at end-of-file"""
     def __get__(me):
       return me._eof
     def __set__(me, proc):
@@ -58,27 +67,32 @@ cdef class PacketBuffer:
     def __del__(me):
       me._eof = None
   def enable(me):
+    """PK.enable(): enable the buffer, allowing packets to be emitted"""
     if me.pk.f & PKBUF_ENABLE:
       raise ValueError, 'already enabled'
     me.pk.f = me.pk.f | PKBUF_ENABLE
     me.enabled()
     return me
   def disable(me):
+    """PK.disable(): disable the buffer, suspending packet emission"""
     if not (me.pk.f & PKBUF_ENABLE):
       raise ValueError, 'already disabled'
     me.pk.f = me.pk.f & ~PKBUF_ENABLE
     me.disabled()
     return me
   def close(me):
+    """PK.close(): report the end of the input stream"""
     if not (me.pk.f & PKBUF_ENABLE):
       raise ValueError, 'buffer disabled'
     pkbuf_close(&me.pk)
     return me
   property free:
+    """PK.free -> INT: amount of space remaining in buffer"""
     def __get__(me):
       cdef unsigned char *p
       return pkbuf_free(&me.pk, &p)
   def flush(me, str):
+    """PK.flush(STR) -> insert STR into the buffer and emit packets"""
     cdef Py_ssize_t len
     cdef unsigned char *p
     cdef unsigned char *q
@@ -96,12 +110,16 @@ cdef class PacketBuffer:
       pkbuf_flush(&me.pk, q, n)
     return PyString_FromStringAndSize(<char *>p, len)
   def enabled(me):
+    """PK.enabled(): called when buffer is enabled"""
     pass
   def disabled(me):
+    """PK.disabled(): called when buffer is disabled"""
     pass
   def packet(me, pk):
+    """PK.packet(PACKET): called for each completed packet"""
     return _maybecall(me._packet, (pk,))
   def eof(me):
+    """PK.eof(): called at end-of-file"""
     return _maybecall(me._eof, ())
 
 cdef void _pkfunc(unsigned char *p, size_t n, pkbuf *pk,
index 523dbe0..9d19ed2 100644 (file)
@@ -28,6 +28,7 @@ cdef char *_progstring
 _progstring = NULL
 
 def ego(char *prog):
+  """ego(PROG): set program name"""
   global quis, _progstring
   if _progstring:
     xfree(_progstring)
@@ -36,8 +37,10 @@ def ego(char *prog):
   quis = _quis()
 
 def moan(char *msg):
+  """moan(MSG): report a warning"""
   _moan('%s', msg)
 def die(char *msg, rc = 126):
+  """die(MSG, [rc = 126]): report a fatal error and exit"""
   _moan('%s', msg)
   raise SystemExit, rc
 
index ca1f365..64e8d08 100644 (file)
@@ -26,6 +26,7 @@
 cdef sel_state _sel
 
 def select():
+  """select(): wait for I/O and/or timeouts"""
   if sel_select(&_sel) and errno != EINTR and errno != EAGAIN:
     _oserror()
 
index f077e7c..9ff1029 100644 (file)
@@ -28,6 +28,11 @@ SEL_WRITE = _SEL_WRITE
 SEL_EXCEPT = _SEL_EXC
 
 cdef class SelFile:
+  """
+  SelFile(FILE, [mode = SEL_READ], [readyproc = None])
+
+  Register a file (or socket, or, ...) with the select loop.
+  """
   cdef sel_file f
   cdef int _activep
   cdef readonly unsigned mode
@@ -46,12 +51,15 @@ cdef class SelFile:
     if me._activep:
       sel_rmfile(&me.f)
   property fd:
+    """SF.fd -> INT: the file descriptor"""
     def __get__(me):
       return me.f.fd
   property activep:
+    """SF.activep -> BOOL: is the descriptor active?"""
     def __get__(me):
       return _tobool(me._activep)
   property readyproc:
+    """SF.readyproc -> FUNC: call FUNC() when file is ready for I/O"""
     def __get__(me):
       return me._readyfunc
     def __set__(me, proc):
@@ -59,18 +67,21 @@ cdef class SelFile:
     def __del__(me):
       me._readyfunc = None
   def enable(me):
+    """SF.enable(): enable waiting on file"""
     if me._activep:
       raise ValueError, 'already enabled'
     sel_addfile(&me.f)
     me._enabled()
     return me
   def disable(me):
+    """SF.disable(): disable waiting on file"""
     if not me._activep:
       raise ValueError, 'already disabled'
     sel_rmfile(&me.f)
     me._disabled()
     return me
   def force(me):
+    """SF.force(): artificially mark file as ready"""
     sel_force(&me.f)
     return me
   cdef _enabled(me):
@@ -80,10 +91,13 @@ cdef class SelFile:
     me._activep = 0
     me.disabled()
   def enabled(me):
+    """SF.enabled(): called when file is enabled"""
     pass
   def disabled(me):
+    """SF.disabled(): called when file is disabled"""
     pass
   def ready(me):
+    """SF.ready(): called when file is ready for I/O"""
     return _maybecall(me._readyfunc, ())
 
 cdef void _filefunc(int fd, unsigned mode, void *arg):
index ba59a7c..ebdd433 100644 (file)
@@ -32,6 +32,11 @@ cdef void _floattotv(timeval *tv, double t):
   tv.tv_usec = <int>(us * 1000000)
 
 cdef class SelTimer:
+  """
+  SelTimer(WHEN, [timerproc = None])
+
+  Arrange to perform some action at time WHEN.
+  """
   cdef sel_timer t
   cdef int _activep
   cdef readonly double time
@@ -47,9 +52,11 @@ cdef class SelTimer:
     if me._activep:
       sel_rmtimer(&me.t)
   property activep:
+    """ST.activep -> BOOL: is the timer active?"""
     def __get__(me):
       return _tobool(me._activep)
   property timerproc:
+    """ST.timerproc -> FUNC: call FUNC() when the timer pops"""
     def __get__(me):
       return me._timer
     def __set__(me, proc):
@@ -57,6 +64,7 @@ cdef class SelTimer:
     def __del__(me):
       me._timer = None
   def kill(me):
+    """ST.kill(): deactivate timer permanently"""
     if not me._activep:
       raise ValueError, 'already dead'
     sel_rmtimer(&me.t)
@@ -66,8 +74,10 @@ cdef class SelTimer:
     me._activep = 0
     me.dead()
   def dead(me):
+    """ST.dead(): called when timer is deactivated"""
     pass
   def timer(me, now):
+    """ST.timer(NOW): called when the timer pops"""
     return _maybecall(me._timer, ())
 
 cdef void _timerfunc(timeval *now, void *arg):
index 35b7cf6..53964c7 100644 (file)
 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 cdef class SelLineBuffer:
+  """
+  SelLineBuffer(FILE, [lineproc = None], [eofproc = None])
+
+  Split an asynchronous stream into lines.
+  """
   cdef selbuf b
   cdef _line
   cdef _eof
@@ -35,12 +40,15 @@ cdef class SelLineBuffer:
   def __dealloc__(me):
     selbuf_destroy(&me.b)
   property activep:
+    """SLB.activep -> BOOL: is the buffer still active?"""
     def __get__(me):
       return _tobool(me.b.b.f & LBUF_ENABLE)
   property fd:
+    """SLB.fd -> INT: the file descriptor"""
     def __get__(me):
       return me.b.reader.fd
   property delim:
+    """SLB.delim -> CHAR | LBUF_...: line-end delimiter"""
     def __get__(me):
       if me.b.b.delim == _LBUF_CRLF or me.b.b.delim == _LBUF_STRICTCRLF:
         return me.b.b.delim
@@ -52,6 +60,7 @@ cdef class SelLineBuffer:
       else:
         me.b.b.delim = ord(d)
   property size:
+    """SLB.size -> INT: buffer size limit"""
     def __get__(me):
       return me.b.b.sz
     def __set__(me, sz):
@@ -59,6 +68,7 @@ cdef class SelLineBuffer:
         raise TypeError, 'size must be positive'
       selbuf_setsize(&me.b, sz)
   property lineproc:
+    """SLB.lineproc -> FUNC: call FUNC(LINE) on each line"""
     def __get__(me):
       return me._line
     def __set__(me, proc):
@@ -66,6 +76,7 @@ cdef class SelLineBuffer:
     def __del__(me):
       me._line = None
   property eofproc:
+    """SLB.eofproc -> FUNC: call FUNC() at end-of-file"""
     def __get__(me):
       return me._eof
     def __set__(me, proc):
@@ -73,24 +84,30 @@ cdef class SelLineBuffer:
     def __del__(me):
       me._eof = None
   def enable(me):
+    """SLB.enable(): enable the buffer, allowing lines to be emitted"""
     if me.b.b.f & LBUF_ENABLE:
       raise ValueError, 'already enabled'
     selbuf_enable(&me.b)
     me.enabled()
     return me
   def disable(me):
+    """SLB.disable(): disable the buffer, suspending line emission"""
     if not (me.b.b.f & LBUF_ENABLE):
       raise ValueError, 'already disabled'
     selbuf_disable(&me.b)
     me.disabled()
     return me
   def enabled(me):
+    """SLB.enabled(): called when buffer is enabled"""
     pass
   def disabled(me):
+    """SLB.disabled(): called when buffer is disabled"""
     pass
   def line(me, line):
+    """SLB.line(LINE): called for each completed line"""
     return _maybecall(me._line, (line,))
   def eof(me):
+    """SLB.eof(): called at end-of-file"""
     return _maybecall(me._eof, ())
 
 cdef void _selbfunc(char *s, size_t n, void *arg):
index ee27302..a54ce95 100644 (file)
--- a/selpk.pyx
+++ b/selpk.pyx
 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 cdef class SelPacketBuffer:
+  """
+  SelPacketBuffer(FILE, [packetproc = None], [eofproc = None])
+
+  Split an incoming stream into packets.
+  """
   cdef selpk p
   cdef _packet
   cdef _eof
@@ -35,12 +40,15 @@ cdef class SelPacketBuffer:
   def __dealloc__(me):
     selpk_destroy(&me.p)
   property activep:
+    """SPK.activep -> BOOL: is the buffer still active?"""
     def __get__(me):
       return _to_bool(me.p.pk.f & PKBUF_ENABLE)
   property fd:
+    """SPK.fd -> INT: the file descriptor"""
     def __get__(me):
       return me.p.reader.fd
   property want:
+    """SPK.want -> INT: size of next packet to return"""
     def __get__(me):
       return me.p.pk.want
     def __set__(me, n):
@@ -48,6 +56,7 @@ cdef class SelPacketBuffer:
         raise TypeError, 'size must be positive'
       selpk_want(&me.p, n)
   property packetproc:
+    """SPK.packetproc -> FUNC: call FUNC(PACKET) on each packet"""
     def __get__(me):
       return me._packet
     def __set__(me, proc):
@@ -55,6 +64,7 @@ cdef class SelPacketBuffer:
     def __del__(me):
       me._packet = None
   property eofproc:
+    """SPK.eofproc -> FUNC: call FUNC() at end-of-file"""
     def __get__(me):
       return me._eof
     def __set__(me, proc):
@@ -62,24 +72,30 @@ cdef class SelPacketBuffer:
     def __del__(me):
       me._eof = None
   def enable(me):
+    """SPK.enable(): enable the buffer, allowing packets to be emitted"""
     if me.p.pk.f & PKBUF_ENABLE:
       raise ValueError, 'already enabled'
     selpk_enable(&me.p)
     me.enabled()
     return me
   def disable(me):
+    """SPK.disable(): disable the buffer, suspending packet emission"""
     if not (me.p.pk.f & PKBUF_ENABLE):
       raise ValueError, 'already disabled'
     selpk_disable(&me.p)
     me.disabled()
     return me
   def enabled(me):
+    """SPK.enabled(): called when buffer is enabled"""
     pass
   def disabled(me):
+    """SPK.disabled(): called when buffer is disabled"""
     pass
   def packet(me, pk):
+    """SPK.packet(PACKET): called for each completed packet"""
     return _maybecall(me._packet, (pk,))
   def eof(me):
+    """SPK.eof(): called at end-of-file"""
     return _maybecall(me._eof, ())
 
 cdef void _selpkfunc(unsigned char *p, size_t n, pkbuf *pk,
diff --git a/sig.pyx b/sig.pyx
index 17d52fe..aafa050 100644 (file)
--- a/sig.pyx
+++ b/sig.pyx
 import signal
 
 cdef class SelSignal:
+  """
+  SelSignal(SIG, [signalledproc = None])
+
+  Collect signals from the event loop.
+  """
   cdef sig s
   cdef int _activep
   cdef readonly int signal
@@ -40,9 +45,11 @@ cdef class SelSignal:
     if me._activep:
       sig_remove(&me.s)
   property activep:
+    """SS.activep -> BOOL: is the handler still active?"""
     def __get__(me):
       return _tobool(me._activep)
   property signalledproc:
+    """SS.signalledproc -> FUNC: call FUNC() when the signal is received"""
     def __get__(me):
       return me._signalled
     def __set__(me, proc):
@@ -50,12 +57,14 @@ cdef class SelSignal:
     def __del__(me):
       me._signalled = None
   def enable(me):
+    """SS.enable(): enable the handler"""
     if me._activep:
       raise ValueError, 'already enabled'
     sig_add(&me.s, me.signal, _sigfunc, <void *>me)
     me._enabled()
     return me
   def disable(me):
+    """SS.disable(): disable the handler"""
     if not me._activep:
       raise ValueError, 'already disabled'
     sig_remove(&me.s)
@@ -68,10 +77,13 @@ cdef class SelSignal:
     me._activep = 0
     me.disabled()
   def enabled(me):
+    """SS.enabled(): called when handler is enabled"""
     pass
   def disabled(me):
+    """SS.disabled(): called when handler is disabled"""
     pass
   def signalled(me):
+    """SS.signalled(): called when the signal is received"""
     return _maybecall(me._signalled, ())
 
 cdef void _sigfunc(int sig, void *arg):
diff --git a/str.pyx b/str.pyx
index 676b0ee..f1a2ee5 100644 (file)
--- a/str.pyx
+++ b/str.pyx
@@ -24,6 +24,7 @@
 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 def word(char *p, quotep = False):
+  """word(STR, [quotep = False]) -> WORD, REST"""
   cdef unsigned f
   cdef char *op
   cdef char *pp
@@ -48,6 +49,7 @@ def word(char *p, quotep = False):
   return w, r
 
 def split(char *p, int n = -1, quotep = False):
+  """split(STR, [n = -1], [quotep = False]) -> WORDS, REST"""
   cdef unsigned f
   cdef char *op
   cdef char *pp
@@ -75,6 +77,7 @@ def split(char *p, int n = -1, quotep = False):
   return l, r
 
 def match(char *p, char *s, prefixp = False):
+  """match(PAT, STR, [prefixp = False]) -> BOOL"""
   cdef unsigned f
 
   f = 0
@@ -83,6 +86,7 @@ def match(char *p, char *s, prefixp = False):
   return _tobool(str_matchx(p, s, f))
 
 def sanitize(char *p, int n = -1):
+  """sanitize(STR, [n = -1]) -> STR"""
   cdef char *buf
   cdef object d
 
@@ -95,6 +99,7 @@ def sanitize(char *p, int n = -1):
   return d
 
 def versioncmp(char *va, char *vb):
+  """versioncmp(V0, V1) -> -1 | 0 | +1"""
   return _versioncmp(va, vb)
 
 ###----- That's all, folks --------------------------------------------------
index e18e367..dcb8a9c 100644 (file)
--- a/stuff.pyx
+++ b/stuff.pyx
 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 def detachtty():
+  """detachtty(): detach from terminal and fork"""
   _detachtty()
 
 def daemonize():
+  """daemonize(): become a daemon"""
   if _daemonize():
     _oserror()
 
diff --git a/sym.pyx b/sym.pyx
index eab6984..f456db8 100644 (file)
--- a/sym.pyx
+++ b/sym.pyx
@@ -28,6 +28,11 @@ cdef struct _sym_entry:
   PyObject *v
 
 cdef class SymTable (Mapping):
+  """
+  SymTable([DICT], **KW)
+
+  A mapping keyed by strings.
+  """
   cdef sym_table _t
   cdef int _init(me) except -1:
     sym_create(&me._t)
index de6f3d4..8ededb0 100644 (file)
 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 def setglobalkey(uint32 k):
+  """setglobalkey(K): set global hash key"""
   unihash_setkey(&unihash_global, k)
 
 cdef class Key:
+  """Key(K): universal hashing key"""
   cdef unihash_info _i
   cdef uint32 _k
   def __cinit__(me, uint32 k):
     unihash_setkey(&me._i, k)
     me._k = k
   property k:
+    """K.k -> INT: the key value"""
     def __get__(me):
       return _u32(me._k)
 
 cdef class Unihash:
+  """Unihash([key = None]): universal hashing context"""
   cdef uint32 _a
   cdef readonly Key key
   cdef unihash_info *_i
@@ -50,11 +54,13 @@ cdef class Unihash:
       me._i = &k._i
     me._a = UNIHASH_INIT(me._i)
   def chunk(me, data):
+    """U.chunk(STR): hash the STR"""
     cdef void *p
     cdef Py_ssize_t n
     PyObject_AsReadBuffer(data, <cvp *>&p, &n)
     me._a = unihash_hash(me._i, me._a, p, n)
   def done(me):
+    """U.done() -> INT: the hash of the data"""
     return _u32(me._a)
 
 ###----- That's all, folks --------------------------------------------------
diff --git a/url.pyx b/url.pyx
index ef7e36c..72467f1 100644 (file)
--- a/url.pyx
+++ b/url.pyx
@@ -24,6 +24,7 @@
 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 cdef class URLEncode:
+  """URLEncode([strictp = False], [laxp = False], [semip = False])"""
   cdef url_ectx ctx
   cdef dstr d
 
@@ -41,12 +42,15 @@ cdef class URLEncode:
       f = f | URLF_SEMI
     me.ctx.f = f
   def encode(me, char *name, char *value):
+    """UE.encode(NAME, VALUE): encode a key/value pair"""
     url_enc(&me.ctx, &me.d, name, value)
     return me
   property result:
+    """UE.result -> STR: the encoded string"""
     def __get__(me):
       return PyString_FromStringAndSize(me.d.buf, me.d.len)
   property strictp:
+    """UE.strictp -> BOOL: strictly escape non-alphanumerics?"""
     def __get__(me):
       return _tobool(me.ctx.f & URLF_STRICT)
     def __set__(me, val):
@@ -55,6 +59,7 @@ cdef class URLEncode:
       else:
         me.ctx.f = me.ctx.f & ~URLF_STRICT
   property laxp:
+    """UE.laxp -> BOOL: only escape obviously unsafe characters?"""
     def __get__(me):
       return _tobool(me.ctx.f & URLF_LAX)
     def __set__(me, val):
@@ -63,6 +68,7 @@ cdef class URLEncode:
       else:
         me.ctx.f = me.ctx.f & ~URLF_LAX
   property semip:
+    """UE.semip -> BOOL: separate key/value pairs with semicolons?"""
     def __get__(me):
       return _tobool(me.ctx.f & URLF_SEMI)
     def __set__(me, val):
@@ -74,6 +80,7 @@ cdef class URLEncode:
     dstr_destroy(&me.d)
 
 cdef class URLDecode:
+  """URLDecode(STR, [semip = False]): iterator over (KEY, VALUE) pairs"""
   cdef url_dctx ctx
   cdef char *p
 
@@ -109,6 +116,7 @@ cdef class URLDecode:
       raise StopIteration
     return nn, vv
   property semip:
+    """UD.semip -> BOOL: key/value pairs separated with semicolons?"""
     def __get__(me):
       return _tobool(me.ctx.f & URLF_SEMI)
     def __set__(me, val):