diff --git a/callirhoe.py b/callirhoe.py index ecfc727..d376fb3 100755 --- a/callirhoe.py +++ b/callirhoe.py @@ -75,13 +75,14 @@ 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}. """ try: found = [] for path in plugin_paths: - found += available_files(plugin_paths[0], cat, preset) + found += available_files(path, cat, preset) if len(found) == 0: raise IOError old = sys.path[0]; sys.path[0] = found[0][1] @@ -137,12 +138,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); @@ -157,31 +159,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 @@ -195,6 +206,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 = [[],[]] @@ -223,7 +236,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. " diff --git a/calmagick.py b/calmagick.py index 81fc373..38d1485 100755 --- a/calmagick.py +++ b/calmagick.py @@ -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: diff --git a/layouts/_base.py b/layouts/_base.py index c0fe3c7..7fe79ae 100644 --- a/layouts/_base.py +++ b/layouts/_base.py @@ -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) diff --git a/layouts/classic.py b/layouts/classic.py index cc5e71a..b64ec67 100644 --- a/layouts/classic.py +++ b/layouts/classic.py @@ -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 diff --git a/layouts/sparse.py b/layouts/sparse.py index 0b9c75d..e9bedb6 100644 --- a/layouts/sparse.py +++ b/layouts/sparse.py @@ -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) diff --git a/lib/geom.py b/lib/geom.py index 3f7918c..d7d5139 100644 --- a/lib/geom.py +++ b/lib/geom.py @@ -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 diff --git a/lib/holiday.py b/lib/holiday.py index 22024a6..f3d4fdd 100644 --- a/lib/holiday.py +++ b/lib/holiday.py @@ -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) diff --git a/lib/plugin.py b/lib/plugin.py index 3c9d99f..8e5dcf3 100644 --- a/lib/plugin.py +++ b/lib/plugin.py @@ -34,6 +34,7 @@ except: 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 @@ -55,7 +56,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) @@ -66,11 +70,14 @@ def plugin_list(cat): # preset = "EN" def get_plugin_paths(): - """return the plugin search paths""" - result = [ os.path.expanduser("~/.callirhoe"), sys.path[0] if sys.path[0] else "."] + """return the plugin search paths + + @rtype: [str,str,..] + """ + result = [ os.path.expanduser("~/.callirhoe"), sys.path[0] if sys.path[0] else "." ] try: - tmp = resources.resource_list - result.append["resource"] + temp = resources.resource_list + result.append("resource") except: pass return result diff --git a/lib/xcairo.py b/lib/xcairo.py index 4e1c899..dcc2667 100644 --- a/lib/xcairo.py +++ b/lib/xcairo.py @@ -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])