diff options
Diffstat (limited to 'pypers/bolzano/db/mysql/ui')
-rwxr-xr-x | pypers/bolzano/db/mysql/ui/HTMLTable.py | 47 | ||||
-rwxr-xr-x | pypers/bolzano/db/mysql/ui/__init__.py | 0 | ||||
-rwxr-xr-x | pypers/bolzano/db/mysql/ui/cycle.py | 66 | ||||
-rwxr-xr-x | pypers/bolzano/db/mysql/ui/iter_utils.py | 151 | ||||
-rwxr-xr-x | pypers/bolzano/db/mysql/ui/quixote_utils.py | 191 | ||||
-rwxr-xr-x | pypers/bolzano/db/mysql/ui/table.html | 23 | ||||
-rwxr-xr-x | pypers/bolzano/db/mysql/ui/x.html | 104 |
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> |