Changed about and README to not point to galileo anymore

This commit is contained in:
Salvo 'LtWorf' Tomaselli 2013-12-27 00:31:43 +01:00
parent f31d0dea28
commit 556eecc118
25 changed files with 2212 additions and 2023 deletions

7
README
View File

@ -2,6 +2,9 @@ To launch the application, run
./relational_gui.py ./relational_gui.py
If it needs some dependencies, check this page: Language definition is here:
http://galileo.dmi.unict.it/wiki/relational/doku.php?id=download#install https://github.com/ltworf/relational/wiki/Grammar-and-language
If it needs some dependencies:
Qt4, Python 2.7, either PyQT4 or Pyside.

View File

@ -37,6 +37,7 @@ rels={}
examples_path = 'samples/' examples_path = 'samples/'
tests_path = 'test/' tests_path = 'test/'
def readfile(fname): def readfile(fname):
'''Reads a file as string and returns its content''' '''Reads a file as string and returns its content'''
fd = open(fname) fd = open(fname)
@ -60,6 +61,7 @@ def load_relations():
rels[relname] = relation.relation('%s%s' % (examples_path, i)) rels[relname] = relation.relation('%s%s' % (examples_path, i))
print 'done' print 'done'
def execute_tests(): def execute_tests():
py_bad = 0 py_bad = 0
@ -72,7 +74,6 @@ def execute_tests():
ex_good = 0 ex_good = 0
ex_tot = 0 ex_tot = 0
for i in os.listdir(tests_path): for i in os.listdir(tests_path):
if i.endswith('.query'): if i.endswith('.query'):
q_tot += 1 q_tot += 1
@ -112,7 +113,6 @@ def execute_tests():
if ex_bad > 0: if ex_bad > 0:
print colorize("Failed tests count: %d" % ex_bad, COLOR_RED) print colorize("Failed tests count: %d" % ex_bad, COLOR_RED)
print colorize("Total results", COLOR_CYAN) print colorize("Total results", COLOR_CYAN)
if q_bad + py_bad + ex_bad == 0: if q_bad + py_bad + ex_bad == 0:
print colorize("No failed tests", COLOR_GREEN) print colorize("No failed tests", COLOR_GREEN)
@ -137,11 +137,9 @@ def run_exec_test(testname):
expr = readfile('%s%s.exec' % (tests_path, testname)) expr = readfile('%s%s.exec' % (tests_path, testname))
exec(expr, glob) # Evaluating the expression exec(expr, glob) # Evaluating the expression
expr = readfile('%s%s.result' % (tests_path, testname)) expr = readfile('%s%s.result' % (tests_path, testname))
exp_result = eval(expr, rels) # Evaluating the expression exp_result = eval(expr, rels) # Evaluating the expression
if isinstance(exp_result, dict): if isinstance(exp_result, dict):
fields_ok = True fields_ok = True
@ -160,6 +158,7 @@ def run_exec_test(testname):
print colorize('=====================================', COLOR_RED) print colorize('=====================================', COLOR_RED)
return False return False
def run_py_test(testname): def run_py_test(testname):
'''Runs a python test, which evaluates expressions directly rather than queries''' '''Runs a python test, which evaluates expressions directly rather than queries'''
print "Running expression python test: " + colorize(testname, COLOR_MAGENTA) print "Running expression python test: " + colorize(testname, COLOR_MAGENTA)
@ -185,6 +184,7 @@ def run_py_test(testname):
print colorize('=====================================', COLOR_RED) print colorize('=====================================', COLOR_RED)
return False return False
def run_test(testname): def run_test(testname):
'''Runs a specific test executing the file '''Runs a specific test executing the file
testname.query testname.query
@ -194,22 +194,26 @@ def run_test(testname):
optimized''' optimized'''
print "Running test: " + colorize(testname, COLOR_MAGENTA) print "Running test: " + colorize(testname, COLOR_MAGENTA)
query=None;expr=None;o_query=None;o_expr=None query = None
expr = None
o_query = None
o_expr = None
result_rel = None result_rel = None
result = None result = None
o_result = None o_result = None
try: try:
result_rel = relation.relation('%s%s.result' % (tests_path, testname)) result_rel = relation.relation('%s%s.result' % (tests_path, testname))
query=unicode(readfile('%s%s.query' % (tests_path,testname)).strip(),'utf8') query = unicode(
readfile('%s%s.query' % (tests_path, testname)).strip(), 'utf8')
o_query = optimizer.optimize_all(query, rels) o_query = optimizer.optimize_all(query, rels)
expr = parser.parse(query) # Converting expression to python string expr = parser.parse(query) # Converting expression to python string
result = eval(expr, rels) # Evaluating the expression result = eval(expr, rels) # Evaluating the expression
o_expr=parser.parse(o_query)#Converting expression to python string o_expr = parser.parse(
o_query) # Converting expression to python string
o_result = eval(o_expr, rels) # Evaluating the expression o_result = eval(o_expr, rels) # Evaluating the expression
c_expr = parser.tree(query).toCode() # Converting to python code c_expr = parser.tree(query).toCode() # Converting to python code

View File

@ -23,6 +23,7 @@ import httplib
import urllib import urllib
import relation import relation
def send_survey(data): def send_survey(data):
'''Sends the survey. Data must be a dictionary. '''Sends the survey. Data must be a dictionary.
returns the http response''' returns the http response'''
@ -33,14 +34,11 @@ def send_survey(data):
# sends the string # sends the string
params = urllib.urlencode({'survey': post}) params = urllib.urlencode({'survey': post})
headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"} headers = {"Content-type":
#connection = httplib.HTTPConnection('galileo.dmi.unict.it') "application/x-www-form-urlencoded", "Accept": "text/plain"}
#connection.request("POST","/~ltworf/survey.php",params,headers)
connection = httplib.HTTPConnection('feedback-ltworf.appspot.com') connection = httplib.HTTPConnection('feedback-ltworf.appspot.com')
connection.request("POST", "/feedback/relational", params, headers) connection.request("POST", "/feedback/relational", params, headers)
return connection.getresponse() return connection.getresponse()
@ -60,6 +58,7 @@ def check_latest_version():
class interface (object): class interface (object):
'''It is used to provide services to the user interfaces, in order to '''It is used to provide services to the user interfaces, in order to
reduce the amount of duplicated code present in different user interfaces. reduce the amount of duplicated code present in different user interfaces.
''' '''

View File

