renamed itoa->atoi (typo!!)

added documentation @rtype



git-svn-id: https://callirhoe.googlecode.com/svn/trunk@161 81c8bb96-aa45-f2e2-0eef-c4fa4a15c6df
This commit is contained in:
geortz@gmail.com 2014-10-21 16:45:52 +00:00
parent 97bcec2027
commit 8e0cf7ec54
9 changed files with 233 additions and 63 deletions

View File

@ -75,6 +75,7 @@ def import_plugin(plugin_paths, cat, longcat, longcat2, listopt, preset):
@param longcat2: long category name in plural form
@param listopt: option name
@param preset: default value
@rtype: module
@note: Aimed for internal use with I{lang}, I{style}, I{geom}, I{layouts}.
"""
@ -135,12 +136,13 @@ def add_list_option(parser, opt):
parser.add_option("--list-%s" % opt, action="store_true", dest="list_%s" % opt, default=False,
help="list available %s" % opt)
def itoa(s, lower_bound=None, upper_bound=None, prefix=''):
"""convert integer to string, exiting on error (for cmdline parsing)
def atoi(s, lower_bound=None, upper_bound=None, prefix=''):
"""convert string to integer, exiting on error (for cmdline parsing)
@param lower_bound: perform additional check so that value >= I{lower_bound}
@param upper_bound: perform additional check so that value <= I{upper_bound}
@param prefix: output prefix for error reporting
@rtype: int
"""
try:
k = int(s);
@ -155,31 +157,40 @@ def itoa(s, lower_bound=None, upper_bound=None, prefix=''):
return k
def _parse_month(mstr):
"""get a month value (0-12) from I{mstr}, exiting on error (for cmdline parsing)"""
m = itoa(mstr,lower_bound=0,upper_bound=12,prefix='month: ')
"""get a month value (0-12) from I{mstr}, exiting on error (for cmdline parsing)
@rtype: int
"""
m = atoi(mstr,lower_bound=0,upper_bound=12,prefix='month: ')
if m == 0: m = time.localtime()[1]
return m
def parse_month_range(s):
"""return (Month,Span) by parsing range I{Month}, I{Month1}-I{Month2} or I{Month}:I{Span}"""
"""return (Month,Span) by parsing range I{Month}, I{Month1}-I{Month2} or I{Month}:I{Span}
@rtype: (int,int)
"""
if ':' in s:
t = s.split(':')
if len(t) != 2: raise Abort("invalid month range '" + s + "'")
Month = _parse_month(t[0])
MonthSpan = itoa(t[1],lower_bound=0,prefix='month span: ')
MonthSpan = atoi(t[1],lower_bound=0,prefix='month span: ')
elif '-' in s:
t = s.split('-')
if len(t) != 2: raise Abort("invalid month range '" + s + "'")
Month = _parse_month(t[0])
MonthSpan = itoa(t[1],lower_bound=Month+1,prefix='month range: ') - Month + 1
MonthSpan = atoi(t[1],lower_bound=Month+1,prefix='month range: ') - Month + 1
else:
Month = _parse_month(s)
MonthSpan = 1
return (Month,MonthSpan)
def parse_year(ystr):
"""get a year value (>=0) from I{ystr}, exiting on error (for cmdline parsing)"""
y = itoa(ystr,lower_bound=0,prefix='year: ')
"""get a year value (>=0) from I{ystr}, exiting on error (for cmdline parsing)
@rtype: int
"""
y = atoi(ystr,lower_bound=0,prefix='year: ')
if y == 0: y = time.localtime()[0]
return y
@ -193,6 +204,8 @@ def extract_parser_args(arglist, parser, pos = -1):
if I{pos}<0 then all positional arguments are extracted, otherwise,
only I{pos} arguments are extracted. arglist[0] (usually sys.argv[0]) is also positional
argument!
@rtype: ([str,...],[str,...])
@return: tuple (argv1,argv2) with extracted argument list and remaining argument list
"""
argv = [[],[]]
@ -221,7 +234,10 @@ def extract_parser_args(arglist, parser, pos = -1):
return tuple(argv)
def get_parser():
"""get the argument parser object"""
"""get the argument parser object
@rtype: optparse.OptionParser
"""
parser = optparse.OptionParser(usage="usage: %prog [options] [[MONTH[-MONTH2|:SPAN]] YEAR] FILE",
description="High quality calendar rendering with vector graphics. "
"By default, a calendar of the current year in pdf format is written to FILE. "

View File

@ -34,14 +34,14 @@ import optparse
import Queue
import threading
from callirhoe import extract_parser_args, parse_month_range, parse_year, itoa, Abort, _version, _copyright
from callirhoe import extract_parser_args, parse_month_range, parse_year, atoi, Abort, _version, _copyright
from lib.geom import rect_rel_scale
# MAYBE-TODO
# move to python 3?
# check ImageMagick availability/version
# convert input to ImageMagick native format for faster re-access
# report error on parse-float (like itoa())
# report error on parse-float (like atoi())
# abort --range only on KeyboardInterrupt?
_prog_im = os.getenv('CALLIRHOE_IM', 'convert')
@ -54,12 +54,16 @@ def run_callirhoe(style, size, args, outfile):
@param size: tuple (I{width},I{height}) for output calendar size (in pixels)
@param args: (extra) argument list to pass to callirhoe
@param outfile: output calendar file
@return: subprocess exit code
@rtype: subprocess.Popen
@return: Popen object
"""
return subprocess.Popen(['callirhoe', '-s', style, '--paper=-%d:-%d' % size] + args + [outfile])
def _bound(x, lower, upper):
"""return the closest number to M{x} that lies in [M{lower,upper}]"""
"""return the closest number to M{x} that lies in [M{lower,upper}]
@rtype: type(x)
"""
if x < lower: return lower
if x > upper: return upper
return x
@ -111,7 +115,10 @@ class PNMImage(object):
self.xsum = [map(lambda x: self._rsum(y,x), range(w+1)) for y in range(0,h)]
def _rsum(self,y,x):
"""running sum with cache"""
"""running sum with cache
@rtype: int
"""
if self._rsum_cache[0] == y and self._rsum_cache[1] == x:
s = self._rsum_cache[2] + self.data[y][x-1]
else:
@ -120,11 +127,15 @@ class PNMImage(object):
return s
def block_avg(self, x, y, szx, szy):
"""returns the average intensity of a block of size M{(szx,szy)} at pos (top-left) M{(x,y)}"""
"""returns the average intensity of a block of size M{(szx,szy)} at pos (top-left) M{(x,y)}
@rtype: float
"""
return float(sum([(self.xsum[y][x+szx] - self.xsum[y][x]) for y in range(y,y+szy)]))/(szx*szy)
def lowest_block_avg(self, szx, szy, at_least = 0):
"""returns the M{(szx,szy)}-sized block with intensity as close to M{at_least} as possible
@rtype: (float,(float,float),(int,int),(int,int))
@return: R=tuple M({avg, (szx_ratio,szy_ratio), (x,y), (szx,szy))}: R[0] is the
average intensity of the block found, R[1] is the block size ratio with respect to the whole image,
R[2] is the block position (top-left) and R[3] is the block size
@ -154,6 +165,8 @@ class PNMImage(object):
Calendar rectangle ratio over Photo ratio. If M{r>1} then calendar rectangle, when scaled, fits
M{x} dimension first. Conversely, if M{r<1}, scaling touches the M{y} dimension first. When M{r=1},
calendar rectangle can fit perfectly within the photo at 100% size.
@rtype: (float,(float,float),(int,int),(int,int),float)
"""
w,h = self.size
sz_lo = _bound(int(w*size_range[0]+0.5),1,w)
@ -172,11 +185,14 @@ class PNMImage(object):
# we do not use at_least because we want the best possible option, for bigger sizes
cur = self.lowest_block_avg(*sz)
if cur[0] <= entropy_thres: return cur + (best[0],)
return best + (best[0],) # avg, sz_ratio, x, y, sz, best_avg
return best + (best[0],) # avg, (szx_ratio,szy_ratio), (x,y), (szx,szy), best_avg
def get_parser():
"""get the argument parser object"""
"""get the argument parser object
@rtype: optparse.OptionParser
"""
parser = optparse.OptionParser(usage="usage: %prog IMAGE [options] [callirhoe-options] [--pre-magick ...] [--in-magick ...] [--post-magick ...]",
description="""High quality photo calendar composition with automatic minimal-entropy placement.
If IMAGE is a single file, then a calendar of the current month is overlayed. If IMAGE contains wildcards,
@ -303,6 +319,7 @@ def parse_magick_args():
ImageMagick-specific arguments should be defined between arguments C{--pre-magick},
C{--in-magick}, C{--post-magick} is this order
@rtype: [[str,...],[str,...],[str,...]]
@return: 3-element list of lists containing the [pre,in,post]-options
"""
magickargs = [[],[],[]]
@ -332,13 +349,19 @@ def parse_magick_args():
return magickargs
def mktemp(ext=''):
"""get temporary file name with optional extension"""
"""get temporary file name with optional extension
@rtype: str
"""
f = tempfile.NamedTemporaryFile(suffix=ext, delete=False)
f.close()
return f.name
def get_outfile(infile, outdir, base_prefix, format, hint=None):
"""get output file name taking into account output directory, format and prefix, avoiding overwriting the input file"""
"""get output file name taking into account output directory, format and prefix, avoiding overwriting the input file
@rtype: str
"""
if hint:
outfile = hint
else:
@ -352,7 +375,10 @@ def get_outfile(infile, outdir, base_prefix, format, hint=None):
return outfile
def _IM_get_image_size(img, args):
"""extract tuple(width,height) from image file using ImageMagick"""
"""extract tuple(width,height) from image file using ImageMagick
@rtype: (int,int)
"""
info = subprocess.check_output([_prog_im, img] + args + ['-format', '%w %h', 'info:']).split()
return tuple(map(int, info))
@ -360,7 +386,10 @@ _IM_lum_args = "-colorspace Lab -channel R -separate +channel -set colorspace Gr
"""IM colorspace conversion arguments to extract image luminance"""
def _IM_get_image_luminance(img, args, geometry = None):
"""get average image luminance as a float in [0,255], using ImageMagick"""
"""get average image luminance as a float in [0,255], using ImageMagick
@rtype: float
"""
return 255.0*float(subprocess.check_output([_prog_im, img] + args +
(['-crop', '%dx%d+%d+%d' % geometry] if geometry else []) +
_IM_lum_args + ['-format', '%[fx:mean]', 'info:']))
@ -375,7 +404,10 @@ _IM_entropy_tail = "-colorspace Lab -channel R -separate +channel -set colorspac
#_IM_entropy_tail = "-colorspace Lab -channel R -separate +channel -normalize -scale".split()
def _IM_entropy_args(alt=False):
"""IM entropy computation arguments, depending on default or alternate algorithm"""
"""IM entropy computation arguments, depending on default or alternate algorithm
@rtype: [str,...]
"""
return _IM_entropy_head + _IM_entropy_alg[alt] + _IM_entropy_tail
def _entropy_placement(img, size, args, options, r):
@ -386,6 +418,7 @@ def _entropy_placement(img, size, args, options, r):
@param args: ImageMagick pre-processing argument list (see C{--pre-magick})
@param options: (command-line) options object
@param r: rectangle ratio, 0=match input ratio
@rtype: (int,int,int,int)
@return: IM geometry tuple(I{width,height,x,y})
"""
w,h = size
@ -417,6 +450,7 @@ def _manual_placement(size, options, r):
@param size: image size tuple(I{width,height})
@param options: (command-line) options object
@param r: rectangle ratio, 0=match input ratio
@rtype: (int,int,int,int)
@return: IM geometry tuple(I{width,height,x,y})
"""
w,h = size
@ -449,6 +483,7 @@ _mutex = threading.Lock()
def get_cache(num_photos, num_months):
"""returns a reference to the cache object, or None if caching is disabled
@rtype: dict
@note: caching is enabled only when more than 1/6 of photos is going to be re-used
"""
q,r = divmod(num_months, num_photos)
@ -488,7 +523,7 @@ def compose_calendar(img, outimg, options, callirhoe_args, magick_args, stats=No
if '/' in options.ratio:
tmp = options.ratio.split('/')
calratio = float(itoa(tmp[0],1))/itoa(tmp[1],1)
calratio = float(atoi(tmp[0],1))/atoi(tmp[1],1)
else:
calratio = float(options.ratio)
if options.placement == 'min' or options.placement == 'max':
@ -556,6 +591,7 @@ def parse_range(s,hint=None):
@param s: range string in format I{Month1-Month2/Year} or I{Month:Span/Year}
@param hint: span value to be used, when M{Span=0}
@rtype: [(int,int),...]
@return: list of (I{Month,Year}) tuples for every month specified
"""
if '/' in s:

View File

@ -26,6 +26,7 @@ def get_parser(layout_name):
"""get the parser object for the layout command-line arguments
@param layout_name: corresponding python module (.py file)
@rtype: optparse.OptionParser
"""
lname = layout_name.split(".")[1]
parser = optparse.OptionParser(usage="%prog (...) --layout " + lname + " [options] (...)",add_help_option=False)

View File

@ -28,7 +28,10 @@ import _base
parser = _base.get_parser(__name__)
def _weekrows_of_month(year, month):
"""returns the number of Monday-Sunday ranges (or subsets of) that a month contains, which are 4, 5 or 6"""
"""returns the number of Monday-Sunday ranges (or subsets of) that a month contains, which are 4, 5 or 6
@rtype: int
"""
day,span = calendar.monthrange(year, month)
if day == 0 and span == 28: return 4
if day == 5 and span == 31: return 6

View File

@ -33,6 +33,7 @@ def get_parser(layout_name):
"""get the parser object for the layout command-line arguments
@param layout_name: corresponding python module (.py file)
@rtype: optparse.OptionParser
"""
lname = layout_name.split(".")[1]
parser = optparse.OptionParser(usage="%prog (...) --layout " + lname + " [options] (...)",add_help_option=False)

View File

@ -23,7 +23,10 @@
# *****************************************
def rect_ratio(r):
"""returns the ratio of rect I{r} which is defined as M{width/height}"""
"""returns the ratio of rect I{r} which is defined as M{width/height}
@rtype: float
"""
return r[2]*1.0/r[3]
def rect_rel_scale(r, fw, fh, align_x = 0, align_y = 0):
@ -40,33 +43,49 @@ def rect_rel_scale(r, fw, fh, align_x = 0, align_y = 0):
linear interpolation.
@type align_y: float in [-1,1]
@param align_y: Performs vertical (top-bottom) alignment similarly to L{align_x}.
@rtype: (float,float,float,float)
"""
x, y, w, h = r
return (x + (align_x + 1.0)*w*(1 - fw)/2.0,
y + (align_y + 1.0)*h*(1 - fh)/2.0, w*fw, h*fh)
def rect_pad(r, pad):
"""returns a padded rect by reducing border by the I{pad} tuple (top,left,bottom,right)"""
"""returns a padded rect by reducing border by the I{pad} tuple (top,left,bottom,right)
@rtype: (float,float,float,float)
"""
x, y, w, h = r
t_, l_, b_, r_ = pad
return (x + l_, y + t_, w - r_ - l_, h - t_ - b_)
def rect_to_abs(r):
"""get absolute coordinates (x0,y0,x1,y1) from rect definition (x,y,w,h)"""
"""get absolute coordinates (x0,y0,x1,y1) from rect definition (x,y,w,h)
@rtype: (float,float,float,float)
"""
x, y, w, h = r
return (x, y, x + w, y + h)
def abs_to_rect(a):
"""get rect definition (x,y,w,h) from absolute coordinates (x0,y0,x1,y1)"""
"""get rect definition (x,y,w,h) from absolute coordinates (x0,y0,x1,y1)
@rtype: (float,float,float,float)
"""
x1, y1, x2, y2 = a
return (x1, y1, x2 - x1, y2 - y1)
def rect_from_origin(r):
"""returns a similar rect with top-left corner at (0,0)"""
"""returns a similar rect with top-left corner at (0,0)
@rtype: (float,float,float,float)
"""
return (0, 0, r[2], r[3])
def rect_hull(r1,r2):
"""returns the smallest rect containing r1 and r2"""
"""returns the smallest rect containing r1 and r2
@rtype: (float,float,float,float)
"""
x1, y1, x2, y2 = rect_to_abs(r1)
x3, y3, x4, y4 = rect_to_abs(r2)
return abs_to_rect((min(x1,x3), min(y1,y3), max(x2,x4), max(y2,y4)))
@ -77,6 +96,7 @@ def rect_hsplit(r, f = 0.5, fdist = 0.0):
@type f: float in [0,1]
@param f: split fraction
@param fdist: fraction of space to discard before splitting (free space)
@rtype: ((float,float,float,float),(float,float,float,float))
@return: tuple (r1,r2) with splits and free space evenly distributed
before r1, between r1 and r2 and after r2
"""
@ -87,7 +107,10 @@ def rect_hsplit(r, f = 0.5, fdist = 0.0):
return (r1, r2)
def rect_vsplit(r, f = 0.5, fdist = 0.0):
"""split a rect vertically, similarly to L{rect_hsplit}"""
"""split a rect vertically, similarly to L{rect_hsplit}
@rtype: ((float,float,float,float),(float,float,float,float))
"""
x, y, w, h = r
rh = h*(1.0 - fdist)
r1 = (x, y + h*fdist/3.0, w, rh*f)
@ -99,6 +122,7 @@ def color_mix(a, b, frac):
@type frac: float in [0,1]
@param frac: amount of first color
@rtype: tuple
"""
return map(lambda (x,y): x*frac + y*(1 - frac), zip(a,b))
@ -107,11 +131,15 @@ def color_scale(a, frac):
@type frac: float
@param frac: scale amount (to be multiplied)
@rtype: tuple
"""
return map(lambda x: min(1.0,x*frac), a)
def color_auto_fg(bg, light = (1,1,1), dark = (0,0,0)):
"""return I{light} or I{dark} foreground color based on an ad-hoc evaluation of I{bg}"""
"""return I{light} or I{dark} foreground color based on an ad-hoc evaluation of I{bg}
@rtype: tuple
"""
return light if (bg[0] + 1.5*bg[1] + bg[2]) < 1.0 else dark
# ********* layout managers ***********
@ -129,7 +157,10 @@ class VLayout(object):
self.pad = pad
def count(self):
"""return maximum number of items in the layout"""
"""return maximum number of items in the layout
@rtype: int
"""
return self.nitems
def resize(self, k):
@ -141,7 +172,10 @@ class VLayout(object):
self.nitems += delta
def item(self, i = 0):
"""get rect for item I{i}"""
"""get rect for item I{i}
@rtype: (float,float,float,float)
"""
x, y, w, h = self.rect
h *= 1.0/self.nitems
y += i*h
@ -152,12 +186,16 @@ class VLayout(object):
@param n: first item
@param k: number of items, -1 for all remaining items
@rtype: (float,float,float,float)
"""
if k < 0: k = (self.count() - n) // 2
return rect_hull(self.item(k), self.item(k + n - 1))
def items(self):
"""returns a sequence of all items"""
"""returns a sequence of all items
@rtype: (float,float,float,float),...
"""
return map(self.item, range(self.count()))
class HLayout(VLayout):
@ -167,6 +205,10 @@ class HLayout(VLayout):
nitems, (pad[1], pad[0], pad[3], pad[2]))
def item(self, i = 0):
"""get rect for item I{i}
@rtype: (float,float,float,float)
"""
t = super(HLayout,self).item(i)
return (t[1], t[0], t[3], t[2])
@ -189,15 +231,24 @@ class GLayout(object):
self.hrep = HLayout((rect[0], rect[1], t[2], t[3]), ncols, (0.0, pad[1], 0.0, pad[3]))
def row_count(self):
"""get (max) number of rows in the grid"""
"""get (max) number of rows in the grid
@rtype: int
"""
return self.vrep.count()
def col_count(self):
"""get (max) number of columns in the grid"""
"""get (max) number of columns in the grid
@rtype: int
"""
return self.hrep.count()
def count(self):
"""get total number of cells in the grid (which is M{rows*cols})"""
"""get total number of cells in the grid (which is M{rows*cols})
@rtype: int
"""
return self.row_count()*self.col_count()
def resize(self, rows, cols):
@ -207,13 +258,19 @@ class GLayout(object):
self.hrep = HLayout(t[0:2], t[2:4], cols, (0.0, pad[1], 0.0, pad[3]))
def item(self, row, col):
"""get rect of cell at position I{row,col}"""
"""get rect of cell at position I{row,col}
@rtype: (float,float,float,float)
"""
ty = self.vrep.item(row)
tx = self.hrep.item(col)
return (tx[0], ty[1], tx[2], tx[3])
def item_seq(self, k, column_wise = False):
"""get rect of cell at position I{k} column-wise or row-wise"""
"""get rect of cell at position I{k} column-wise or row-wise
@rtype: (float,float,float,float)
"""
if not column_wise:
row, col = k // self.col_count(), k % self.col_count()
else:
@ -221,15 +278,24 @@ class GLayout(object):
return self.item(row, col)
def items(self, column_wise = False):
"""get sequence of rects of cells column-wise or row-wise"""
"""get sequence of rects of cells column-wise or row-wise
@rtype: (float,float,float,float),...
"""
return map(self.item_seq, range(self.count()))
def row_items(self, row):
"""get sequence of cell rects of a row"""
"""get sequence of cell rects of a row
@rtype: (float,float,float,float),...
"""
return map(lambda x: self.item(row, x), range(self.col_count()))
def col_items(self, col):
"""get sequence of cell rects of a column"""
"""get sequence of cell rects of a column
@rtype: (float,float,float,float),...
"""
return map(lambda x: self.item(x, col), range(self.row_count()))
@ -240,6 +306,7 @@ class GLayout(object):
@param nc: number of spanning columns
@param row: starting row, -1 for vertically centered
@param col: starting column, -1 for horizontally centered
@rtype: (float,float,float,float)
"""
if row < 0: row = (self.row_count() - nr) // 2
if col < 0: col = (self.col_count() - nc) // 2

View File

@ -25,7 +25,9 @@
from datetime import date, timedelta
def _get_orthodox_easter(year):
"""compute date of orthodox easter"""
"""compute date of orthodox easter
@rtype: datetime.date
"""
y1, y2, y3 = year % 4 , year % 7, year % 19
a = 19*y3 + 15
y4 = a % 30
@ -37,7 +39,10 @@ def _get_orthodox_easter(year):
# return res
def _get_catholic_easter(year):
"""compute date of catholic easter"""
"""compute date of catholic easter
@rtype: datetime.date
"""
a, b, c = year % 19, year // 100, year % 100
d, e = divmod(b,4)
f = (b + 8) // 25
@ -50,11 +55,17 @@ def _get_catholic_easter(year):
return date(year, emonth, edate+1)
def _strip_empty(sl):
"""strip empty strings from list I{sl}"""
"""strip empty strings from list I{sl}
@rtype: [str,...]
"""
return filter(lambda z: z, sl) if sl else []
def _flatten(sl):
"""join list I{sl} into a comma-separated string"""
"""join list I{sl} into a comma-separated string
@rtype: str
"""
if not sl: return None
return ', '.join(sl)
@ -94,19 +105,31 @@ class Holiday(object):
self.flags |= hol.flags
def header(self):
"""return a comma-separated string for L{header_list}"""
"""return a comma-separated string for L{header_list}
@rtype: str
"""
return _flatten(self.header_list)
def footer(self):
"""return a comma-separated string for L{footer_list}"""
"""return a comma-separated string for L{footer_list}
@rtype: str
"""
return _flatten(self.footer_list)
def __str__(self):
"""string representation for debugging purposes"""
"""string representation for debugging purposes
@rtype: str
"""
return str(self.footer()) + ':' + str(self.header()) + ':' + str(self.flags)
def _parse_flags(self, fstr):
"""return a bit combination of flags, from a comma-separated string list"""
"""return a bit combination of flags, from a comma-separated string list
@rtype: int
"""
if not fstr: return 0
fs = fstr.split(',')
val = 0
@ -130,6 +153,8 @@ def _decode_date_str(ddef):
If C{ddef} is of the form "YYYYMMDD" then tuple (YYYY,MM,DD) is returned, which
stands for year YYYY - month MM - day DD.
@rtype: (int,int,int)
"""
if len(ddef) == 2:
return (0,0,int(ddef))
@ -189,11 +214,12 @@ class HolidayProvider(object):
def _parse_day_record(self, fields):
"""return tuple (etype,ddef,footer,header,flags)
@rtype: (char,type(ddef),str,str,int)
@note: I{ddef} is one of the following:
None
int
((y,m,d),)
((y,m,d),(y,m,d))
- None
- int
- ((y,m,d),)
- ((y,m,d),(y,m,d))
"""
if len(fields) != 5:
raise ValueError("Too many fields: " + str(fields))
@ -239,6 +265,7 @@ class HolidayProvider(object):
@param header: passed as C{[header]} of the generated L{Holiday} object
@param footer: passed as C{[footer]} of the generated L{Holiday} object
@param flags: C{flags} of the generated L{Holiday} object
@rtype: (Holiday,Holiday,Holiday,Holiday)
"""
if header:
if self.multiday_markers:
@ -341,6 +368,7 @@ class HolidayProvider(object):
def get_holiday(self, y, m, d):
"""return a L{Holiday} object for the specified date (y,m,d) or C{None} if no holiday is defined
@rtype: Holiday
@note: If year I{y} has not been requested before, the cache is updated first
with all holidays that belong in I{y}, indexed by C{date()} objects.
"""
@ -388,6 +416,7 @@ class HolidayProvider(object):
def get_style(self, flags, dow):
"""return appropriate style object, depending on I{flags} and I{dow}
@rtype: Style
@param flags: bit combination of holiday flags
@param dow: day of week
"""
@ -400,6 +429,7 @@ class HolidayProvider(object):
def __call__(self, year, month, dom, dow):
"""returns (header,footer,day_style)
@rtype: (str,str,Style)
@param month: month (0-12)
@param dom: day of month (1-31)
@param dow: day of week (0-6)

View File

@ -29,6 +29,7 @@ import glob
def available_files(parent, dir, fmatch = None):
"""find parent/dir/*.py files to be used for plugins
@rtype: [str,...]
@note:
1. __init__.py should exist
2. files starting with underscore are ignored
@ -50,7 +51,10 @@ def available_files(parent, dir, fmatch = None):
return res if good else []
def plugin_list(cat):
"""return a sequence of available plugins, using L{available_files()} and L{get_plugin_paths()}"""
"""return a sequence of available plugins, using L{available_files()} and L{get_plugin_paths()}
@rtype: [str,...]
"""
plugin_paths = get_plugin_paths()
return available_files(plugin_paths[0], cat) + available_files(plugin_paths[1], cat)
@ -61,5 +65,8 @@ def plugin_list(cat):
# preset = "EN"
def get_plugin_paths():
"""return the plugin search paths"""
"""return the plugin search paths
@rtype: [str,str]
"""
return [ os.path.expanduser("~/.callirhoe"), sys.path[0] if sys.path[0] else "." ]

View File

@ -43,6 +43,8 @@ def page_spec(spec = None):
Paper type can be an ISO paper type (a0..a9 or a0w..a9w) or of the
form W:H; positive values correspond to W or H mm, negative values correspond to
-W or -H pixels; 'w' suffix swaps width & height; None defaults to A4 paper
@rtype: (int,int)
"""
if not spec:
return (ISOPAGE[5], ISOPAGE[4])
@ -62,11 +64,17 @@ def page_spec(spec = None):
return (w,h)
def mm_to_dots(mm):
"""convert millimeters to dots"""
"""convert millimeters to dots
@rtype: float
"""
return mm/25.4 * XDPI
def dots_to_mm(dots):
"""convert dots to millimeters"""
"""convert dots to millimeters
@rtype: float
"""
return dots*25.4/XDPI
class Page(object):
@ -205,7 +213,10 @@ def set_color(cr, rgba):
cr.set_source_rgba(*rgba)
def extract_font_name(f):
"extract the font name from a string or from a tuple (fontname, slant, weight)"""
"""extract the font name from a string or from a tuple (fontname, slant, weight)
@rtype: str
"""
return f if type(f) is str else f[0]
def make_sloppy_rect(cr, rect, sdx = 0.0, sdy = 0.0, srot = 0.0):
@ -233,8 +244,6 @@ def draw_shadow(cr, rect, thickness = None, shadow_color = (0,0,0,0.3)):
@param thickness: if C{None} nothing is drawn
@param shadow_color: shadow color
"""
if thickness is None: return
fx = mm_to_dots(thickness[0])
fy = mm_to_dots(thickness[1])