diff --git a/doc/demo.txt b/doc/demo.txt index 621c30d..fcd15bf 100644 --- a/doc/demo.txt +++ b/doc/demo.txt @@ -12,7 +12,7 @@ different server scripts may be found in the scripts themselves and in web-server.txt. To start, though, the easiest way to view the demos is as follows: in a terminal window, run:: - python -m quixote.server.simple_server + python3 -m quixote.server.simple_server and in a browser, open http://localhost:8080. If you wish to run the demo on a remote computer, you will need to ask the server to listen diff --git a/quixote/__init__.py b/quixote/__init__.py index fbf598e..2ba8cfd 100644 --- a/quixote/__init__.py +++ b/quixote/__init__.py @@ -3,7 +3,7 @@ A small and flexible Python web application framework. """ -__version__ = '2.9' +__version__ = '3.0' # These are frequently needed by Quixote applications. from quixote.publish import \ diff --git a/quixote/demo/altdemo.py b/quixote/demo/altdemo.py index 7a9edb5..c0332c0 100644 --- a/quixote/demo/altdemo.py +++ b/quixote/demo/altdemo.py @@ -1,3 +1,5 @@ ++#!/usr/bin/env python3 ++ """An alternative Quixote demo. This version is contained in a single module and does not use PTL. The easiest way to run this demo is to use the simple HTTP server included with Quixote. For example: @@ -54,9 +56,8 @@ class RootDirectory(Directory): content += htmltext( '
Hello, %s.
') % get_user() content += htmltext('%s
' % href('logout', 'logout')) - sessions = get_session_manager().items() + sessions = sorted(get_session_manager().items()) if sessions: - sessions.sort() content += htmltext('' ' | Session | ' @@ -177,17 +178,17 @@ try: session_class=PersistentSession, session_mapping=sessions) def forget_changes(self, session): - print 'abort changes', get_session() + print('abort changes', get_session()) connection.abort() def commit_changes(self, session): - print 'commit changes', get_session() + print('commit changes', get_session()) connection.commit() def create_durus_publisher(): global connection filename = os.path.join(tempfile.gettempdir(), 'quixote-demo.durus') - print 'Opening %r as a Durus database.' % filename + print('Opening %r as a Durus database.' % filename) connection = Connection(FileStorage(filename)) root = connection.get_root() session_manager = root.get('session_manager', None) diff --git a/quixote/demo/integers.ptl b/quixote/demo/integers.ptl index b94f11f..31a6d59 100644 --- a/quixote/demo/integers.ptl +++ b/quixote/demo/integers.ptl @@ -4,7 +4,7 @@ from quixote.directory import Directory, export from quixote.errors import TraversalError def fact(n): - f = 1L + f = 1 while n > 1: f *= n n -= 1 @@ -15,7 +15,7 @@ class IntegerUI(Directory): def __init__(self, component): try: self.n = int(component) - except ValueError, exc: + except ValueError as exc: raise TraversalError(str(exc)) @export diff --git a/quixote/demo/mini_demo.py b/quixote/demo/mini_demo.py index 5980089..1d0413d 100755 --- a/quixote/demo/mini_demo.py +++ b/quixote/demo/mini_demo.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ A minimal Quixote demo. If you have the 'quixote' package in your Python path, you can run it like this: @@ -35,5 +35,5 @@ def create_publisher(): if __name__ == '__main__': from quixote.server.simple_server import run - print 'creating demo listening on http://localhost:8080/' + print('creating demo listening on http://localhost:8080/') run(create_publisher, host='localhost', port=8080) diff --git a/quixote/demo/root.ptl b/quixote/demo/root.ptl index 582b58d..4073899 100644 --- a/quixote/demo/root.ptl +++ b/quixote/demo/root.ptl @@ -13,7 +13,7 @@ class RootDirectory(Directory): @export(name='') def index [html] (self): - print "debug message from the index page" + print("debug message from the index page") """ @@ -65,7 +65,7 @@ class RootDirectory(Directory): @export def error(self): - raise ValueError, "this is a Python exception" + raise ValueError("this is a Python exception") @export def publish_error(self): diff --git a/quixote/directory.py b/quixote/directory.py index c0f59b1..cc3f0ea 100644 --- a/quixote/directory.py +++ b/quixote/directory.py @@ -28,13 +28,11 @@ class DirectoryClass(type): return cls -class Directory(object): +class Directory(object, metaclass=DirectoryClass): """ Instance attributes: none """ - __metaclass__ = DirectoryClass - # A list containing strings or 2-tuples of strings that map external # names to internal names. Note that the empty string will be # implicitly mapped to '_q_index'. @@ -99,7 +97,7 @@ class Directory(object): if "" in self._q_exports and not quixote.get_request().form: # Fix missing trailing slash. path = quixote.get_path() - print "Adding slash to: %r " % path + print("Adding slash to: %r " % path) return quixote.redirect(path + "/", permanent=True) else: raise TraversalError(private_msg=('directory %r is not ' @@ -143,7 +141,7 @@ def export(func=None, name=None): """ def do_export(func): if name is None: - func._q_name = func.func_name + func._q_name = func.__name__ else: func._q_name = name return func @@ -160,7 +158,7 @@ def subdir(func=None, name=None): """ def do_export(func): if name is None: - func._q_name = func.func_name + func._q_name = func.__name__ else: func._q_name = name return property(func) diff --git a/quixote/form/compatibility.py b/quixote/form/compatibility.py index 41d8f01..7247827 100644 --- a/quixote/form/compatibility.py +++ b/quixote/form/compatibility.py @@ -69,7 +69,7 @@ class Form(_Form): return values def action(self, submit, values): - raise NotImplementedError, "sub-classes must implement 'action()'" + raise NotImplementedError("sub-classes must implement 'action()'") def handle(self): """handle() -> string diff --git a/quixote/form/form.py b/quixote/form/form.py index 5c30724..88e5faf 100644 --- a/quixote/form/form.py +++ b/quixote/form/form.py @@ -88,7 +88,7 @@ class Form(object): if enctype is not None and enctype not in ( "application/x-www-form-urlencoded", "multipart/form-data"): - raise ValueError, ("Form enctype must be " + raise ValueError("Form enctype must be " "'application/x-www-form-urlencoded' or " "'multipart/form-data', not %r" % enctype) self.enctype = enctype @@ -117,14 +117,11 @@ class Form(object): try: return self._names[name].parse() except KeyError: - raise KeyError, 'no widget named %r' % name - - def has_key(self, name): - """Return true if the widget named 'name' is in the form.""" - return name in self._names + raise KeyError('no widget named %r' % name) def __contains__(self, name): - return self.has_key(name) + """Return true if the widget named 'name' is in the form.""" + return name in self._names def get(self, name, default=None): """(name:string, default=None) -> any @@ -156,7 +153,7 @@ class Form(object): does not include sub-widgets (e.g. widgets that are part of CompositeWidgets) """ - return self._names.values() + return list(self._names.values()) # -- Form processing and error checking ---------------------------- @@ -223,14 +220,14 @@ class Form(object): """ widget = self._names.get(name) if not widget: - raise KeyError, "unknown name %r" % name + raise KeyError("unknown name %r" % name) widget.set_error(error) # -- Form population methods --------------------------------------- def add(self, widget_class, name, *args, **kwargs): if name in self._names: - raise ValueError, "form already has '%s' widget" % name + raise ValueError("form already has '%s' widget" % name) # add 'id' attribute if not already present if 'id' not in kwargs: kwargs['id'] = name @@ -348,8 +345,7 @@ class Form(object): sorted by code_id. """ form_code = [] - code_ids = javascript_code.keys() - code_ids.sort() + code_ids = sorted(javascript_code.keys()) for code_id in code_ids: code = javascript_code[code_id] if code: diff --git a/quixote/form/widget.py b/quixote/form/widget.py index 82f9e53..857905e 100644 --- a/quixote/form/widget.py +++ b/quixote/form/widget.py @@ -133,7 +133,7 @@ class Widget(object): if submitted: try: self._parse(request) - except WidgetValueError, exc: + except WidgetValueError as exc: self.set_error(stringify(exc)) if (self.required and self.value is None and not self.has_error()): @@ -143,7 +143,7 @@ class Widget(object): def _parse(self, request): # subclasses may override but this is not part of the public API value = request.form.get(self.name) - if isinstance(value, basestring) and value.strip(): + if isinstance(value, str) and value.strip(): self.value = value else: self.value = None @@ -311,7 +311,7 @@ class SelectWidget(Widget): if not options: # The HTML and XHTML specifications require select elements to # contain at least one option. - raise ValueError, "a non-empty list of 'options' is required" + raise ValueError("a non-empty list of 'options' is required") else: self.set_options(options, sort) self.verify_selection = verify_selection @@ -350,10 +350,10 @@ class SelectWidget(Widget): return keys # can't use OIDs, try using descriptions used_keys = {} - keys = map(stringify, descriptions) + keys = list(map(stringify, descriptions)) for key in keys: if key in used_keys: - raise ValueError, "duplicated descriptions (provide keys)" + raise ValueError("duplicated descriptions (provide keys)") used_keys[key] = 1 return keys @@ -391,14 +391,14 @@ class SelectWidget(Widget): descriptions.append(description) keys.append(stringify(key)) else: - raise ValueError, 'invalid options %r' % options + raise ValueError('invalid options %r' % options) else: values = descriptions = options if not keys: keys = self._generate_keys(values, descriptions) - options = zip(values, descriptions, keys) + options = list(zip(values, descriptions, keys)) if sort: def make_sort_key(option): @@ -407,8 +407,7 @@ class SelectWidget(Widget): return ('', option) else: return (stringify(description).lower(), option) - doptions = map(make_sort_key, options) - doptions.sort() + doptions = sorted(map(make_sort_key, options)) options = [item[1] for item in doptions] self.options = options @@ -439,7 +438,7 @@ class SelectWidget(Widget): self.set_options(allowed_values, sort) else: assert len(descriptions) == len(allowed_values) - self.set_options(zip(allowed_values, descriptions), sort) + self.set_options(list(zip(allowed_values, descriptions)), sort) def is_selected(self, value): return value == self.value @@ -613,7 +612,7 @@ class HiddenWidget(Widget): def set_error(self, error): if error is not None: - raise TypeError, 'error not allowed on hidden widgets' + raise TypeError('error not allowed on hidden widgets') def render_content(self): if self.value is None: @@ -769,7 +768,7 @@ class CompositeWidget(Widget): def add(self, widget_class, name, *args, **kwargs): if name in self._names: - raise ValueError, 'the name %r is already used' % name + raise ValueError('the name %r is already used' % name) if self.attrs.get('disabled') and 'disabled' not in kwargs: kwargs['disabled'] = True widget = widget_class(subname(self.name, name), *args, **kwargs) @@ -805,7 +804,7 @@ class WidgetList(CompositeWidget): assert type(element_kwargs) is dict, ( "value '%s' element_kwargs not a dict: " "got %r" % (name, element_kwargs)) - assert isinstance(add_element_label, (basestring, htmltext)), ( + assert isinstance(add_element_label, (str, htmltext)), ( "value '%s'add_element_label not a string: " "got %r" % (name, add_element_label)) @@ -899,7 +898,7 @@ class WidgetDict(CompositeWidget): assert type(element_value_kwargs) is dict, ( "value '%s' element_value_kwargs not a dict: " "got %r" % (name, element_value_kwargs)) - assert isinstance(add_element_label, (basestring, htmltext)), ( + assert isinstance(add_element_label, (str, htmltext)), ( 'value %r element_name not a string: ' 'got %r' % (name, add_element_label)) diff --git a/quixote/form1/form.py b/quixote/form1/form.py index 1adc978..afc436a 100644 --- a/quixote/form1/form.py +++ b/quixote/form1/form.py @@ -89,7 +89,7 @@ class Form: if enctype is not None and enctype not in ( "application/x-www-form-urlencoded", "multipart/form-data"): - raise ValueError, ("Form enctype must be " + raise ValueError("Form enctype must be " "'application/x-www-form-urlencoded' or " "'multipart/form-data', not %r" % enctype) self.enctype = enctype @@ -231,7 +231,7 @@ class Form: return r def _render_required_notice(self, request): - if filter(None, self.required.values()): + if any(self.required.values()): r = htmltext('|
---|---|---|
' '* = required field' ' |