@ -34,7 +34,9 @@ import parser
from cStringIO import StringIO from cStringIO import StringIO
from tokenize import generate_tokens from tokenize import generate_tokens
sel_op=('//=','**=','and','not','in','//','**','<<','>>','==','!=','>=','<=','+=','-=','*=','/=','%=','or','+','-','*','/','&','|','^','~','<','>','%','=','(',')',',','[',']') sel_op = (
'//=', '**=', 'and', 'not', 'in', '//', '**', '<<', '>>', '==', '!=', '>=', '<=', '+=', '-=',
'*=', '/=', '%=', 'or', '+', '-', '*', '/', '&', '|', '^', '~', '<', '>', '%', '=', '(', ')', ',', '[', ']')
PRODUCT = parser.PRODUCT PRODUCT = parser.PRODUCT
DIFFERENCE = parser.DIFFERENCE DIFFERENCE = parser.DIFFERENCE
@ -64,6 +66,7 @@ def replace_node(replace,replacement):
replace.right = replacement.right replace.right = replacement.right
replace.left = replacement.left replace.left = replacement.left
def recoursive_scan(function, node, rels=None): def recoursive_scan(function, node, rels=None):
'''Does a recoursive optimization on the tree. '''Does a recoursive optimization on the tree.
@ -115,6 +118,7 @@ def duplicated_select(n):
return changes + recoursive_scan(duplicated_select, n) return changes + recoursive_scan(duplicated_select, n)
def futile_union_intersection_subtraction(n): def futile_union_intersection_subtraction(n):
'''This function locates things like r r, and replaces them with r. '''This function locates things like r r, and replaces them with r.
R R --> R R R --> R
@ -170,6 +174,7 @@ def futile_union_intersection_subtraction(n):
return changes + recoursive_scan(futile_union_intersection_subtraction, n) return changes + recoursive_scan(futile_union_intersection_subtraction, n)
def down_to_unions_subtractions_intersections(n): def down_to_unions_subtractions_intersections(n):
'''This funcion locates things like σ i==2 (c d), where the union '''This funcion locates things like σ i==2 (c d), where the union
can be a subtraction and an intersection and replaces them with can be a subtraction and an intersection and replaces them with
@ -200,6 +205,7 @@ def down_to_unions_subtractions_intersections(n):
return changes + recoursive_scan(down_to_unions_subtractions_intersections, n) return changes + recoursive_scan(down_to_unions_subtractions_intersections, n)
def duplicated_projection(n): def duplicated_projection(n):
'''This function locates thing like π i ( π j (R)) and replaces '''This function locates thing like π i ( π j (R)) and replaces
them with π i (R)''' them with π i (R)'''
@ -211,6 +217,7 @@ def duplicated_projection(n):
return changes + recoursive_scan(duplicated_projection, n) return changes + recoursive_scan(duplicated_projection, n)
def selection_inside_projection(n): def selection_inside_projection(n):
'''This function locates things like σ j (π k(R)) and '''This function locates things like σ j (π k(R)) and
converts them into π k(σ j (R))''' converts them into π k(σ j (R))'''
@ -226,6 +233,7 @@ def selection_inside_projection(n):
return changes + recoursive_scan(selection_inside_projection, n) return changes + recoursive_scan(selection_inside_projection, n)
def swap_union_renames(n): def swap_union_renames(n):
'''This function locates things like '''This function locates things like
ρ ab(R) ρ ab(Q) ρ ab(R) ρ ab(Q)
@ -263,6 +271,7 @@ def swap_union_renames(n):
return changes + recoursive_scan(swap_union_renames, n) return changes + recoursive_scan(swap_union_renames, n)
def futile_renames(n): def futile_renames(n):
'''This function purges renames like id->id''' '''This function purges renames like id->id'''
changes = 0 changes = 0
@ -276,7 +285,8 @@ def futile_renames(n):
for i in n.prop.split(','): for i in n.prop.split(','):
q = i.split(ARROW) q = i.split(ARROW)
_vars[q[0].strip()] = q[1].strip() _vars[q[0].strip()] = q[1].strip()
#Scans dictionary to locate things like "a->b,b->c" and replace them with "a->c" # Scans dictionary to locate things like "a->b,b->c" and replace them
# with "a->c"
for key in list(_vars.keys()): for key in list(_vars.keys()):
try: try:
value = _vars[key] value = _vars[key]
@ -297,6 +307,7 @@ def futile_renames(n):
return changes + recoursive_scan(futile_renames, n) return changes + recoursive_scan(futile_renames, n)
def subsequent_renames(n): def subsequent_renames(n):
'''This function removes redoundant subsequent renames joining them into one''' '''This function removes redoundant subsequent renames joining them into one'''
@ -317,7 +328,8 @@ def subsequent_renames(n):
for i in n.prop.split(','): for i in n.prop.split(','):
q = i.split(ARROW) q = i.split(ARROW)
_vars[q[0].strip()] = q[1].strip() _vars[q[0].strip()] = q[1].strip()
#Scans dictionary to locate things like "a->b,b->c" and replace them with "a->c" # Scans dictionary to locate things like "a->b,b->c" and replace them
# with "a->c"
for key in list(_vars.keys()): for key in list(_vars.keys()):
try: try:
value = _vars[key] value = _vars[key]
@ -345,9 +357,11 @@ def subsequent_renames(n):
return changes + recoursive_scan(subsequent_renames, n) return changes + recoursive_scan(subsequent_renames, n)
class level_string(str): class level_string(str):
level = 0 level = 0
def tokenize_select(expression): def tokenize_select(expression):
'''This function returns the list of tokens present in a '''This function returns the list of tokens present in a
selection. The expression can contain parenthesis. selection. The expression can contain parenthesis.
@ -368,7 +382,6 @@ def tokenize_select(expression):
except: except:
pass pass
level = 0 level = 0
for i in range(len(l)): for i in range(len(l)):
l[i] = level_string(l[i]) l[i] = level_string(l[i])
@ -381,6 +394,7 @@ def tokenize_select(expression):
return l return l
def swap_rename_projection(n): def swap_rename_projection(n):
'''This function locates things like π k(ρ j(R)) '''This function locates things like π k(ρ j(R))
and replaces them with ρ j(π k(R)). and replaces them with ρ j(π k(R)).
@ -422,9 +436,9 @@ def swap_rename_projection(n):
n.child.prop += i + ',' n.child.prop += i + ','
n.child.prop = n.child.prop[:-1] n.child.prop = n.child.prop[:-1]
return changes + recoursive_scan(swap_rename_projection, n) return changes + recoursive_scan(swap_rename_projection, n)
def swap_rename_select(n): def swap_rename_select(n):
'''This function locates things like σ k(ρ j(R)) and replaces '''This function locates things like σ k(ρ j(R)) and replaces
them with ρ j(σ k(R)). Renaming the attributes used in the them with ρ j(σ k(R)). Renaming the attributes used in the
@ -449,7 +463,8 @@ def swap_rename_select(n):
if len(splitted) == 1: if len(splitted) == 1:
_tokens[i] = _vars[_tokens[i].split('.')[0]] _tokens[i] = _vars[_tokens[i].split('.')[0]]
else: else:
_tokens[i]=_vars[_tokens[i].split('.')[0]]+'.'+splitted[1] _tokens[i] = _vars[
_tokens[i].split('.')[0]] + '.' + splitted[1]
# Swapping operators # Swapping operators
n.name = RENAME n.name = RENAME
@ -462,6 +477,7 @@ def swap_rename_select(n):
return changes + recoursive_scan(swap_rename_select, n) return changes + recoursive_scan(swap_rename_select, n)
def select_union_intersect_subtract(n): def select_union_intersect_subtract(n):
'''This function locates things like σ i(a) σ q(a) '''This function locates things like σ i(a) σ q(a)
and replaces them with σ (i OR q) (a) and replaces them with σ (i OR q) (a)
@ -498,6 +514,7 @@ def select_union_intersect_subtract(n):
return changes + recoursive_scan(select_union_intersect_subtract, n) return changes + recoursive_scan(select_union_intersect_subtract, n)
def selection_and_product(n, rels): def selection_and_product(n, rels):
'''This function locates things like σ k (R*Q) and converts them into '''This function locates things like σ k (R*Q) and converts them into
σ l (σ j (R) * σ i (Q)). Where j contains only attributes belonging to R, σ l (σ j (R) * σ i (Q)). Where j contains only attributes belonging to R,
@ -597,7 +614,9 @@ def selection_and_product(n,rels):
return changes + recoursive_scan(selection_and_product, n, rels) return changes + recoursive_scan(selection_and_product, n, rels)
general_optimizations=[duplicated_select,down_to_unions_subtractions_intersections,duplicated_projection,selection_inside_projection,subsequent_renames,swap_rename_select,futile_union_intersection_subtraction,swap_union_renames,swap_rename_projection,select_union_intersect_subtract] general_optimizations = [
duplicated_select, down_to_unions_subtractions_intersections, duplicated_projection, selection_inside_projection,
subsequent_renames, swap_rename_select, futile_union_intersection_subtraction, swap_union_renames, swap_rename_projection, select_union_intersect_subtract]
specific_optimizations = [selection_and_product] specific_optimizations = [selection_and_product]
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -43,6 +43,7 @@ tokenize=parser.tokenize
tree = parser.tree tree = parser.tree
# End of the stuff # End of the stuff
def optimize_all(expression, rels, specific=True, general=True, debug=None): def optimize_all(expression, rels, specific=True, general=True, debug=None):
'''This function performs all the available optimizations. '''This function performs all the available optimizations.
@ -73,15 +74,18 @@ def optimize_all(expression,rels,specific=True,general=True,debug=None):
if specific: if specific:
for i in optimizations.specific_optimizations: for i in optimizations.specific_optimizations:
res = i(n, rels) # Performs the optimization res = i(n, rels) # Performs the optimization
if res!=0 and dbg: debug.append(n.__str__()) if res != 0 and dbg:
debug.append(n.__str__())
total += res total += res
if general: if general:
for i in optimizations.general_optimizations: for i in optimizations.general_optimizations:
res = i(n) # Performs the optimization res = i(n) # Performs the optimization
if res!=0 and dbg: debug.append(n.__str__()) if res != 0 and dbg:
debug.append(n.__str__())
total += res total += res
return n.__str__() return n.__str__()
def specific_optimize(expression, rels): def specific_optimize(expression, rels):
'''This function performs specific optimizations. Means that it will need to '''This function performs specific optimizations. Means that it will need to
know the fields used by the relations. know the fields used by the relations.
@ -92,6 +96,7 @@ def specific_optimize(expression,rels):
Return value: this will return an optimized version of the expression''' Return value: this will return an optimized version of the expression'''
return optimize_all(expression, rels, specific=True, general=False) return optimize_all(expression, rels, specific=True, general=False)
def general_optimize(expression): def general_optimize(expression):
'''This function performs general optimizations. Means that it will not need to '''This function performs general optimizations. Means that it will not need to
know the fields used by the relations know the fields used by the relations
@ -110,7 +115,8 @@ if __name__=="__main__":
# a= tokenize(u"π a,b (a*b)") # a= tokenize(u"π a,b (a*b)")
# a=tokenize("(a-b*c)*(b-c)") # a=tokenize("(a-b*c)*(b-c)")
import relation,optimizations import relation
import optimizations
'''rels={} '''rels={}
rels["P1"]= relation.relation("/home/salvo/dev/relational/trunk/samples/people.csv") rels["P1"]= relation.relation("/home/salvo/dev/relational/trunk/samples/people.csv")
@ -132,7 +138,8 @@ if __name__=="__main__":
(π id,name,chief,age (σ chief == i and age > a ((ρ agea,idi (π id,age (people)))*people)))ᐅᐊ(σ skill == 'C' (skills)) (π id,name,chief,age (σ chief == i and age > a ((ρ agea,idi (π id,age (people)))*people)))ᐅᐊ(σ skill == 'C' (skills))
''' '''
#print specific_optimize("σ name==skill and age>21 and id==indice and skill=='C'(P1ᐅᐊS1)",rels) # print specific_optimize("σ name==skill and age>21 and id==indice and
# skill=='C'(P1ᐅᐊS1)",rels)
# print n # print n
# print n.result_format(rels) # print n.result_format(rels)

View File

