summaryrefslogtreecommitdiff
path: root/pypers/bolzano/db/mysql/ui
diff options
context:
space:
mode:
Diffstat (limited to 'pypers/bolzano/db/mysql/ui')
-rwxr-xr-xpypers/bolzano/db/mysql/ui/HTMLTable.py47
-rwxr-xr-xpypers/bolzano/db/mysql/ui/__init__.py0
-rwxr-xr-xpypers/bolzano/db/mysql/ui/cycle.py66
-rwxr-xr-xpypers/bolzano/db/mysql/ui/iter_utils.py151
-rwxr-xr-xpypers/bolzano/db/mysql/ui/quixote_utils.py191
-rwxr-xr-xpypers/bolzano/db/mysql/ui/table.html23
-rwxr-xr-xpypers/bolzano/db/mysql/ui/x.html104
7 files changed, 582 insertions, 0 deletions
diff --git a/pypers/bolzano/db/mysql/ui/HTMLTable.py b/pypers/bolzano/db/mysql/ui/HTMLTable.py
new file mode 100755
index 0000000..5b6fe53
--- /dev/null
+++ b/pypers/bolzano/db/mysql/ui/HTMLTable.py
@@ -0,0 +1,47 @@
+import os
+from cycle import Cycle, chop
+from quixote.form.form import Form
+import quixote.form.widget as w
+from quixote_utils import RootDirectory, htmltext
+
+class HTMLTable(object):
+ def __init__(self, body, header=None, maxsize=20):
+ self.header = header or []
+ self.body = body
+ self.maxsize = maxsize
+ self.cycle = Cycle(chop(self.body, maxsize))
+
+ def make_row(self, row, typ="td"):
+ return "<tr>%s</tr>" % "".join(["<%s>%s</%s>" %
+ (typ, col, typ) for col in row])
+ def gen_table(self):
+ yield "<table border='1'>"
+ yield self.make_row(self.header, "th")
+ for row in self.cycle():
+ yield self.make_row(row)
+ yield "</table>"
+
+
+ def render(self):
+ return "\n".join(self.gen_table())
+
+if __name__ == "__main__": # test
+
+
+ class Root(RootDirectory):
+ _q_exports = ["show_table"]
+ table = HTMLTable([["a", i] for i in range(100)])
+ def show_table(self):
+ form = Form()
+ form.add(w.SubmitWidget, "prev", "prev")
+ form.add(w.SubmitWidget, "next", "next")
+ if form.is_submitted():
+ if form["prev"]:
+ self.table.cycle.prev()
+ elif form["next"]:
+ self.table.cycle.next()
+ return htmltext(self.table.render()) + form.render()
+
+ Root().publish_show("show_table")
+
+
diff --git a/pypers/bolzano/db/mysql/ui/__init__.py b/pypers/bolzano/db/mysql/ui/__init__.py
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/pypers/bolzano/db/mysql/ui/__init__.py
diff --git a/pypers/bolzano/db/mysql/ui/cycle.py b/pypers/bolzano/db/mysql/ui/cycle.py
new file mode 100755
index 0000000..d3d8c80
--- /dev/null
+++ b/pypers/bolzano/db/mysql/ui/cycle.py
@@ -0,0 +1,66 @@
+#from itertools import cycle
+
+class CycleOld(object):
+ def __init__(self, seq):
+ self.seq = list(seq)
+ self.index = 0
+ self.min_index = 0
+ self.max_index = len(self.seq) - 1
+ def __call__(self):
+ return self.seq[self.index]
+ def prev(self):
+ if self.index == self.min_index:
+ self.index = self.max_index
+ else:
+ self.index -= 1
+ return self()
+ def next(self):
+ if self.index == self.max_index:
+ self.index = self.min_index
+ else:
+ self.index += 1
+ return self()
+
+class Cycle(object):
+ def __init__(self, seq):
+ self.seq = list(seq)
+ self.len = len(self.seq)
+ self.index = 0
+ def __call__(self):
+ return self.seq[self.index % self.len]
+ def prev(self):
+ self.index -= 1
+ return self()
+ def next(self):
+ self.index += 1
+ return self()
+
+def chop(seq, binsize):
+ bin = []
+ for i, el in enumerate(seq):
+ bin.append(el)
+ if i % binsize == binsize - 1:
+ yield bin; bin = []
+ if bin:
+ yield bin
+
+if __name__ == "__main__":
+ print list(chop("precipitevolissimevolmente", 3))
+
+# chop([1,2,3,4,5,6], 2)
+# [[1,2], [3,4], [4.6]]
+
+
+## cycle = Cycle2([1,2,3])
+## print cycle()
+## print cycle.prev()
+## print cycle.prev()
+## print cycle.prev()
+## print cycle.prev()
+## print "-"*10
+## print cycle.next()
+## print cycle.next()
+## print cycle.next()
+## print cycle.next()
+
+
diff --git a/pypers/bolzano/db/mysql/ui/iter_utils.py b/pypers/bolzano/db/mysql/ui/iter_utils.py
new file mode 100755
index 0000000..78ce0ec
--- /dev/null
+++ b/pypers/bolzano/db/mysql/ui/iter_utils.py
@@ -0,0 +1,151 @@
+"""General utilities involving iterables."""
+
+import sets, itertools, os
+try: # Python 2.4 vs. Python 2.3
+ set
+except NameError:
+ from sets import Set as set
+
+def check(it):
+ """
+ Checks if an iterator is empty. Returns a copy of the original iterator.
+
+ >>> it = check(iter([1]))
+ >>> if it: it.next()
+ 1
+ """
+ try:
+ first = it.next()
+ except StopIteration:
+ return False
+ else:
+ return itertools.chain([first], it)
+
+def skip_redundant(iterable, skipset=None):
+ "Redundant items are repeated items or items in the original skipset."
+ if skipset is None: skipset = set()
+ for item in iterable:
+ if item not in skipset:
+ skipset.add(item)
+ yield item
+
+def chop(iterable, batchsize):
+ """Chop an iterable. For instance
+
+ >>> list(chop([1,2,3,4], 2))
+ [[1, 2], [3, 4]]
+ >>> list(chop([1,2,3,4,5,6,7],3))
+ [[1, 2, 3], [4, 5, 6], [7]]
+
+ It trunks the remainder elements, if the
+ iterable is not divisible by batchsize.
+ """
+ it = iter(iterable)
+ while True:
+ batch = list(itertools.islice(it, batchsize))
+ if batch: yield batch
+ else: break
+
+# used in the voting package
+def first_duplicate_ls(it):
+ """Returns None or a list with the duplicated element."""
+ dupl = sets.Set()
+ for el in it:
+ if el in dupl:
+ return [el]
+ else:
+ dupl.add(el)
+
+# useful to display the list of votes in a short form
+class PackedList(list):
+ """Take a list with repetitions and pack it in the form
+
+ PackedList([elements ..]) --> [(number_of_repetitions, element) ...]
+
+ Gives a nice printing representation. Usage:
+ PackedList(<list>, <string-repr-method> = str)
+ It is possible to specify a custom string representation for
+ the list elements."""
+
+ def __init__(self, ls, to_str = str):
+ self.to_str = to_str
+ self.packedls = []
+ self.pack(list(ls))
+ self.extend(self.packedls)
+
+ def pack(self, lst):
+ """Recursive packer. At each call removes an element from ls and
+ adds it to self.packedls. Returns when ls is fully depleted.
+ """
+ if not lst: return
+ el, ls= lst[0], lst[1:]
+ count = 1 # number of repetitions
+ for i, elem in enumerate(ls[:]):
+ if elem == el: # remove the duplicated element
+ del ls[i+1-count] # in the right position
+ count += 1
+ self.packedls.append((count, el))
+ self.pack(ls) # recurse until ls is empty
+
+ def __str__(self):
+ """Returns a table <number of repetions>: <element>"""
+ return "\n".join(["%s: %s" % (t[0], self.to_str(t[1])) for t in self])
+
+# a reiterable cycle going in both directions
+class Cycle(object):
+ def __init__(self, seq):
+ self._list = list(seq)
+ self._len = len(self._list)
+ self.index = 0
+ def __iter__(self):
+ return itertools.cycle(self._list)
+ def next(self):
+ self.index += 1
+ return self()
+ def prev(self):
+ self.index -= 1
+ return self()
+ def __len__(self):
+ return self._len
+ def __call__(self):
+ return self._list[self.index % self._len]
+ def __getitem__(self, i):
+ return self._list[i % self._len]
+ def __setitem__(self, i, v):
+ self._list[i % self._len] = v
+
+############ OLD VERSIONS ###############
+
+## def chop_trunk(it, n = 2):
+## tup = (iter(it), ) * n
+## return itertools.izip(*tup)
+
+## def chop_notrunk(iterable, binsize):
+## bin = []
+## for i, el in enumerate(iterable):
+## bin.append(el)
+## if i % binsize == binsize-1:
+## yield bin; bin = []
+## if bin:
+## yield bin
+
+## def chop(iterable, binsize, trunk=False):
+## if trunk:
+## return chop_trunk(iterable, binsize)
+## else:
+## return chop_notrunk(iterable, binsize)
+
+if __name__ == "__main__": # test Cycle
+ c = Cycle([1,2,3])
+ print c()
+ print c.next()
+ print c.next()
+ print c.next()
+ print c.next()
+ print c.next()
+ print c.prev()
+ print c.prev()
+ print c.prev()
+ print c.prev()
+ print c.prev()
+ print c.prev()
diff --git a/pypers/bolzano/db/mysql/ui/quixote_utils.py b/pypers/bolzano/db/mysql/ui/quixote_utils.py
new file mode 100755
index 0000000..0a93d42
--- /dev/null
+++ b/pypers/bolzano/db/mysql/ui/quixote_utils.py
@@ -0,0 +1,191 @@
+import os, sys, time, webbrowser
+from quixote.directory import Directory
+from quixote.publish import Publisher, SessionPublisher
+from quixote.session import Session, SessionManager
+from quixote.server import simple_server
+from quixote.errors import AccessError
+from quixote import get_response, get_user
+from quixote.html import href, htmltext
+from quixote.form.form import Form
+from quixote.form.widget import *
+
+webbrowser.register("konqueror", webbrowser.Konqueror)
+elinks = webbrowser.GenericBrowser('xterm -e elinks %s')
+lynx = webbrowser.GenericBrowser('xterm -e lynx -accept_all_cookies %s')
+webbrowser.register("elinks", webbrowser.GenericBrowser, elinks)
+webbrowser.register("lynx", webbrowser.GenericBrowser, lynx) # second choice
+
+class RecognizeExports(type):
+ def __init__(cls, name, bases, dic):
+ super(RecognizeExports, cls).__init__(cls, name, bases, dic)
+ for k in dic: setattr(cls, k, dic[k])
+ def __setattr__(cls, name, value):
+ if hasattr(value, "_q_exported"):
+ cls._q_exports.append(name)
+ super(RecognizeExports, cls).__setattr__(name, value)
+
+# by definition, the root directory is a singleton
+class RootDirectory(Directory):
+ _q_exports = [""]
+ __metaclass__ = RecognizeExports
+ __Publisher = Publisher
+ __server = simple_server
+ __port = 7080
+
+ def _q_index(self):
+ return "Welcome to the root of your application."
+
+ def set_default(self, server=simple_server, Publisher=Publisher,
+ Session=Session, session_mapping=None, port=7080):
+ self.__server = server
+ self.__Publisher = Publisher
+ self.__Session = Session
+ self.__session_mapping = session_mapping
+ self.__port = port
+
+ __init__ = set_default
+
+ def publish(self):
+ if issubclass(self.__Publisher, SessionPublisher):
+ create_pub = lambda : self.__Publisher(
+ self, SessionManager(self.__Session, self.__session_mapping))
+ else:
+ create_pub = lambda : self.__Publisher(self)
+ self.__server.run(create_pub, '', self.__port)
+
+ def publish_show(self, page="", browser="mozilla"):
+ if os.fork(): # parent
+ self.publish()
+ else: # child
+ webbrowser.get(browser).open(
+ "http://localhost:%s/%s" % (self.__port, page))
+
+
+class UnauthorizedError(AccessError):
+ """The request requires user authentication.
+
+ This subclass of AccessError sends a 401 instead of a 403,
+ hinting that the client should try again with authentication.
+ """
+ status_code = 401
+ title = "Unauthorized"
+ description = "You are not authorized to access this resource."
+
+ def __init__(self, realm='Protected', public_msg=None, private_msg=None):
+ self.realm = realm
+ AccessError.__init__(self, public_msg, private_msg)
+
+ def format(self):
+ get_response().set_header(
+ 'WWW-Authenticate', 'Basic realm="%s"' % self.realm)
+ return AccessError.format(self)
+
+
+class User(object):
+ def __init__(self, username, password):
+ self.username = username
+ self.password = password
+ def __str__(self):
+ return "<User: %s %s>" % (self.username, self.password)
+ def permissions(self):
+ """Returns the list of methods starting with 'can_'."""
+ return [perm for perm in dir(self) if perm.startswith("can_")]
+
+def public(f):
+ f._q_exported = True
+ return f
+
+class private(object):
+ """Redirect to the login page if the user is not logged in or if he does
+ not have the right permissions."""
+ # obviously, this assumes a login page exists and is called 'login'
+ def __init__(self, *groups_with_access):
+ self.valid_groups = groups_with_access or (User,)
+ def __call__(self, method):
+ def wrapper(root):
+ user = get_user()
+ if not user or not isinstance(user, self.valid_groups):
+ root.resume = meth_name
+ valid_groups = ", ".join([
+ cls.__name__ for cls in self.valid_groups])
+ return "You are trying to access a page restricted to %s. " % \
+ valid_groups + href(
+ "login", "Please login as a valid user.")
+ else:
+ return method(root)
+ meth_name = method.func_name
+ wrapper.func_name = meth_name
+ wrapper._q_exported = True
+ return wrapper
+
+######################## deprecated ############################
+
+def old_public(f):
+ """Append f.__name__ to the caller's _q_exports. If the caller has
+ no _q_exports, creates it."""
+ _q_exports = sys._getframe(1).f_locals.setdefault("_q_exports",[""])
+ _q_exports.append(f.__name__)
+ return f
+
+class old_private(object):
+ """Redirect to the login page if the user is not logged in or if he does
+ not have the right permissions."""
+ # obviously, this assumes a login page exists and is called 'login'
+ def __init__(self, *groups_with_access):
+ self.valid_groups = groups_with_access or (User,)
+ def __call__(self, method):
+ def wrapper(root):
+ user = get_user()
+ if not user or not isinstance(user, self.valid_groups):
+ root.resume = meth_name
+ valid_groups = ", ".join([cls.__name__ for cls
+ in self.valid_groups])
+ return "You are trying to access a page restricted to %s. " % \
+ valid_groups + href("login", "Please login as a valid user.")
+ else:
+ return method(root)
+ meth_name = method.func_name
+ _q_exports = sys._getframe(1).f_locals.setdefault("_q_exports",[""])
+ _q_exports.append(meth_name)
+ wrapper.func_name = meth_name
+ return wrapper
+
+from iter_utils import Cycle, chop
+
+class MultipageTable(object):
+ # use Quixote forms
+ def __init__(self, body, header=[], maxsize=20):
+ self.header = header
+ self.maxsize = maxsize
+ self.section = Cycle(chop(body, maxsize))
+ self.sect = self.section[0] # default
+ self.ismultipage = len(self.section) > 1
+
+ def makerow(self, row, header=False):
+ if header:
+ r = " ".join(["<th>%s</th>" % col for col in row])
+ else:
+ r = " ".join(["<td>%s</td>" % col for col in row])
+ return "<tr>%s</tr>" % r
+
+ def maketable(self):
+ if self.ismultipage:
+ form = Form()
+ form.add(SubmitWidget, "prev", "Prev")
+ form.add(SubmitWidget, "next", "Next")
+ if form["next"]: # is submitted
+ self.sect = self.section.next()
+ if form["prev"]: # is submitted
+ self.sect = self.section.prev()
+ yield "Page #%s of %s" % (self.section.index+1, len(self.section))
+ yield "<table border='1'>"
+ if self.header:
+ yield self.makerow(self.header)
+ for row in self.sect:
+ yield self.makerow(row)
+ yield "</table>"
+ if self.ismultipage:
+ yield form.render()
+
+ def render(self):
+ return htmltext("\n").join(map(htmltext, self.maketable()))
diff --git a/pypers/bolzano/db/mysql/ui/table.html b/pypers/bolzano/db/mysql/ui/table.html
new file mode 100755
index 0000000..c914c52
--- /dev/null
+++ b/pypers/bolzano/db/mysql/ui/table.html
@@ -0,0 +1,23 @@
+<table border='1'>
+<tr><th>Variable</th><th>Value</th></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+</table>
diff --git a/pypers/bolzano/db/mysql/ui/x.html b/pypers/bolzano/db/mysql/ui/x.html
new file mode 100755
index 0000000..999462e
--- /dev/null
+++ b/pypers/bolzano/db/mysql/ui/x.html
@@ -0,0 +1,104 @@
+[['p', 'r', 'e'], ['c', 'i', 'p'], ['i', 't', 'e'], ['v', 'o', 'l'], ['i', 's', 's'], ['i', 'm', 'e'], ['v', 'o', 'l'], ['m', 'e', 'n'], ['t', 'e']]
+<table border='1'>
+<tr><th>Variable</th><th>Value</th></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+<tr><td>a</td><td>1</td></tr>
+</table>