This commit is contained in:
Salvo 'LtWorf' Tomaselli
2015-07-14 11:01:35 +02:00
parent 98ac364dc7
commit 73dd14d9dd
10 changed files with 209 additions and 193 deletions

View File

@@ -151,6 +151,3 @@ class user_interface (object):
str(e)
))
return r

View File

@@ -77,7 +77,9 @@ class TokenizerException (Exception):
class ParserException (Exception):
pass
class CallableString(str):
'''
This is a string. However it is also callable.
@@ -94,7 +96,8 @@ class CallableString(str):
context is a dictionary where to
each name is associated the relative relation
'''
return eval(self,context)
return eval(self, context)
class node (object):
@@ -136,16 +139,16 @@ class node (object):
u"'%s' is not a valid relation name" % self.name)
return
#Expression from right to left, searching for binary operators
#this means that binary operators have lesser priority than
#unary operators.
#It finds the operator with lesser priority, uses it as root of this
#(sub)tree using everything on its left as left parameter (so building
#a left subtree with the part of the list located on left) and doing
#the same on right.
#Since it searches for strings, and expressions into parenthesis are
#within sub-lists, they won't be found here, ensuring that they will
#have highest priority.
# Expression from right to left, searching for binary operators
# this means that binary operators have lesser priority than
# unary operators.
# It finds the operator with lesser priority, uses it as root of this
# (sub)tree using everything on its left as left parameter (so building
# a left subtree with the part of the list located on left) and doing
# the same on right.
# Since it searches for strings, and expressions into parenthesis are
# within sub-lists, they won't be found here, ensuring that they will
# have highest priority.
for i in range(len(expression) - 1, -1, -1):
if expression[i] in b_operators: # Binary operator
self.kind = BINARY
@@ -318,7 +321,7 @@ def tokenize(expression):
items = [] # List for the tokens
#This is a state machine. Initial status is determined by the starting of the
# This is a state machine. Initial status is determined by the starting of the
# expression. There are the following statuses:
#
# relation: this is the status if the expressions begins with something else than an
@@ -327,7 +330,8 @@ def tokenize(expression):
# unary operator: this status is more complex, since it will be followed by a parameter AND a
# sub-expression.
# sub-expression: this status is entered when finding a '(' and will be exited when finding a ')'.
# means that the others open must be counted to determine which close is the right one.'''
# means that the others open must be counted to determine which close is
# the right one.
expression = expression.strip() # Removes initial and endind spaces
state = 0

View File

@@ -101,8 +101,8 @@ class relation (object):
elif self.header.sharedAttributes(other.header) == len(self.header):
return other.projection(self.header)
raise Exception('Relations differ: [%s] [%s]' % (
','.join(self.header) , ','.join(other.header)
))
','.join(self.header), ','.join(other.header)
))
def selection(self, expr):
'''Selection, expr must be a valid boolean expression, can contain field names,
@@ -111,7 +111,9 @@ class relation (object):
newt.header = header(self.header)
for i in self.content:
# Fills the attributes dictionary with the values of the tuple
attributes = {attr:i[j].autocast() for j, attr in enumerate(self.header)}
attributes = {attr: i[j].autocast()
for j, attr in enumerate(self.header)
}
try:
if eval(expr, attributes):
@@ -129,7 +131,8 @@ class relation (object):
if (self.__class__ != other.__class__)or(self.header.sharedAttributes(other.header) != 0):
raise Exception(
'Unable to perform product on relations with colliding attributes')
'Unable to perform product on relations with colliding attributes'
)
newt = relation()
newt.header = header(self.header + other.header)
@@ -277,7 +280,7 @@ class relation (object):
# Creating the header with all the fields, done like that because order is
# needed
h = (i for i in other.header if i not in shared)
newt.header = header(chain(self.header,h))
newt.header = header(chain(self.header, h))
# Shared ids of self
sid = self.header.getAttributesId(shared)
@@ -296,13 +299,13 @@ class relation (object):
match = match and (i[sid[k]] == j[oid[k]])
if match:
item = chain(i,(j[l] for l in noid))
item = chain(i, (j[l] for l in noid))
newt.content.add(tuple(item))
added = True
# If it didn't partecipate, adds it
if not added:
item = chain(i,repeat('---',len(noid)))
item = chain(i, repeat('---', len(noid)))
newt.content.add(tuple(item))
return newt
@@ -319,7 +322,7 @@ class relation (object):
# Creating the header with all the fields, done like that because order is
# needed
h = (i for i in other.header if i not in shared)
newt.header = header(chain(self.header,h))
newt.header = header(chain(self.header, h))
# Shared ids of self
sid = self.header.getAttributesId(shared)
@@ -374,7 +377,7 @@ class relation (object):
col += 1
res = ""
for f,attr in enumerate(self.header):
for f, attr in enumerate(self.header):
res += "%s" % (attr.ljust(2 + m_len[f]))
for r in self.content:
@@ -398,12 +401,11 @@ class relation (object):
affected = 0
attributes = {}
keys = dic.keys() # List of headers to modify
f_ids = self.header.getAttributesId(
keys) # List of indexes corresponding to keys
f_ids = self.header.getAttributesId(keys)
# new_content=[] #New content of the relation
for i in self.content:
for j,attr in enumerate(self.header):
for j, attr in enumerate(self.header):
attributes[attr] = i[j].autocast()
if eval(expr, attributes): # If expr is true, changing the tuple
@@ -445,7 +447,7 @@ class relation (object):
deleting all the tuples that make expr true.
Returns the number of affected rows.'''
#Not necessary self._make_writable()
# Not necessary self._make_writable()
l = len(self.content)
self._readonly = False
@@ -459,7 +461,7 @@ class header(tuple):
It is used within relations to know if requested operations are accepted'''
# Since relations are mutalbe we explicitly block hashing them
def __new__ (cls, fields):
def __new__(cls, fields):
return super(header, cls).__new__(cls, tuple(fields))
def __init__(self, *args, **kwargs):
@@ -481,7 +483,7 @@ class header(tuple):
params is a dictionary of {old:new} names
'''
attrs = list(self)
for old,new in params.items():
for old, new in params.items():
if not is_valid_relation_name(new):
raise Exception('%s is not a valid attribute name' % new)
try:

View File

@@ -25,9 +25,11 @@ import re
RELATION_NAME_REGEXP = r'^[_a-zA-Z]+[_a-zA-Z0-9]*$'
class rstring (str):
'''String subclass with some custom methods'''
def autocast(self):
'''
Returns the automatic cast for this