@ -23,6 +23,7 @@ import optimizer
import multiprocessing import multiprocessing
import parser import parser
def execute(tree, rels): def execute(tree, rels):
'''This funcion executes a query in parallel. '''This funcion executes a query in parallel.
Tree is the tree describing the query (usually obtained with Tree is the tree describing the query (usually obtained with
@ -36,6 +37,7 @@ def execute(tree,rels):
p.join() p.join()
return result return result
def __p_exec__(tree, rels, q): def __p_exec__(tree, rels, q):
'''q is the queue used for communication''' '''q is the queue used for communication'''
if tree.kind == parser.RELATION: if tree.kind == parser.RELATION:
@ -52,10 +54,11 @@ def __p_exec__(tree,rels,q):
q.put(result) q.put(result)
elif tree.kind == parser.BINARY: elif tree.kind == parser.BINARY:
left_q = multiprocessing.Queue() left_q = multiprocessing.Queue()
left_p = multiprocessing.Process(target=__p_exec__, args=(tree.left,rels,left_q,)) left_p = multiprocessing.Process(
target=__p_exec__, args=(tree.left, rels, left_q,))
right_q = multiprocessing.Queue() right_q = multiprocessing.Queue()
right_p = multiprocessing.Process(target=__p_exec__, args=(tree.right,rels,right_q,)) right_p = multiprocessing.Process(
target=__p_exec__, args=(tree.right, rels, right_q,))
# Spawn the children # Spawn the children
left_p.start() left_p.start()
@ -72,6 +75,8 @@ def __p_exec__(tree,rels,q):
result = __p_exec_binary__(tree, left, right) result = __p_exec_binary__(tree, left, right)
q.put(result) q.put(result)
return return
def __p_exec_binary__(tree, left, right): def __p_exec_binary__(tree, left, right):
if tree.name == '*': if tree.name == '*':
return left.product(right) return left.product(right)
@ -92,12 +97,14 @@ def __p_exec_binary__(tree,left,right):
else: # tree.name=='ᐅFULLᐊ': else: # tree.name=='ᐅFULLᐊ':
return left.outer(right) return left.outer(right)
def __p_exec_unary__(tree, rel): def __p_exec_unary__(tree, rel):
if tree.name == 'π': # Projection if tree.name == 'π': # Projection
tree.prop = tree.prop.replace(' ', '').split(',') tree.prop = tree.prop.replace(' ', '').split(',')
result = rel.projection(tree.prop) result = rel.projection(tree.prop)
elif tree.name == "ρ": # Rename elif tree.name == "ρ": # Rename
#tree.prop='{\"%s\"}' % tree.prop.replace(',','\",\"').replace('➡','\":\"').replace(' ','') # tree.prop='{\"%s\"}' %
# tree.prop.replace(',','\",\"').replace('➡','\":\"').replace(' ','')
d = {} d = {}
tree.prop = tree.prop.replace(' ', '') tree.prop = tree.prop.replace(' ', '')
for i in tree.prop.split(','): for i in tree.prop.split(','):
@ -108,4 +115,3 @@ def __p_exec_unary__(tree,rel):
else: # Selection else: # Selection
result = rel.selection(tree.prop) result = rel.selection(tree.prop)
return result return result

View File

@ -61,18 +61,26 @@ SELECTION=u'σ'
RENAME = u'ρ' RENAME = u'ρ'
ARROW = u'' ARROW = u''
b_operators=(PRODUCT,DIFFERENCE,UNION,INTERSECTION,DIVISION,JOIN,JOIN_LEFT,JOIN_RIGHT,JOIN_FULL) # List of binary operators b_operators = (PRODUCT, DIFFERENCE, UNION, INTERSECTION, DIVISION,
JOIN, JOIN_LEFT, JOIN_RIGHT, JOIN_FULL) # List of binary operators
u_operators = (PROJECTION, SELECTION, RENAME) # List of unary operators u_operators = (PROJECTION, SELECTION, RENAME) # List of unary operators
# Associates operator with python method # Associates operator with python method
op_functions={PRODUCT:'product',DIFFERENCE:'difference',UNION:'union',INTERSECTION:'intersection',DIVISION:'division',JOIN:'join',JOIN_LEFT:'outer_left',JOIN_RIGHT:'outer_right',JOIN_FULL:'outer',PROJECTION:'projection',SELECTION:'selection',RENAME:'rename'} op_functions = {
PRODUCT: 'product', DIFFERENCE: 'difference', UNION: 'union', INTERSECTION: 'intersection', DIVISION: 'division', JOIN: 'join',
JOIN_LEFT: 'outer_left', JOIN_RIGHT: 'outer_right', JOIN_FULL: 'outer', PROJECTION: 'projection', SELECTION: 'selection', RENAME: 'rename'}
class TokenizerException (Exception): class TokenizerException (Exception):
pass pass
class ParserException (Exception): class ParserException (Exception):
pass pass
class node (object): class node (object):
'''This class is a node of a relational expression. Leaves are relations and internal nodes are operations. '''This class is a node of a relational expression. Leaves are relations and internal nodes are operations.
The kind property says if the node is a binary operator, unary operator or relation. The kind property says if the node is a binary operator, unary operator or relation.
@ -103,7 +111,8 @@ class node (object):
self.kind = RELATION self.kind = RELATION
self.name = expression[0] self.name = expression[0]
if not rtypes.is_valid_relation_name(self.name): if not rtypes.is_valid_relation_name(self.name):
raise ParserException(u"'%s' is not a valid relation name" % self.name) raise ParserException(
u"'%s' is not a valid relation name" % self.name)
return return
'''Expression from right to left, searching for binary operators '''Expression from right to left, searching for binary operators
@ -122,10 +131,12 @@ class node (object):
self.name = expression[i] self.name = expression[i]
if len(expression[:i]) == 0: if len(expression[:i]) == 0:
raise ParserException(u"Expected left operand for '%s'" % self.name) raise ParserException(
u"Expected left operand for '%s'" % self.name)
if len(expression[i + 1:]) == 0: if len(expression[i + 1:]) == 0:
raise ParserException(u"Expected right operand for '%s'" % self.name) raise ParserException(
u"Expected right operand for '%s'" % self.name)
self.left = node(expression[:i]) self.left = node(expression[:i])
self.right = node(expression[i + 1:]) self.right = node(expression[i + 1:])
@ -137,7 +148,8 @@ class node (object):
self.name = expression[i] self.name = expression[i]
if len(expression) <= i + 2: if len(expression) <= i + 2:
raise ParserException(u"Expected more tokens in '%s'"%self.name) raise ParserException(
u"Expected more tokens in '%s'" % self.name)
self.prop = expression[1 + i].strip() self.prop = expression[1 + i].strip()
self.child = node(expression[2 + i]) self.child = node(expression[2 + i])
@ -145,6 +157,7 @@ class node (object):
return return
raise ParserException(u"Unable to parse tokens") raise ParserException(u"Unable to parse tokens")
pass pass
def toCode(self): def toCode(self):
'''This method converts the tree into a python code object''' '''This method converts the tree into a python code object'''
code = self.toPython() code = self.toPython()
@ -162,7 +175,8 @@ class node (object):
if self.name == PROJECTION: if self.name == PROJECTION:
prop = '\"%s\"' % prop.replace(' ', '').replace(',', '\",\"') prop = '\"%s\"' % prop.replace(' ', '').replace(',', '\",\"')
elif self.name == RENAME: elif self.name == RENAME:
prop='{\"%s\"}' % prop.replace(',','\",\"').replace(ARROW,'\":\"').replace(' ','') prop = '{\"%s\"}' % prop.replace(
',', '\",\"').replace(ARROW, '\":\"').replace(' ', '')
else: # Selection else: # Selection
prop = '\"%s\"' % prop prop = '\"%s\"' % prop
@ -170,6 +184,7 @@ class node (object):
else: else:
return self.name return self.name
pass pass
def printtree(self, level=0): def printtree(self, level=0):
'''returns a representation of the tree using indentation''' '''returns a representation of the tree using indentation'''
r = '' r = ''
@ -184,6 +199,7 @@ class node (object):
r += self.child.printtree(level + 1) r += self.child.printtree(level + 1)
return '\n' + r return '\n' + r
def get_left_leaf(self): def get_left_leaf(self):
'''This function returns the leftmost leaf in the tree. It is needed by some optimizations.''' '''This function returns the leftmost leaf in the tree. It is needed by some optimizations.'''
if self.kind == RELATION: if self.kind == RELATION:
@ -193,7 +209,6 @@ class node (object):
elif self.kind == BINARY: elif self.kind == BINARY:
return self.left.get_left_leaf() return self.left.get_left_leaf()
def result_format(self, rels): def result_format(self, rels):
'''This function returns a list containing the fields that the resulting relation will have. '''This function returns a list containing the fields that the resulting relation will have.
It requires a dictionary where keys are the names of the relations and the values are It requires a dictionary where keys are the names of the relations and the values are
@ -229,6 +244,7 @@ class node (object):
return _fields return _fields
elif self.name in (JOIN, JOIN_LEFT, JOIN_RIGHT, JOIN_FULL): elif self.name in (JOIN, JOIN_LEFT, JOIN_RIGHT, JOIN_FULL):
return list(set(self.left.result_format(rels)).union(set(self.right.result_format(rels)))) return list(set(self.left.result_format(rels)).union(set(self.right.result_format(rels))))
def __eq__(self, other): def __eq__(self, other):
if not (isinstance(other, node) and self.name == other.name and self.kind == other.kind): if not (isinstance(other, node) and self.name == other.name and self.kind == other.kind):
return False return False
@ -258,6 +274,7 @@ class node (object):
return (le + self.name + re) return (le + self.name + re)
def _find_matching_parenthesis(expression, start=0, openpar=u'(', closepar=u')'): def _find_matching_parenthesis(expression, start=0, openpar=u'(', closepar=u')'):
'''This function returns the position of the matching '''This function returns the position of the matching
close parenthesis to the 1st open parenthesis found close parenthesis to the 1st open parenthesis found
@ -271,6 +288,7 @@ def _find_matching_parenthesis(expression,start=0,openpar=u'(',closepar=u')'):
if par_count == 0: if par_count == 0:
return i # Closing parenthesis of the parameter return i # Closing parenthesis of the parameter
def tokenize(expression): def tokenize(expression):
'''This function converts an expression into a list where '''This function converts an expression into a list where
every token of the expression is an item of a list. Expressions into every token of the expression is an item of a list. Expressions into
@ -307,23 +325,29 @@ def tokenize(expression):
state = 2 state = 2
end = _find_matching_parenthesis(expression) end = _find_matching_parenthesis(expression)
if end == None: if end == None:
raise TokenizerException("Missing matching ')' in '%s'" %expression) raise TokenizerException(
"Missing matching ')' in '%s'" % expression)
# Appends the tokenization of the content of the parenthesis # Appends the tokenization of the content of the parenthesis
items.append(tokenize(expression[1:end])) items.append(tokenize(expression[1:end]))
# Removes the entire parentesis and content from the expression # Removes the entire parentesis and content from the expression
expression = expression[end + 1:].strip() expression = expression[end + 1:].strip()
elif expression.startswith((u"σ", u"π", u"ρ")): # Unary 2 bytes elif expression.startswith((u"σ", u"π", u"ρ")): # Unary 2 bytes
items.append(expression[0:1]) #Adding operator in the top of the list items.append(expression[0:1])
expression=expression[1:].strip() #Removing operator from the expression #Adding operator in the top of the list
expression = expression[
1:].strip() # Removing operator from the expression
if expression.startswith('('): # Expression with parenthesis, so adding what's between open and close without tokenization if expression.startswith('('): # Expression with parenthesis, so adding what's between open and close without tokenization
par=expression.find('(',_find_matching_parenthesis(expression)) par = expression.find(
'(', _find_matching_parenthesis(expression))
else: # Expression without parenthesis, so adding what's between start and parenthesis as whole else: # Expression without parenthesis, so adding what's between start and parenthesis as whole
par = expression.find('(') par = expression.find('(')
items.append(expression[:par].strip()) #Inserting parameter of the operator items.append(expression[:par].strip())
expression=expression[par:].strip() #Removing parameter from the expression #Inserting parameter of the operator
expression = expression[
par:].strip() # Removing parameter from the expression
elif expression.startswith((u"÷", u"", u"", u"*", u"-")): elif expression.startswith((u"÷", u"", u"", u"*", u"-")):
items.append(expression[0]) items.append(expression[0])
expression = expression[1:].strip() # 1 char from the expression expression = expression[1:].strip() # 1 char from the expression
@ -336,26 +360,29 @@ def tokenize(expression):
expression = expression[i + 1:].strip() expression = expression[i + 1:].strip()
state = 4 state = 4
elif re.match(r'[_0-9A-Za-z]', expression[0]) == None: # At this point we only have relation names, so we raise errors for anything else elif re.match(r'[_0-9A-Za-z]', expression[0]) == None: # At this point we only have relation names, so we raise errors for anything else
raise TokenizerException("Unexpected '%c' in '%s'" % (expression[0],expression)) raise TokenizerException(
"Unexpected '%c' in '%s'" % (expression[0], expression))
else: # Relation (hopefully) else: # Relation (hopefully)
if state == 1: # Previous was a relation, appending to the last token if state == 1: # Previous was a relation, appending to the last token
i = items.pop() i = items.pop()
items.append(i + expression[0]) items.append(i + expression[0])
expression=expression[1:].strip() #1 char from the expression expression = expression[
1:].strip() # 1 char from the expression
else: else:
state = 1 state = 1
items.append(expression[0]) items.append(expression[0])
expression=expression[1:].strip() #1 char from the expression expression = expression[
1:].strip() # 1 char from the expression
return items return items
def tree(expression): def tree(expression):
'''This function parses a relational algebra expression into a tree and returns '''This function parses a relational algebra expression into a tree and returns
the root node using the Node class defined in this module.''' the root node using the Node class defined in this module.'''
return node(tokenize(expression)) return node(tokenize(expression))
def parse(expr): def parse(expr):
'''This function parses a relational algebra expression, converting it into python, '''This function parses a relational algebra expression, converting it into python,
executable by eval function to get the result of the expression. executable by eval function to get the result of the expression.

