view roundup/mlink_expr.py @ 6814:3f60a71b0812

Summary: Support selecion session/otk data store. Add redis as data store. Allow admin to select the backend data store. Compatibility matrix: main\/ session>| anydbm | sqlite | redis | mysql | postgresql | anydbm | D | | X | | | sqlite | X | D | X | | | mysql | | | | D | | postgresql | | | | | D | --------------------------------------------------------------+ D - default if unconfigured, X - compatible choice DETAILS roundup/configuration.py: add config.ini section sessiondb with settings: backend and redis_url. CHANGES.txt, doc/admin_guide.txt, doc/installation.txt, doc/upgrading.txt: doc on config of session db and redis. Plus some other fixes: admin - clarified why we do not drop __words and __testids table in native-fts conversion. TYpo fix. upgrading - doc how you can keep using anydbm for session data with sqlite. Fix dupe sentence in an upgrading config.ini section. roundup/backends/back_anydbm.py, roundup/backends/back_sqlite.py: code to support redis, redis/anydbm backends respectively. roundup/backends/sessions_redis.py new storage backend for redis. roundup/rest.py, roundup/cgi/actions.py, roundup/cgi/templating.py redis uses a different way of calculating lifetime/timestamp. Since expiration of an item occurred if its timestamp was more than 1 week old, code would calculate: now - 1 week + lifetime. But this results in faster expiration in redis if used for lifetime/timestamp. Convert code to use the lifetime() method in BasicDatabase that generates the right timestamp for each backend. test/session_common.py: added tests for more cases, get without default, getall non-existing key etc. timestamp test changed to use new self.get_ts which is overridden in other tests. Test that datatypes survive storage. test/test_redis_session.py: test redis session store with sqlite and anydbm primary databases test/test_anydbm.py, test/test_sqlite.py add test to make sure the databases are properly set up sqlite - add test cases where anydbm is used as datastore anydbm - remove updateTimestamp override add get_ts(). test/test_config.py tests on redis_url and compatibility on choice of sessiondb backend .travis.yml: add redis db and redis-py
author John Rouillard <rouilj@ieee.org>
date Thu, 04 Aug 2022 14:41:58 -0400
parents a0c0ee3ed8b1
children 7b090bb35c25
line wrap: on
line source

#
# Copyright: 2010 Intevation GmbH.
#            2021 Ralf Schlatterbeck, rsc@runtux.com.
# 

# This module is Free Software under the Roundup licensing,
# see the COPYING.txt file coming with Roundup.
#

class Binary:

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def visit(self, visitor):
        self.x.visit(visitor)
        self.y.visit(visitor)

class Unary:

    def __init__(self, x):
        self.x = x

    def generate(self, atom):
        return atom(self)

    def visit(self, visitor):
        self.x.visit(visitor)

class Equals(Unary):

    def evaluate(self, v):
        return self.x in v

    def visit(self, visitor):
        visitor(self)

class Empty(Unary):

    def evaluate(self, v):
        return not v

    def visit(self, visitor):
        visitor(self)

class Not(Unary):

    def evaluate(self, v):
        return not self.x.evaluate(v)

    def generate(self, atom):
        return "NOT(%s)" % self.x.generate(atom)

class Or(Binary):

    def evaluate(self, v):
        return self.x.evaluate(v) or self.y.evaluate(v)

    def generate(self, atom):
        return "(%s)OR(%s)" % (
            self.x.generate(atom),
            self.y.generate(atom))

class And(Binary):

    def evaluate(self, v):
        return self.x.evaluate(v) and self.y.evaluate(v)

    def generate(self, atom):
        return "(%s)AND(%s)" % (
            self.x.generate(atom),
            self.y.generate(atom))

def compile_expression(opcodes):

    stack = []
    push, pop = stack.append, stack.pop
    for opcode in opcodes:
        if   opcode == -1: push(Empty(opcode))
        elif opcode == -2: push(Not(pop()))
        elif opcode == -3: push(And(pop(), pop()))
        elif opcode == -4: push(Or(pop(), pop()))
        else:              push(Equals(opcode))

    return pop()

class Expression:

    def __init__(self, v, is_link=False):
        try:
            opcodes = [int(x) for x in v]
            if min(opcodes) >= -1:
                raise ValueError()

            compiled = compile_expression(opcodes)
            if is_link:
                self.evaluate = lambda x: compiled.evaluate(
                    x and [int(x)] or [])
            else:
                self.evaluate = lambda x: compiled.evaluate([int(y) for y in x])
        except:
            if is_link:
                v = [None if x == '-1' else x for x in v]
                self.evaluate = lambda x: x in v
            elif '-1' in v:
                v = [x for x in v if int(x) > 0]
                self.evaluate = lambda x: bool(set(x) & set(v)) or not x
            else:
                self.evaluate = lambda x: bool(set(x) & set(v))

Roundup Issue Tracker: http://roundup-tracker.org/