# HG changeset patch # User David Barts # Date 1559088516 25200 # Node ID ce67eac10fc72610ecd742b80a36df27f4730cc3 # Parent 4ed261056057c49eabdfa03d4051b60ad13164fd Allow global character encoding specification. diff -r 4ed261056057 -r ce67eac10fc7 launch --- a/launch Tue May 28 15:54:47 2019 -0700 +++ b/launch Tue May 28 17:08:36 2019 -0700 @@ -7,7 +7,7 @@ import os, sys from argparse import ArgumentParser -from tincan import launch +from tincan import launch, ENCODING # V a r i a b l e s @@ -17,14 +17,16 @@ parser = ArgumentParser(prog=sys.argv[0], usage="%(prog)s [options] [directory [path]]") opt = parser.add_argument -opt("-b", "--bind", default="localhost", help="address to bind to") +opt("-b", "--bind", default="localhost", help="address to bind to (default: localhost)") opt("-d", "--debug", action="store_true", help="enable debug mode") +opt("-e", "--encoding", default=ENCODING, help="encoding to use (default {0})".format(ENCODING)) opt("-f", "--force", action="store_true", help="do not abort on errors") -opt("-p", "--port", default=8080, help="port to listen on") +opt("-p", "--port", default=8080, help="port to listen on (default: 8080)") opt("directory", default=".", help="directory to serve", nargs='?') opt("path", default="/", help="URL path to serve", nargs='?') args = parser.parse_args(sys.argv[1:]) -app, errors = launch(fsroot=args.directory, urlroot=args.path, debug=args.debug) +app, errors = launch(fsroot=args.directory, urlroot=args.path, debug=args.debug, + encoding=args.encoding) if errors: action = "continuing" if args.force else "aborting" sys.stderr.write("{0}: {1} error{2} detected, {3}\n".format( diff -r 4ed261056057 -r ce67eac10fc7 tincan.py --- a/tincan.py Tue May 28 15:54:47 2019 -0700 +++ b/tincan.py Tue May 28 17:08:36 2019 -0700 @@ -194,11 +194,12 @@ def prepare(self, **options): from chameleon import PageTemplate, PageTemplateFile if self.source: - self.tpl = PageTemplate(self.source, encoding=self.encoding, - **options) + self.tpl = PageTemplate(self.source, **options) else: self.tpl = PageTemplateFile(self.filename, encoding=self.encoding, search_path=self.lookup, **options) + # XXX - work around broken Chameleon decoding + self.tpl.default_encoding = self.encoding def render(self, *args, **kwargs): for dictarg in args: @@ -354,10 +355,10 @@ # Using a cache is likely to help efficiency a lot, since many pages # will typically #load the same standard stuff. _tcache = {} -def _get_template(name, direct): +def _get_template(name, direct, coding): aname = os.path.abspath(os.path.join(direct, name)) if aname not in _tcache: - tmpl = ChameleonTemplate(name=name, lookup=[direct]) + tmpl = ChameleonTemplate(name=name, lookup=[direct], encoding=coding) tmpl.prepare() assert aname == tmpl.filename _tcache[aname] = tmpl @@ -425,6 +426,7 @@ self._seen = set() self._app = launcher.app self._save_loads = launcher.debug + self._encoding = launcher.encoding def launch(self): """ @@ -480,9 +482,9 @@ raise TinCanError("{0}: invalid #template: {1!s}".format(self._urlpath, e)) from e except IndexError as e: raise TinCanError("{0}: invalid #template".format(self._urlpath)) from e - self._body = ChameleonTemplate(source=tfile.body) + self._body = ChameleonTemplate(source=tfile.body, encoding=self._encoding) else: - self._body = ChameleonTemplate(source=self._template.body) + self._body = ChameleonTemplate(source=self._template.body, encoding=self._encoding) self._body.prepare() # Process loads self._loads = {} @@ -496,7 +498,7 @@ else: fdir = os.path.join(self._fsroot, *self._subdir) try: - tmpl = _get_template(load.fname, fdir) + tmpl = _get_template(load.fname, fdir, self._encoding) except Exception as e: raise TinCanError("{0}: bad #load: {1!s}".format(self._urlpath, e)) from e self._loads[load.vname] = tmpl.tpl @@ -525,7 +527,8 @@ raise TinCanError("{0}: bad #errors line".format(self._urlpath)) from e if not errors: errors = range(_ERRMIN, _ERRMAX+1) - route = _TinCanErrorRoute(ChameleonTemplate(source=self._template.body), + route = _TinCanErrorRoute( + ChameleonTemplate(source=self._template.body, encoding=self._encoding), self._loads, self._class) for error in errors: if error < _ERRMIN or error > _ERRMAX: @@ -676,6 +679,7 @@ _WINF = "WEB-INF" _BANNED = set([_WINF]) +ENCODING = "utf-8" class _Launcher(object): """ @@ -691,6 +695,7 @@ self.app = None self.errors = 0 self.debug = False + self.encoding = ENCODING def launch(self): """ @@ -751,7 +756,7 @@ sys.stderr.write(message) sys.stderr.write('\n') -def launch(fsroot=None, urlroot='/', logger=_logger, debug=False): +def launch(fsroot=None, urlroot='/', logger=_logger, debug=False, encoding=ENCODING): """ Launch and return a TinCan webapp. Does not run the app; it is the caller's responsibility to call app.run() @@ -760,6 +765,7 @@ fsroot = os.getcwd() launcher = _Launcher(fsroot, urlroot, logger) launcher.debug = debug + launcher.encoding = encoding launcher.launch() return launcher.app, launcher.errors