View File

@ -21,10 +21,13 @@
import parser import parser
class TypeException(Exception): class TypeException(Exception):
pass pass
class Query(object): class Query(object):
def __init__(self, query): def __init__(self, query):
if not isinstance(query, unicode): if not isinstance(query, unicode):

View File

@ -23,7 +23,9 @@
from rtypes import * from rtypes import *
import csv import csv
class relation (object): class relation (object):
'''This objects defines a relation (as a group of consistent tuples) and operations '''This objects defines a relation (as a group of consistent tuples) and operations
A relation can be represented using a table A relation can be represented using a table
Calling an operation and providing a non relation parameter when it is expected will Calling an operation and providing a non relation parameter when it is expected will
@ -122,8 +124,10 @@ class relation (object):
if eval(expr, attributes): if eval(expr, attributes):
newt.content.add(i) newt.content.add(i)
except Exception, e: except Exception, e:
raise Exception("Failed to evaluate %s\n%s" % (expr,e.__str__())) raise Exception(
"Failed to evaluate %s\n%s" % (expr, e.__str__()))
return newt return newt
def product(self, other): def product(self, other):
'''Cartesian product, attributes must be different to avoid collisions '''Cartesian product, attributes must be different to avoid collisions
Doing this operation on relations with colliding attributes will Doing this operation on relations with colliding attributes will
@ -131,7 +135,8 @@ class relation (object):
It is possible to use rename on attributes and then use the product''' It is possible to use rename on attributes and then use the product'''
if (self.__class__ != other.__class__)or(self.header.sharedAttributes(other.header) != 0): if (self.__class__ != other.__class__)or(self.header.sharedAttributes(other.header) != 0):
raise Exception('Unable to perform product on relations with colliding attributes') raise Exception(
'Unable to perform product on relations with colliding attributes')
newt = relation() newt = relation()
newt.header = header(self.header.attributes + other.header.attributes) newt.header = header(self.header.attributes + other.header.attributes)
@ -140,7 +145,6 @@ class relation (object):
newt.content.add(i + j) newt.content.add(i + j)
return newt return newt
def projection(self, * attributes): def projection(self, * attributes):
'''Projection operator, takes many parameters, for each field to use. '''Projection operator, takes many parameters, for each field to use.
Can also use a single parameter with a list. Can also use a single parameter with a list.
@ -202,7 +206,8 @@ class relation (object):
It is possible to use projection and rename to make headers match.''' It is possible to use projection and rename to make headers match.'''
other = self._rearrange_(other) # Rearranges attributes' order other = self._rearrange_(other) # Rearranges attributes' order
if (self.__class__ != other.__class__)or(self.header != other.header): if (self.__class__ != other.__class__)or(self.header != other.header):
raise Exception('Unable to perform intersection on relations with different attributes') raise Exception(
'Unable to perform intersection on relations with different attributes')
newt = relation() newt = relation()
newt.header = header(list(self.header.attributes)) newt.header = header(list(self.header.attributes))
@ -217,12 +222,14 @@ class relation (object):
It is possible to use projection and rename to make headers match.''' It is possible to use projection and rename to make headers match.'''
other = self._rearrange_(other) # Rearranges attributes' order other = self._rearrange_(other) # Rearranges attributes' order
if (self.__class__ != other.__class__)or(self.header != other.header): if (self.__class__ != other.__class__)or(self.header != other.header):
raise Exception('Unable to perform difference on relations with different attributes') raise Exception(
'Unable to perform difference on relations with different attributes')
newt = relation() newt = relation()
newt.header = header(list(self.header.attributes)) newt.header = header(list(self.header.attributes))
newt.content = self.content.difference(other.content) newt.content = self.content.difference(other.content)
return newt return newt
def division(self, other): def division(self, other):
'''Division operator '''Division operator
The division is a binary operation that is written as R ÷ S. The The division is a binary operation that is written as R ÷ S. The
@ -233,8 +240,8 @@ class relation (object):
''' '''
# d_headers are the headers from self that aren't also headers in other # d_headers are the headers from self that aren't also headers in other
d_headers=list(set(self.header.attributes) - set(other.header.attributes)) d_headers = list(
set(self.header.attributes) - set(other.header.attributes))
''' '''
Wikipedia defines the division as follows: Wikipedia defines the division as follows:
@ -261,12 +268,14 @@ class relation (object):
It is possible to use projection and rename to make headers match.''' It is possible to use projection and rename to make headers match.'''
other = self._rearrange_(other) # Rearranges attributes' order other = self._rearrange_(other) # Rearranges attributes' order
if (self.__class__ != other.__class__)or(self.header != other.header): if (self.__class__ != other.__class__)or(self.header != other.header):
raise Exception('Unable to perform union on relations with different attributes') raise Exception(
'Unable to perform union on relations with different attributes')
newt = relation() newt = relation()
newt.header = header(list(self.header.attributes)) newt.header = header(list(self.header.attributes))
newt.content = self.content.union(other.content) newt.content = self.content.union(other.content)
return newt return newt
def thetajoin(self, other, expr): def thetajoin(self, other, expr):
'''Defined as product and then selection with the given expression.''' '''Defined as product and then selection with the given expression.'''
return self.product(other).selection(expr) return self.product(other).selection(expr)
@ -347,11 +356,13 @@ class relation (object):
shared attributes, it will behave as cartesian product.''' shared attributes, it will behave as cartesian product.'''
# List of attributes in common between the relations # List of attributes in common between the relations
shared=list(set(self.header.attributes).intersection(set(other.header.attributes))) shared = list(set(self.header.attributes)
.intersection(set(other.header.attributes)))
newt = relation() # Creates the new relation newt = relation() # Creates the new relation
#Adding to the headers all the fields, done like that because order is needed # Adding to the headers all the fields, done like that because order is
# needed
newt.header = header(list(self.header.attributes)) newt.header = header(list(self.header.attributes))
for i in other.header.attributes: for i in other.header.attributes:
if i not in shared: if i not in shared:
@ -382,10 +393,12 @@ class relation (object):
newt.content.add(tuple(item)) newt.content.add(tuple(item))
return newt return newt
def __eq__(self, other): def __eq__(self, other):
'''Returns true if the relations are the same, ignoring order of items. '''Returns true if the relations are the same, ignoring order of items.
This operation is rather heavy, since it requires sorting and comparing.''' This operation is rather heavy, since it requires sorting and comparing.'''
other=self._rearrange_(other) #Rearranges attributes' order so can compare tuples directly other = self._rearrange_(
other) # Rearranges attributes' order so can compare tuples directly
if (self.__class__ != other.__class__)or(self.header != other.header): if (self.__class__ != other.__class__)or(self.header != other.header):
return False # Both parameters must be a relation return False # Both parameters must be a relation
@ -393,8 +406,6 @@ class relation (object):
if set(self.header.attributes) != set(other.header.attributes): if set(self.header.attributes) != set(other.header.attributes):
return False return False
# comparing content # comparing content
return self.content == other.content return self.content == other.content
@ -416,7 +427,6 @@ class relation (object):
for f in range(len(self.header.attributes)): for f in range(len(self.header.attributes)):
res += "%s" % (self.header.attributes[f].ljust(2 + m_len[f])) res += "%s" % (self.header.attributes[f].ljust(2 + m_len[f]))
for r in self.content: for r in self.content:
col = 0 col = 0
res += "\n" res += "\n"
@ -438,7 +448,8 @@ class relation (object):
affected = 0 affected = 0
attributes = {} attributes = {}
keys = dic.keys() # List of headers to modify 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) # List of indexes corresponding to keys
# new_content=[] #New content of the relation # new_content=[] #New content of the relation
for i in self.content: for i in self.content:
@ -492,14 +503,15 @@ class relation (object):
for j in range(len(self.header.attributes)): for j in range(len(self.header.attributes)):
attributes[self.header.attributes[j]] = self._autocast(i[j]) attributes[self.header.attributes[j]] = self._autocast(i[j])
if not eval(expr, attributes): if not eval(expr, attributes):
affected -= 1 affected -= 1
new_content.add(i) new_content.add(i)
self.content = new_content self.content = new_content
return affected return affected
class header (object): class header (object):
'''This class defines the header of a relation. '''This class defines the header of a relation.
It is used within relations to know if requested operations are accepted''' It is used within relations to know if requested operations are accepted'''
@ -517,7 +529,6 @@ class header (object):
def __repr__(self): def __repr__(self):
return "header(%s)" % (self.attributes.__repr__()) return "header(%s)" % (self.attributes.__repr__())
def rename(self, old, new): def rename(self, old, new):
'''Renames a field. Doesn't check if it is a duplicate. '''Renames a field. Doesn't check if it is a duplicate.
Returns True if the field was renamed, False otherwise''' Returns True if the field was renamed, False otherwise'''
@ -542,6 +553,7 @@ class header (object):
def __eq__(self, other): def __eq__(self, other):
return self.attributes == other.attributes return self.attributes == other.attributes
def __ne__(self, other): def __ne__(self, other):
return self.attributes != other.attributes return self.attributes != other.attributes
@ -553,4 +565,3 @@ class header (object):
if i == self.attributes[j]: if i == self.attributes[j]:
res.append(j) res.append(j)
return res return res

View File

@ -24,8 +24,11 @@
import datetime import datetime
import re import re
class rstring (str): class rstring (str):
'''String subclass with some custom methods''' '''String subclass with some custom methods'''
def isInt(self): def isInt(self):
'''Returns true if the string represents an int number '''Returns true if the string represents an int number
it only considers as int numbers the strings matching it only considers as int numbers the strings matching
@ -36,6 +39,7 @@ class rstring (str):
return False return False
else: else:
return True return True
def isFloat(self): def isFloat(self):
'''Returns true if the string represents a float number '''Returns true if the string represents a float number
it only considers as float numbers, the strings matching it only considers as float numbers, the strings matching
@ -58,7 +62,8 @@ class rstring (str):
except: except:
pass pass
r= re.match(r'^([0-9]{1,4})(\\|-|/)([0-9]{1,2})(\\|-|/)([0-9]{1,2})$',self) r = re.match(
r'^([0-9]{1,4})(\\|-|/)([0-9]{1,2})(\\|-|/)([0-9]{1,2})$', self)
if r == None: if r == None:
self._isdate = False self._isdate = False
self._date = None self._date = None
@ -84,8 +89,12 @@ class rstring (str):
except: except:
self.isDate() self.isDate()
return self._date return self._date
class rdate (object): class rdate (object):
'''Represents a date''' '''Represents a date'''
def __init__(self, date): def __init__(self, date):
'''date: A string representing a date''' '''date: A string representing a date'''
if not isinstance(date, rstring): if not isinstance(date, rstring):
@ -99,23 +108,32 @@ class rdate (object):
def __hash__(self): def __hash__(self):
return self.intdate.__hash__() return self.intdate.__hash__()
def __str__(self): def __str__(self):
return self.intdate.__str__() return self.intdate.__str__()
def __add__(self, days): def __add__(self, days):
res = self.intdate + datetime.timedelta(days) res = self.intdate + datetime.timedelta(days)
return rdate(res.__str__()) return rdate(res.__str__())
def __eq__(self, other): def __eq__(self, other):
return self.intdate == other.intdate return self.intdate == other.intdate
def __ge__(self, other): def __ge__(self, other):
return self.intdate >= other.intdate return self.intdate >= other.intdate
def __gt__(self, other): def __gt__(self, other):
return self.intdate > other.intdate return self.intdate > other.intdate
def __le__(self, other): def __le__(self, other):
return self.intdate <= other.intdate return self.intdate <= other.intdate
def __lt__(self, other): def __lt__(self, other):
return self.intdate < other.intdate return self.intdate < other.intdate
def __ne__(self, other): def __ne__(self, other):
return self.intdate != other.intdate return self.intdate != other.intdate
def __sub__(self, other): def __sub__(self, other):
return (self.intdate - other.intdate).days return (self.intdate - other.intdate).days

View File

@ -23,6 +23,7 @@ import signal
import sys import sys
from relational import * from relational import *
def terminate(*a): def terminate(*a):
'''Restores the terminal and terminates''' '''Restores the terminal and terminates'''
curses.nocbreak() curses.nocbreak()
@ -32,6 +33,7 @@ def terminate(*a):
sys.exit(0) sys.exit(0)
def main(): def main():
global stdscr global stdscr
# Initializes the signal # Initializes the signal
@ -52,15 +54,11 @@ def main():
win = curses.panel.new_panel(curses.newwin(termsize[0], termsize[1])) win = curses.panel.new_panel(curses.newwin(termsize[0], termsize[1]))
# win.window().box() # win.window().box()
win.window().addstr(0, (termsize[1] / 2) - 5, "Relational") win.window().addstr(0, (termsize[1] / 2) - 5, "Relational")
win.window().refresh() win.window().refresh()
# curses.napms(1000) # curses.napms(1000)
query = curses.panel.new_panel(curses.newwin(3, termsize[1], 1, 0)) query = curses.panel.new_panel(curses.newwin(3, termsize[1], 1, 0))
query.window().box() query.window().box()
query.window().addstr(1, 1, "") query.window().addstr(1, 1, "")
@ -71,9 +69,7 @@ def main():
# curses.napms(1000) # curses.napms(1000)
# qq=curses.textpad.Textbox(stdscr) # qq=curses.textpad.Textbox(stdscr)
'''win = curses.newwin(0, 0)#New windows for the entire screen '''win = curses.newwin(0, 0)#New windows for the entire screen
#stdscr.border(0) #stdscr.border(0)
stdscr.addstr(str(dir (win))) stdscr.addstr(str(dir (win)))
@ -97,13 +93,11 @@ def main():
if c == 27: # Escape if c == 27: # Escape
squery += add_symbol(symselect) squery += add_symbol(symselect)
# elif c==curses.KEY_BACKSPACE: #Delete # elif c==curses.KEY_BACKSPACE: #Delete
elif c == 13: elif c == 13:
squery = squery[:-1] squery = squery[:-1]
else: else:
squery+=chr(c); squery += chr(c)
query.window().box() query.window().box()
query.top() query.top()
@ -111,10 +105,13 @@ def main():
query.window().addstr(1, 1, squery) query.window().addstr(1, 1, squery)
query.window().refresh() query.window().refresh()
def init_symbol_list(termsize, create=True): def init_symbol_list(termsize, create=True):
if create: if create:
p=curses.panel.new_panel(curses.newwin(15,16,2,termsize[1]/2-7)) p = curses.panel.new_panel(
curses.newwin(15, 16, 2, termsize[1] / 2 - 7))
else: else:
p = termsize p = termsize
p.window().box() p.window().box()
@ -135,13 +132,15 @@ def init_symbol_list(termsize,create=True):
# p.hide() # p.hide()
return p return p
def add_symbol(p): def add_symbol(p):
'''Shows the panel to add a symbol '''Shows the panel to add a symbol
and then returns the choosen symbol itself''' and then returns the choosen symbol itself'''
init_symbol_list(p, False) init_symbol_list(p, False)
d_={'0':'*','1':'-','2':'','3':'','4':'ᐅᐊ','5':'ᐅLEFTᐊ','6':'ᐅRIGHTᐊ','7':'ᐅFULLᐊ','8':'σ','9':'ρ','a':'π','b':''} d_ = {'0': '*', '1': '-', '2': '', '3': '', '4': 'ᐅᐊ', '5': 'ᐅLEFTᐊ',
'6': 'ᐅRIGHTᐊ', '7': 'ᐅFULLᐊ', '8': 'σ', '9': 'ρ', 'a': 'π', 'b': ''}
p.show() p.show()
p.top() p.top()
@ -156,6 +155,7 @@ def add_symbol(p):
char = '' char = ''
return char return char
def spaces(t): def spaces(t):
'''Returns a number of spaces specified t''' '''Returns a number of spaces specified t'''
s = '' s = ''

View File

@ -42,6 +42,7 @@ def printver(exit=True):
if exit: if exit:
sys.exit(0) sys.exit(0)
def printhelp(code=0): def printhelp(code=0):
print "Relational" print "Relational"
print print
@ -92,7 +93,6 @@ if __name__ == "__main__":
from PySide import QtCore, QtGui from PySide import QtCore, QtGui
pyqt = False pyqt = False
if pyqt: if pyqt:
try: try:
from relational_gui import maingui, guihandler, about, surveyForm from relational_gui import maingui, guihandler, about, surveyForm
@ -106,14 +106,13 @@ if __name__ == "__main__":
print >> sys.stderr, "Module relational_pyside is missing.\nPlease install relational package." print >> sys.stderr, "Module relational_pyside is missing.\nPlease install relational package."
sys.exit(3) sys.exit(3)
about.version = version about.version = version
surveyForm.version = version surveyForm.version = version
guihandler.version = version guihandler.version = version
app = QtGui.QApplication(sys.argv) app = QtGui.QApplication(sys.argv)
app.setOrganizationName('None'); app.setOrganizationName('None')
app.setApplicationName('relational'); app.setApplicationName('relational')
ui = maingui.Ui_MainWindow() ui = maingui.Ui_MainWindow()
Form = guihandler.relForm(ui) Form = guihandler.relForm(ui)
@ -146,4 +145,3 @@ if __name__ == "__main__":
sys.exit(3) sys.exit(3)
relational_readline.linegui.version = version relational_readline.linegui.version = version
relational_readline.linegui.main(files) relational_readline.linegui.main(files)

View File

@ -37,7 +37,9 @@ except:
version = 0 version = 0
class Ui_Dialog(object): class Ui_Dialog(object):
def setupUi(self, Dialog): def setupUi(self, Dialog):
Dialog.setObjectName("Dialog") Dialog.setObjectName("Dialog")
Dialog.resize(510, 453) Dialog.resize(510, 453)
@ -96,14 +98,16 @@ class Ui_Dialog(object):
self.verticalLayout_7.setObjectName("verticalLayout_7") self.verticalLayout_7.setObjectName("verticalLayout_7")
if (webk): if (webk):
self.webView = QtWebKit.QWebView(self.tab_2) self.webView = QtWebKit.QWebView(self.tab_2)
self.webView.setUrl(QtCore.QUrl("http://galileo.dmi.unict.it/wiki/relational/doku.php")) self.webView.setUrl(
QtCore.QUrl("https://github.com/ltworf/relational/wiki/Grammar-and-language"))
self.webView.setObjectName("webView") self.webView.setObjectName("webView")
self.verticalLayout_7.addWidget(self.webView) self.verticalLayout_7.addWidget(self.webView)
else: else:
self.webLink = QtGui.QLabel(self.groupBox) self.webLink = QtGui.QLabel(self.groupBox)
self.webLink.setFont(font) self.webLink.setFont(font)
self.webLink.setObjectName("lblLink") self.webLink.setObjectName("lblLink")
self.webLink.setText(QtGui.QApplication.translate("Dialog", "<a href=\"http://galileo.dmi.unict.it/wiki/relational/\">Relational's website</a>", None,)) self.webLink.setText(QtGui.QApplication.translate(
"Dialog", "<a href=\"https://github.com/ltworf/relational\">Relational's website</a>", None,))
self.webLink.setOpenExternalLinks(True) self.webLink.setOpenExternalLinks(True)
self.webLink.setTextFormat(QtCore.Qt.AutoText) self.webLink.setTextFormat(QtCore.Qt.AutoText)
self.webLink.setTextInteractionFlags( self.webLink.setTextInteractionFlags(
@ -126,24 +130,39 @@ class Ui_Dialog(object):
self.retranslateUi(Dialog) self.retranslateUi(Dialog)
self.tabWidget.setCurrentIndex(0) self.tabWidget.setCurrentIndex(0)
QtCore.QObject.connect(self.buttonBox,QtCore.SIGNAL("accepted()"),Dialog.accept) QtCore.QObject.connect(
QtCore.QObject.connect(self.buttonBox,QtCore.SIGNAL("rejected()"),Dialog.reject) self.buttonBox, QtCore.SIGNAL("accepted()"), Dialog.accept)
QtCore.QObject.connect(
self.buttonBox, QtCore.SIGNAL("rejected()"), Dialog.reject)
QtCore.QMetaObject.connectSlotsByName(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog): def retranslateUi(self, Dialog):
Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Documentation", None, QtGui.QApplication.UnicodeUTF8)) Dialog.setWindowTitle(QtGui.QApplication.translate(
self.groupBox.setTitle(QtGui.QApplication.translate("Dialog", "Relational", None, QtGui.QApplication.UnicodeUTF8)) "Dialog", "Documentation", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("Dialog", "Relational", None, QtGui.QApplication.UnicodeUTF8)) self.groupBox.setTitle(QtGui.QApplication.translate(
self.label_3.setText(QtGui.QApplication.translate("Dialog", "Version "+version, None, QtGui.QApplication.UnicodeUTF8)) "Dialog", "Relational", None, QtGui.QApplication.UnicodeUTF8))
self.label_3.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) self.label.setText(QtGui.QApplication.translate(
self.groupBox_3.setTitle(QtGui.QApplication.translate("Dialog", "Author", None, QtGui.QApplication.UnicodeUTF8)) "Dialog", "Relational", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("Dialog", "Salvo \"LtWorf\" Tomaselli &lt;<a href=\"mailto:tiposchi@tiscali.it\">tiposchi@tiscali.it</a>&gt;<br>Emilio Di Prima &lt;emiliodiprima[at]msn[dot]com&gt; (For the windows setup)", None, QtGui.QApplication.UnicodeUTF8)) self.label_3.setText(QtGui.QApplication.translate(
"Dialog", "Version " + version, None, QtGui.QApplication.UnicodeUTF8))
self.label_3.setTextInteractionFlags(
QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextSelectableByMouse)
self.groupBox_3.setTitle(QtGui.QApplication.translate(
"Dialog", "Author", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate(
"Dialog", "Salvo \"LtWorf\" Tomaselli &lt;<a href=\"mailto:tiposchi@tiscali.it\">tiposchi@tiscali.it</a>&gt;<br>Emilio Di Prima &lt;emiliodiprima[at]msn[dot]com&gt; (For the windows setup)", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setOpenExternalLinks(True) self.label_2.setOpenExternalLinks(True)
self.label_2.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) self.label_2.setTextInteractionFlags(
self.groupBox_2.setTitle(QtGui.QApplication.translate("Dialog", "Links", None, QtGui.QApplication.UnicodeUTF8)) QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextSelectableByMouse)
self.label_4.setText(QtGui.QApplication.translate("Dialog", "<a href=\"http://galileo.dmi.unict.it/wiki/relational/\">http://galileo.dmi.unict.it/wiki/relational/</a>", None, QtGui.QApplication.UnicodeUTF8)) self.groupBox_2.setTitle(QtGui.QApplication.translate(
"Dialog", "Links", None, QtGui.QApplication.UnicodeUTF8))
self.label_4.setText(QtGui.QApplication.translate(
"Dialog", "<a href=\"https://github.com/ltworf/relational/\">https://github.com/ltworf/relational/</a>", None, QtGui.QApplication.UnicodeUTF8))
self.label_4.setOpenExternalLinks(True) self.label_4.setOpenExternalLinks(True)
self.label_4.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) self.label_4.setTextInteractionFlags(
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), QtGui.QApplication.translate("Dialog", "About", None, QtGui.QApplication.UnicodeUTF8)) QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextSelectableByMouse)
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), QtGui.QApplication.translate(
"Dialog", "About", None, QtGui.QApplication.UnicodeUTF8))
self.textEdit.setHtml(QtGui.QApplication.translate("Dialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" self.textEdit.setHtml(QtGui.QApplication.translate("Dialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><title>GNU General Public License - GNU Project - Free Software Foundation (FSF)</title><style type=\"text/css\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><title>GNU General Public License - GNU Project - Free Software Foundation (FSF)</title><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n" "p, li { white-space: pre-wrap; }\n"
@ -286,9 +305,10 @@ class Ui_Dialog(object):
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">The hypothetical commands `show w\' and `show c\' should show the appropriate parts of the General Public License. Of course, your program\'s commands might be different; for a GUI interface, you would use an “about box”. </p>\n" "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">The hypothetical commands `show w\' and `show c\' should show the appropriate parts of the General Public License. Of course, your program\'s commands might be different; for a GUI interface, you would use an “about box”. </p>\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see &lt;http://www.gnu.org/licenses/&gt;. </p>\n" "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see &lt;http://www.gnu.org/licenses/&gt;. </p>\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read &lt;http://www.gnu.org/philosophy/why-not-lgpl.html&gt;. </p></body></html>", None, QtGui.QApplication.UnicodeUTF8)) "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read &lt;http://www.gnu.org/philosophy/why-not-lgpl.html&gt;. </p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.License), QtGui.QApplication.translate("Dialog", "License", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.License), QtGui.QApplication.translate(
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), QtGui.QApplication.translate("Dialog", "Docs", None, QtGui.QApplication.UnicodeUTF8)) "Dialog", "License", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), QtGui.QApplication.translate(
"Dialog", "Docs", None, QtGui.QApplication.UnicodeUTF8))
if __name__ == "__main__": if __name__ == "__main__":
@ -299,4 +319,3 @@ if __name__ == "__main__":
ui.setupUi(Dialog) ui.setupUi(Dialog)
Dialog.show() Dialog.show()
sys.exit(app.exec_()) sys.exit(app.exec_())

View File

@ -34,15 +34,20 @@ def get_py_str(a):
return unicode(a.toUtf8(), 'utf-8') return unicode(a.toUtf8(), 'utf-8')
return a # Already a python string in PySide return a # Already a python string in PySide
def set_utf8_text(component, text): def set_utf8_text(component, text):
if not pyqt: if not pyqt:
component.setText(text) component.setText(text)
else: else:
component.setText(QtCore.QString.fromUtf8(text)) component.setText(QtCore.QString.fromUtf8(text))
def get_filename(filename): def get_filename(filename):
if pyqt: if pyqt:
return str(filename.toUtf8()) return str(filename.toUtf8())
return filename[0] return filename[0]
def add_list_item(l, item): def add_list_item(l, item):
if pyqt: if pyqt:
history_item = QtCore.QString() history_item = QtCore.QString()

View File

@ -28,12 +28,14 @@ import rel_edit
class creatorForm(QtGui.QDialog): class creatorForm(QtGui.QDialog):
def __init__(self, rel=None): def __init__(self, rel=None):
QtGui.QDialog.__init__(self) QtGui.QDialog.__init__(self)
self.setSizeGripEnabled(True) self.setSizeGripEnabled(True)
self.result_relation = None self.result_relation = None
self.rel = rel self.rel = rel
def setUi(self, ui): def setUi(self, ui):
self.ui = ui self.ui = ui
self.table = self.ui.table self.table = self.ui.table
@ -42,6 +44,7 @@ class creatorForm(QtGui.QDialog):
self.setup_empty() self.setup_empty()
else: else:
self.setup_relation(self.rel) self.setup_relation(self.rel)
def setup_relation(self, rel): def setup_relation(self, rel):
self.table.insertRow(0) self.table.insertRow(0)
@ -60,6 +63,7 @@ class creatorForm(QtGui.QDialog):
self.table.setItem(self.table.rowCount() - 1, j, item) self.table.setItem(self.table.rowCount() - 1, j, item)
pass pass
def setup_empty(self): def setup_empty(self):
self.table.insertColumn(0) self.table.insertColumn(0)
self.table.insertColumn(0) self.table.insertColumn(0)
@ -79,15 +83,18 @@ class creatorForm(QtGui.QDialog):
self.table.setItem(0, 1, i01) self.table.setItem(0, 1, i01)
self.table.setItem(1, 0, i10) self.table.setItem(1, 0, i10)
self.table.setItem(1, 1, i11) self.table.setItem(1, 1, i11)
def create_relation(self): def create_relation(self):
hlist = [] hlist = []
for i in range(self.table.columnCount()): for i in range(self.table.columnCount()):
hlist.append(compatibility.get_py_str(self.table.item(0,i).text())) hlist.append(
compatibility.get_py_str(self.table.item(0, i).text()))
try: try:
header = relation.header(hlist) header = relation.header(hlist)
except Exception, e: except Exception, e:
QtGui.QMessageBox.information(None,QtGui.QApplication.translate("Form", "Error"),"%s\n%s" % (QtGui.QApplication.translate("Form", "Header error!"),e.__str__()) ) QtGui.QMessageBox.information(None, QtGui.QApplication.translate("Form", "Error"), "%s\n%s" % (
QtGui.QApplication.translate("Form", "Header error!"), e.__str__()))
return None return None
r = relation.relation() r = relation.relation()
r.header = header r.header = header
@ -96,9 +103,11 @@ class creatorForm(QtGui.QDialog):
hlist = [] hlist = []
for j in range(self.table.columnCount()): for j in range(self.table.columnCount()):
try: try:
hlist.append(compatibility.get_py_str(self.table.item(i,j).text())) hlist.append(
compatibility.get_py_str(self.table.item(i, j).text()))
except: except:
QtGui.QMessageBox.information(None,QtGui.QApplication.translate("Form", "Error"),QtGui.QApplication.translate("Form", "Unset value in %d,%d!"% (i+1,j+1)) ) QtGui.QMessageBox.information(None, QtGui.QApplication.translate(
"Form", "Error"), QtGui.QApplication.translate("Form", "Unset value in %d,%d!" % (i + 1, j + 1)))
return None return None
r.content.add(tuple(hlist)) r.content.add(tuple(hlist))
return r return r
@ -111,20 +120,25 @@ class creatorForm(QtGui.QDialog):
if self.result_relation != None: if self.result_relation != None:
QtGui.QDialog.accept(self) QtGui.QDialog.accept(self)
pass pass
def reject(self): def reject(self):
self.result_relation = None self.result_relation = None
QtGui.QDialog.reject(self) QtGui.QDialog.reject(self)
pass pass
def addColumn(self): def addColumn(self):
self.table.insertColumn(self.table.columnCount()) self.table.insertColumn(self.table.columnCount())
pass pass
def addRow(self): def addRow(self):
self.table.insertRow(1) self.table.insertRow(1)
pass pass
def deleteColumn(self): def deleteColumn(self):
if self.table.columnCount() > 1: if self.table.columnCount() > 1:
self.table.removeColumn(self.table.currentColumn()) self.table.removeColumn(self.table.currentColumn())
pass pass
def deleteRow(self): def deleteRow(self):
if self.table.rowCount() > 2: if self.table.rowCount() > 2:
self.table.removeRow(self.table.currentRow()) self.table.removeRow(self.table.currentRow())
@ -149,5 +163,6 @@ def edit_relation(rel=None):
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
app = QtGui.QApplication(sys.argv) app = QtGui.QApplication(sys.argv)
r=relation.relation("/home/salvo/dev/relational/trunk/samples/people.csv") r = relation.relation(
"/home/salvo/dev/relational/trunk/samples/people.csv")
print edit_relation(r) print edit_relation(r)

View File

@ -26,7 +26,6 @@ except:
from PySide import QtCore, QtGui from PySide import QtCore, QtGui
from relational import relation, parser, optimizer, rtypes from relational import relation, parser, optimizer, rtypes
import about import about
@ -55,14 +54,17 @@ class relForm(QtGui.QMainWindow):
online = maintenance.check_latest_version() online = maintenance.check_latest_version()
if online > version: if online > version:
r=QtGui.QApplication.translate("Form", "New version available online: %s." % online) r = QtGui.QApplication.translate(
"Form", "New version available online: %s." % online)
elif online == version: elif online == version:
r=QtGui.QApplication.translate("Form", "Latest version installed.") r = QtGui.QApplication.translate(
"Form", "Latest version installed.")
else: else:
r=QtGui.QApplication.translate("Form", "You are using an unstable version.") r = QtGui.QApplication.translate(
"Form", "You are using an unstable version.")
QtGui.QMessageBox.information(self,QtGui.QApplication.translate("Form", "Version"),r)
QtGui.QMessageBox.information(
self, QtGui.QApplication.translate("Form", "Version"), r)
def load_query(self, *index): def load_query(self, *index):
self.ui.txtQuery.setText(self.savedQ.itemData(index[0]).toString()) self.ui.txtQuery.setText(self.savedQ.itemData(index[0]).toString())
@ -81,9 +83,8 @@ class relForm(QtGui.QMainWindow):
result = optimizer.optimize_all(query, self.relations) result = optimizer.optimize_all(query, self.relations)
compatibility.set_utf8_text(self.ui.txtQuery, result) compatibility.set_utf8_text(self.ui.txtQuery, result)
except Exception, e: except Exception, e:
QtGui.QMessageBox.information(None,QtGui.QApplication.translate("Form", "Error"),"%s\n%s" % (QtGui.QApplication.translate("Form", "Check your query!"),e.__str__()) ) QtGui.QMessageBox.information(None, QtGui.QApplication.translate("Form", "Error"), "%s\n%s" %
(QtGui.QApplication.translate("Form", "Check your query!"), e.__str__()))
def resumeHistory(self, item): def resumeHistory(self, item):
itm = compatibility.get_py_str(item.text()).split(' = ', 1) itm = compatibility.get_py_str(item.text()).split(' = ', 1)
@ -94,10 +95,12 @@ class relForm(QtGui.QMainWindow):
'''Executes the query''' '''Executes the query'''
query = compatibility.get_py_str(self.ui.txtQuery.text()) query = compatibility.get_py_str(self.ui.txtQuery.text())
res_rel=compatibility.get_py_str(self.ui.txtResult.text())#result relation's name res_rel = compatibility.get_py_str(
self.ui.txtResult.text()) # result relation's name
if not rtypes.is_valid_relation_name(res_rel): if not rtypes.is_valid_relation_name(res_rel):
QtGui.QMessageBox.information(self,QtGui.QApplication.translate("Form", "Error"),QtGui.QApplication.translate("Form", "Wrong name for destination relation.")) QtGui.QMessageBox.information(self, QtGui.QApplication.translate(
"Form", "Error"), QtGui.QApplication.translate("Form", "Wrong name for destination relation."))
return return
try: try:
@ -106,22 +109,27 @@ class relForm(QtGui.QMainWindow):
print query, "-->", expr # Printing debug print query, "-->", expr # Printing debug
result = eval(expr, self.relations) # Evaluating the expression result = eval(expr, self.relations) # Evaluating the expression
self.relations[res_rel]=result #Add the relation to the dictionary self.relations[
res_rel] = result # Add the relation to the dictionary
self.updateRelations() # update the list self.updateRelations() # update the list
self.selectedRelation = result self.selectedRelation = result
self.showRelation(self.selectedRelation) #Show the result in the table self.showRelation(self.selectedRelation)
# Show the result in the table
except Exception, e: except Exception, e:
print e.__unicode__() print e.__unicode__()
QtGui.QMessageBox.information(None,QtGui.QApplication.translate("Form", "Error"),u"%s\n%s" % (QtGui.QApplication.translate("Form", "Check your query!"),e.__unicode__()) ) QtGui.QMessageBox.information(None, QtGui.QApplication.translate("Form", "Error"), u"%s\n%s" %
(QtGui.QApplication.translate("Form", "Check your query!"), e.__unicode__()))
return return
# Adds to history # Adds to history
item=u'%s = %s' % (compatibility.get_py_str(self.ui.txtResult.text()),compatibility.get_py_str(self.ui.txtQuery.text())) item = u'%s = %s' % (compatibility.get_py_str(
self.ui.txtResult.text()), compatibility.get_py_str(self.ui.txtQuery.text()))
# item=item.decode('utf-8')) # item=item.decode('utf-8'))
compatibility.add_list_item(self.ui.lstHistory, item) compatibility.add_list_item(self.ui.lstHistory, item)
self.qcounter += 1 self.qcounter += 1
compatibility.set_utf8_text(self.ui.txtResult,u"_last%d"% self.qcounter) #Sets the result relation name to none compatibility.set_utf8_text(self.ui.txtResult, u"_last%d" %
self.qcounter) # Sets the result relation name to none
def showRelation(self, rel): def showRelation(self, rel):
'''Shows the selected relation into the table''' '''Shows the selected relation into the table'''
@ -143,11 +151,12 @@ class relForm(QtGui.QMainWindow):
# Sets columns # Sets columns
for i in range(len(rel.header.attributes)): for i in range(len(rel.header.attributes)):
self.ui.table.headerItem().setText(i, rel.header.attributes[i]) self.ui.table.headerItem().setText(i, rel.header.attributes[i])
self.ui.table.resizeColumnToContents(i) #Must be done in order to avoid too small columns self.ui.table.resizeColumnToContents(
i) # Must be done in order to avoid too small columns
def printRelation(self, item): def printRelation(self, item):
self.selectedRelation=self.relations[compatibility.get_py_str(item.text())] self.selectedRelation = self.relations[
compatibility.get_py_str(item.text())]
self.showRelation(self.selectedRelation) self.showRelation(self.selectedRelation)
def showAttributes(self, item): def showAttributes(self, item):
@ -162,25 +171,31 @@ class relForm(QtGui.QMainWindow):
for i in self.relations: for i in self.relations:
if i != "__builtins__": if i != "__builtins__":
self.ui.lstRelations.addItem(i) self.ui.lstRelations.addItem(i)
def saveRelation(self): def saveRelation(self):
filename = QtGui.QFileDialog.getSaveFileName(self,QtGui.QApplication.translate("Form", "Save Relation"),"",QtGui.QApplication.translate("Form", "Relations (*.csv)")) filename = QtGui.QFileDialog.getSaveFileName(self, QtGui.QApplication.translate(
"Form", "Save Relation"), "", QtGui.QApplication.translate("Form", "Relations (*.csv)"))
filename = compatibility.get_filename(filename) filename = compatibility.get_filename(filename)
if (len(filename) == 0): # Returns if no file was selected if (len(filename) == 0): # Returns if no file was selected
return return
self.selectedRelation.save(filename) self.selectedRelation.save(filename)
return return
def unloadRelation(self): def unloadRelation(self):
for i in self.ui.lstRelations.selectedItems(): for i in self.ui.lstRelations.selectedItems():
del self.relations[compatibility.get_py_str(i.text())] del self.relations[compatibility.get_py_str(i.text())]
self.updateRelations() self.updateRelations()
def editRelation(self): def editRelation(self):
import creator import creator
for i in self.ui.lstRelations.selectedItems(): for i in self.ui.lstRelations.selectedItems():
result=creator.edit_relation(self.relations[compatibility.get_py_str(i.text())]) result = creator.edit_relation(
self.relations[compatibility.get_py_str(i.text())])
if result != None: if result != None:
self.relations[compatibility.get_py_str(i.text())] = result self.relations[compatibility.get_py_str(i.text())] = result
self.updateRelations() self.updateRelations()
def newRelation(self): def newRelation(self):
import creator import creator
result = creator.edit_relation() result = creator.edit_relation()
@ -190,7 +205,8 @@ class relForm(QtGui.QMainWindow):
res = QtGui.QInputDialog.getText( res = QtGui.QInputDialog.getText(
self, self,
QtGui.QApplication.translate("Form", "New relation"), QtGui.QApplication.translate("Form", "New relation"),
QtGui.QApplication.translate("Form", "Insert the name for the new relation"), QtGui.QApplication.translate(
"Form", "Insert the name for the new relation"),
QtGui.QLineEdit.Normal, '') QtGui.QLineEdit.Normal, '')
if res[1] == False or len(res[0]) == 0: if res[1] == False or len(res[0]) == 0:
return return
@ -199,22 +215,26 @@ class relForm(QtGui.QMainWindow):
name = compatibility.get_py_str(res[0]) name = compatibility.get_py_str(res[0])
if not rtypes.is_valid_relation_name(name): if not rtypes.is_valid_relation_name(name):
r=QtGui.QApplication.translate("Form", str("Wrong name for destination relation: %s." % name)) r = QtGui.QApplication.translate(
QtGui.QMessageBox.information(self,QtGui.QApplication.translate("Form", "Error"),r) "Form", str("Wrong name for destination relation: %s." % name))
QtGui.QMessageBox.information(
self, QtGui.QApplication.translate("Form", "Error"), r)
return return
try: try:
self.relations[name] = result self.relations[name] = result
except Exception, e: except Exception, e:
print e print e
QtGui.QMessageBox.information(None,QtGui.QApplication.translate("Form", "Error"),"%s\n%s" % (QtGui.QApplication.translate("Form", "Check your query!"),e.__str__()) ) QtGui.QMessageBox.information(None, QtGui.QApplication.translate("Form", "Error"), "%s\n%s" %
(QtGui.QApplication.translate("Form", "Check your query!"), e.__str__()))
return return
self.updateRelations() self.updateRelations()
def closeEvent(self, event): def closeEvent(self, event):
self.save_settings() self.save_settings()
event.accept() event.accept()
def save_settings(self): def save_settings(self):
# self.settings.setValue("width",) # self.settings.setValue("width",)
pass pass
@ -245,7 +265,8 @@ class relForm(QtGui.QMainWindow):
It shouldn't be called giving filename but not giving name.''' It shouldn't be called giving filename but not giving name.'''
# Asking for file to load # Asking for file to load
if filename == None: if filename == None:
filename = QtGui.QFileDialog.getOpenFileName(self,QtGui.QApplication.translate("Form", "Load Relation"),"",QtGui.QApplication.translate("Form", "Relations (*.csv);;Text Files (*.txt);;All Files (*)")) filename = QtGui.QFileDialog.getOpenFileName(self, QtGui.QApplication.translate(
"Form", "Load Relation"), "", QtGui.QApplication.translate("Form", "Relations (*.csv);;Text Files (*.txt);;All Files (*)"))
filename = compatibility.get_filename(filename) filename = compatibility.get_filename(filename)
# Default relation's name # Default relation's name
@ -259,7 +280,9 @@ class relForm(QtGui.QMainWindow):
defname = defname[:-4] defname = defname[:-4]
if name == None: # Prompt dialog to insert name for the relation if name == None: # Prompt dialog to insert name for the relation
res=QtGui.QInputDialog.getText(self, QtGui.QApplication.translate("Form", "New relation"),QtGui.QApplication.translate("Form", "Insert the name for the new relation"), res = QtGui.QInputDialog.getText(
self, QtGui.QApplication.translate("Form", "New relation"), QtGui.QApplication.translate(
"Form", "Insert the name for the new relation"),
QtGui.QLineEdit.Normal, defname) QtGui.QLineEdit.Normal, defname)
if res[1] == False or len(res[0]) == 0: if res[1] == False or len(res[0]) == 0:
return return
@ -268,44 +291,58 @@ class relForm(QtGui.QMainWindow):
name = compatibility.get_py_str(res[0]) name = compatibility.get_py_str(res[0])
if not rtypes.is_valid_relation_name(name): if not rtypes.is_valid_relation_name(name):
r=QtGui.QApplication.translate("Form", str("Wrong name for destination relation: %s." % name)) r = QtGui.QApplication.translate(
QtGui.QMessageBox.information(self,QtGui.QApplication.translate("Form", "Error"),r) "Form", str("Wrong name for destination relation: %s." % name))
QtGui.QMessageBox.information(
self, QtGui.QApplication.translate("Form", "Error"), r)
return return
try: try:
self.relations[name] = relation.relation(filename) self.relations[name] = relation.relation(filename)
except Exception, e: except Exception, e:
print e print e
QtGui.QMessageBox.information(None,QtGui.QApplication.translate("Form", "Error"),"%s\n%s" % (QtGui.QApplication.translate("Form", "Check your query!"),e.__str__()) ) QtGui.QMessageBox.information(None, QtGui.QApplication.translate("Form", "Error"), "%s\n%s" %
(QtGui.QApplication.translate("Form", "Check your query!"), e.__str__()))
return return
self.updateRelations() self.updateRelations()
def addProduct(self): def addProduct(self):
self.addSymbolInQuery(u"*") self.addSymbolInQuery(u"*")
def addDifference(self): def addDifference(self):
self.addSymbolInQuery(u"-") self.addSymbolInQuery(u"-")
def addUnion(self): def addUnion(self):
self.addSymbolInQuery(u"") self.addSymbolInQuery(u"")
def addIntersection(self): def addIntersection(self):
self.addSymbolInQuery(u"") self.addSymbolInQuery(u"")
def addDivision(self): def addDivision(self):
self.addSymbolInQuery(u"÷") self.addSymbolInQuery(u"÷")
def addOLeft(self): def addOLeft(self):
self.addSymbolInQuery(u"ᐅLEFTᐊ") self.addSymbolInQuery(u"ᐅLEFTᐊ")
def addJoin(self): def addJoin(self):
self.addSymbolInQuery(u"ᐅᐊ") self.addSymbolInQuery(u"ᐅᐊ")
def addORight(self): def addORight(self):
self.addSymbolInQuery(u"ᐅRIGHTᐊ") self.addSymbolInQuery(u"ᐅRIGHTᐊ")
def addOuter(self): def addOuter(self):
self.addSymbolInQuery(u"ᐅFULLᐊ") self.addSymbolInQuery(u"ᐅFULLᐊ")
def addProjection(self): def addProjection(self):
self.addSymbolInQuery(u"π") self.addSymbolInQuery(u"π")
def addSelection(self): def addSelection(self):
self.addSymbolInQuery(u"σ") self.addSymbolInQuery(u"σ")
def addRename(self): def addRename(self):
self.addSymbolInQuery(u"ρ") self.addSymbolInQuery(u"ρ")
def addArrow(self): def addArrow(self):
self.addSymbolInQuery(u"") self.addSymbolInQuery(u"")

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'relational_gui/maingui.ui' # Form implementation generated from reading ui file 'relational_gui/maingui.ui'
# #
# Created: Fri Dec 27 00:05:54 2013 # Created: Fri Dec 27 00:23:51 2013
# by: PyQt4 UI code generator 4.10.3 # by: PyQt4 UI code generator 4.10.3
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'relational_gui/rel_edit.ui' # Form implementation generated from reading ui file 'relational_gui/rel_edit.ui'
# #
# Created: Fri Dec 27 00:05:54 2013 # Created: Fri Dec 27 00:23:51 2013
# by: PyQt4 UI code generator 4.10.3 # by: PyQt4 UI code generator 4.10.3
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'relational_gui/survey.ui' # Form implementation generated from reading ui file 'relational_gui/survey.ui'
# #
# Created: Fri Dec 27 00:05:54 2013 # Created: Fri Dec 27 00:23:51 2013
# by: PyQt4 UI code generator 4.10.3 # by: PyQt4 UI code generator 4.10.3
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'relational_pyside/maingui.ui' # Form implementation generated from reading ui file 'relational_pyside/maingui.ui'
# #
# Created: Fri Dec 27 00:05:55 2013 # Created: Fri Dec 27 00:23:51 2013
# by: pyside-uic 0.2.15 running on PySide 1.2.1 # by: pyside-uic 0.2.15 running on PySide 1.2.1
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'relational_pyside/rel_edit.ui' # Form implementation generated from reading ui file 'relational_pyside/rel_edit.ui'
# #
# Created: Fri Dec 27 00:05:55 2013 # Created: Fri Dec 27 00:23:51 2013
# by: pyside-uic 0.2.15 running on PySide 1.2.1 # by: pyside-uic 0.2.15 running on PySide 1.2.1
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'relational_pyside/survey.ui' # Form implementation generated from reading ui file 'relational_pyside/survey.ui'
# #
# Created: Fri Dec 27 00:05:54 2013 # Created: Fri Dec 27 00:23:51 2013
# by: pyside-uic 0.2.15 running on PySide 1.2.1 # by: pyside-uic 0.2.15 running on PySide 1.2.1
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!

View File

@ -17,7 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
# author Salvo "LtWorf" Tomaselli <tiposchi@tiscali.it> # author Salvo "LtWorf" Tomaselli <tiposchi@tiscali.it>
# Initial readline code from http://www.doughellmann.com/PyMOTW/readline/index.html # Initial readline code from
# http://www.doughellmann.com/PyMOTW/readline/index.html
import readline import readline
import logging import logging
@ -31,7 +32,9 @@ from xtermcolor import colorize
PROMPT_COLOR = 0xffff00 PROMPT_COLOR = 0xffff00
ERROR_COLOR = 0xff0000 ERROR_COLOR = 0xff0000
class SimpleCompleter(object): class SimpleCompleter(object):
'''Handles completion''' '''Handles completion'''
def __init__(self, options): def __init__(self, options):
@ -95,11 +98,15 @@ class SimpleCompleter(object):
relations = {} relations = {}
completer=SimpleCompleter(['SURVEY','LIST','LOAD ','UNLOAD ','HELP ','QUIT','SAVE ','_PRODUCT ','_UNION ','_INTERSECTION ','_DIFFERENCE ','_JOIN ','_LJOIN ','_RJOIN ','_FJOIN ','_PROJECTION ','_RENAME_TO ','_SELECTION ','_RENAME ','_DIVISION ']) completer = SimpleCompleter(
['SURVEY', 'LIST', 'LOAD ', 'UNLOAD ', 'HELP ', 'QUIT', 'SAVE ', '_PRODUCT ', '_UNION ', '_INTERSECTION ',
'_DIFFERENCE ', '_JOIN ', '_LJOIN ', '_RJOIN ', '_FJOIN ', '_PROJECTION ', '_RENAME_TO ', '_SELECTION ', '_RENAME ', '_DIVISION '])
def load_relation(filename, defname=None): def load_relation(filename, defname=None):
if not os.path.isfile(filename): if not os.path.isfile(filename):
print >> sys.stderr, colorize("%s is not a file" % filename,ERROR_COLOR) print >> sys.stderr, colorize(
"%s is not a file" % filename, ERROR_COLOR)
return None return None
f = filename.split('/') f = filename.split('/')
@ -109,7 +116,8 @@ def load_relation(filename,defname=None):
defname = defname[:-4] defname = defname[:-4]
if not rtypes.is_valid_relation_name(defname): if not rtypes.is_valid_relation_name(defname):
print >> sys.stderr, colorize("%s is not a valid relation name" % defname,ERROR_COLOR) print >> sys.stderr, colorize(
"%s is not a valid relation name" % defname, ERROR_COLOR)
return return
try: try:
relations[defname] = relation.relation(filename) relations[defname] = relation.relation(filename)
@ -121,18 +129,21 @@ def load_relation(filename,defname=None):
print >>sys.stderr, colorize(e, ERROR_COLOR) print >>sys.stderr, colorize(e, ERROR_COLOR)
return None return None
def survey(): def survey():
'''performs a survey''' '''performs a survey'''
from relational import maintenance from relational import maintenance
post = {'software': 'Relational algebra (cli)', 'version': version} post = {'software': 'Relational algebra (cli)', 'version': version}
fields=('System','Country','School','Age','How did you find','email (only if you want a reply)','Comments') fields = ('System', 'Country', 'School', 'Age', 'How did you find',
'email (only if you want a reply)', 'Comments')
for i in fields: for i in fields:
a = raw_input('%s: ' % i) a = raw_input('%s: ' % i)
post[i] = a post[i] = a
maintenance.send_survey(post) maintenance.send_survey(post)
def help(command): def help(command):
'''Prints help on the various functions''' '''Prints help on the various functions'''
p = command.split(' ', 1) p = command.split(' ', 1)
@ -225,6 +236,7 @@ def exec_line(command):
else: else:
exec_query(command) exec_query(command)
def replacements(query): def replacements(query):
'''This funcion replaces ascii easy operators with the correct ones''' '''This funcion replaces ascii easy operators with the correct ones'''
query = query.replace(u'_PRODUCT', u'*') query = query.replace(u'_PRODUCT', u'*')
@ -242,6 +254,7 @@ def replacements(query):
query = query.replace(u'_DIVISION', u'÷') query = query.replace(u'_DIVISION', u'÷')
return query return query
def exec_query(command): def exec_query(command):
'''This function executes a query and prints the result on the screen '''This function executes a query and prints the result on the screen
if the command terminates with ";" the result will not be printed if the command terminates with ";" the result will not be printed
@ -255,8 +268,6 @@ def exec_query(command):
else: else:
printrel = True printrel = True
# Performs replacements for weird operators # Performs replacements for weird operators
command = replacements(command) command = replacements(command)
@ -270,7 +281,6 @@ def exec_query(command):
relname = 'last_' relname = 'last_'
query = command query = command
# Execute query # Execute query
try: try:
pyquery = parser.parse(query) pyquery = parser.parse(query)
@ -288,6 +298,7 @@ def exec_query(command):
except Exception, e: except Exception, e:
print colorize(e, ERROR_COLOR) print colorize(e, ERROR_COLOR)
def main(files=[]): def main(files=[]):
print colorize('> ', PROMPT_COLOR) + "; Type HELP to get the HELP" print colorize('> ', PROMPT_COLOR) + "; Type HELP to get the HELP"
print colorize('> ', PROMPT_COLOR) + "; Completion is activated using the tab (if supported by the terminal)" print colorize('> ', PROMPT_COLOR) + "; Completion is activated using the tab (if supported by the terminal)"
@ -301,7 +312,6 @@ def main(files=[]):
readline.parse_and_bind('set editing-mode emacs') readline.parse_and_bind('set editing-mode emacs')
readline.set_completer_delims(" ") readline.set_completer_delims(" ")
while True: while True:
try: try:
line = raw_input(colorize('> ', PROMPT_COLOR)) line = raw_input(colorize('> ', PROMPT_COLOR))
@ -317,4 +327,3 @@ def main(files=[]):
if __name__ == "__main__": if __name__ == "__main__":
main() main()