Changed about and README to not point to galileo anymore
This commit is contained in:
7
README
7
README
@@ -2,6 +2,9 @@ To launch the application, run
|
||||
|
||||
./relational_gui.py
|
||||
|
||||
If it needs some dependencies, check this page:
|
||||
http://galileo.dmi.unict.it/wiki/relational/doku.php?id=download#install
|
||||
Language definition is here:
|
||||
https://github.com/ltworf/relational/wiki/Grammar-and-language
|
||||
|
||||
If it needs some dependencies:
|
||||
Qt4, Python 2.7, either PyQT4 or Pyside.
|
||||
|
||||
|
20
driver.py
20
driver.py
@@ -37,6 +37,7 @@ rels={}
|
||||
examples_path = 'samples/'
|
||||
tests_path = 'test/'
|
||||
|
||||
|
||||
def readfile(fname):
|
||||
'''Reads a file as string and returns its content'''
|
||||
fd = open(fname)
|
||||
@@ -60,6 +61,7 @@ def load_relations():
|
||||
rels[relname] = relation.relation('%s%s' % (examples_path, i))
|
||||
print 'done'
|
||||
|
||||
|
||||
def execute_tests():
|
||||
|
||||
py_bad = 0
|
||||
@@ -72,7 +74,6 @@ def execute_tests():
|
||||
ex_good = 0
|
||||
ex_tot = 0
|
||||
|
||||
|
||||
for i in os.listdir(tests_path):
|
||||
if i.endswith('.query'):
|
||||
q_tot += 1
|
||||
@@ -112,7 +113,6 @@ def execute_tests():
|
||||
if ex_bad > 0:
|
||||
print colorize("Failed tests count: %d" % ex_bad, COLOR_RED)
|
||||
|
||||
|
||||
print colorize("Total results", COLOR_CYAN)
|
||||
if q_bad + py_bad + ex_bad == 0:
|
||||
print colorize("No failed tests", COLOR_GREEN)
|
||||
@@ -137,11 +137,9 @@ def run_exec_test(testname):
|
||||
expr = readfile('%s%s.exec' % (tests_path, testname))
|
||||
exec(expr, glob) # Evaluating the expression
|
||||
|
||||
|
||||
expr = readfile('%s%s.result' % (tests_path, testname))
|
||||
exp_result = eval(expr, rels) # Evaluating the expression
|
||||
|
||||
|
||||
if isinstance(exp_result, dict):
|
||||
fields_ok = True
|
||||
|
||||
@@ -160,6 +158,7 @@ def run_exec_test(testname):
|
||||
print colorize('=====================================', COLOR_RED)
|
||||
return False
|
||||
|
||||
|
||||
def run_py_test(testname):
|
||||
'''Runs a python test, which evaluates expressions directly rather than queries'''
|
||||
print "Running expression python test: " + colorize(testname, COLOR_MAGENTA)
|
||||
@@ -185,6 +184,7 @@ def run_py_test(testname):
|
||||
print colorize('=====================================', COLOR_RED)
|
||||
return False
|
||||
|
||||
|
||||
def run_test(testname):
|
||||
'''Runs a specific test executing the file
|
||||
testname.query
|
||||
@@ -194,22 +194,26 @@ def run_test(testname):
|
||||
optimized'''
|
||||
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 = None
|
||||
o_result = None
|
||||
|
||||
|
||||
try:
|
||||
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)
|
||||
|
||||
expr = parser.parse(query) # Converting expression to python string
|
||||
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
|
||||
|
||||
c_expr = parser.tree(query).toCode() # Converting to python code
|
||||
|
@@ -23,6 +23,7 @@ import httplib
|
||||
import urllib
|
||||
import relation
|
||||
|
||||
|
||||
def send_survey(data):
|
||||
'''Sends the survey. Data must be a dictionary.
|
||||
returns the http response'''
|
||||
@@ -33,14 +34,11 @@ def send_survey(data):
|
||||
|
||||
# sends the string
|
||||
params = urllib.urlencode({'survey': post})
|
||||
headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"}
|
||||
#connection = httplib.HTTPConnection('galileo.dmi.unict.it')
|
||||
#connection.request("POST","/~ltworf/survey.php",params,headers)
|
||||
|
||||
headers = {"Content-type":
|
||||
"application/x-www-form-urlencoded", "Accept": "text/plain"}
|
||||
connection = httplib.HTTPConnection('feedback-ltworf.appspot.com')
|
||||
connection.request("POST", "/feedback/relational", params, headers)
|
||||
|
||||
|
||||
return connection.getresponse()
|
||||
|
||||
|
||||
@@ -60,6 +58,7 @@ def check_latest_version():
|
||||
|
||||
|
||||
class interface (object):
|
||||
|
||||
'''It is used to provide services to the user interfaces, in order to
|
||||
reduce the amount of duplicated code present in different user interfaces.
|
||||
'''
|
||||
|
@@ -34,7 +34,9 @@ import parser
|
||||
from cStringIO import StringIO
|
||||
from tokenize import generate_tokens
|
||||
|
||||
sel_op=('//=','**=','and','not','in','//','**','<<','>>','==','!=','>=','<=','+=','-=','*=','/=','%=','or','+','-','*','/','&','|','^','~','<','>','%','=','(',')',',','[',']')
|
||||
sel_op = (
|
||||
'//=', '**=', 'and', 'not', 'in', '//', '**', '<<', '>>', '==', '!=', '>=', '<=', '+=', '-=',
|
||||
'*=', '/=', '%=', 'or', '+', '-', '*', '/', '&', '|', '^', '~', '<', '>', '%', '=', '(', ')', ',', '[', ']')
|
||||
|
||||
PRODUCT = parser.PRODUCT
|
||||
DIFFERENCE = parser.DIFFERENCE
|
||||
@@ -64,6 +66,7 @@ def replace_node(replace,replacement):
|
||||
replace.right = replacement.right
|
||||
replace.left = replacement.left
|
||||
|
||||
|
||||
def recoursive_scan(function, node, rels=None):
|
||||
'''Does a recoursive optimization on the tree.
|
||||
|
||||
@@ -115,6 +118,7 @@ def duplicated_select(n):
|
||||
|
||||
return changes + recoursive_scan(duplicated_select, n)
|
||||
|
||||
|
||||
def futile_union_intersection_subtraction(n):
|
||||
'''This function locates things like r ᑌ r, and replaces them with r.
|
||||
R ᑌ R --> R
|
||||
@@ -170,6 +174,7 @@ def futile_union_intersection_subtraction(n):
|
||||
|
||||
return changes + recoursive_scan(futile_union_intersection_subtraction, n)
|
||||
|
||||
|
||||
def down_to_unions_subtractions_intersections(n):
|
||||
'''This funcion locates things like σ i==2 (c ᑌ d), where the union
|
||||
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)
|
||||
|
||||
|
||||
def duplicated_projection(n):
|
||||
'''This function locates thing like π i ( π j (R)) and replaces
|
||||
them with π i (R)'''
|
||||
@@ -211,6 +217,7 @@ def duplicated_projection(n):
|
||||
|
||||
return changes + recoursive_scan(duplicated_projection, n)
|
||||
|
||||
|
||||
def selection_inside_projection(n):
|
||||
'''This function locates things like σ j (π k(R)) and
|
||||
converts them into π k(σ j (R))'''
|
||||
@@ -226,6 +233,7 @@ def selection_inside_projection(n):
|
||||
|
||||
return changes + recoursive_scan(selection_inside_projection, n)
|
||||
|
||||
|
||||
def swap_union_renames(n):
|
||||
'''This function locates things like
|
||||
ρ a➡b(R) ᑌ ρ a➡b(Q)
|
||||
@@ -263,6 +271,7 @@ def swap_union_renames(n):
|
||||
|
||||
return changes + recoursive_scan(swap_union_renames, n)
|
||||
|
||||
|
||||
def futile_renames(n):
|
||||
'''This function purges renames like id->id'''
|
||||
changes = 0
|
||||
@@ -276,7 +285,8 @@ def futile_renames(n):
|
||||
for i in n.prop.split(','):
|
||||
q = i.split(ARROW)
|
||||
_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()):
|
||||
try:
|
||||
value = _vars[key]
|
||||
@@ -297,6 +307,7 @@ def futile_renames(n):
|
||||
|
||||
return changes + recoursive_scan(futile_renames, n)
|
||||
|
||||
|
||||
def subsequent_renames(n):
|
||||
'''This function removes redoundant subsequent renames joining them into one'''
|
||||
|
||||
@@ -317,7 +328,8 @@ def subsequent_renames(n):
|
||||
for i in n.prop.split(','):
|
||||
q = i.split(ARROW)
|
||||
_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()):
|
||||
try:
|
||||
value = _vars[key]
|
||||
@@ -345,9 +357,11 @@ def subsequent_renames(n):
|
||||
|
||||
return changes + recoursive_scan(subsequent_renames, n)
|
||||
|
||||
|
||||
class level_string(str):
|
||||
level = 0
|
||||
|
||||
|
||||
def tokenize_select(expression):
|
||||
'''This function returns the list of tokens present in a
|
||||
selection. The expression can contain parenthesis.
|
||||
@@ -368,7 +382,6 @@ def tokenize_select(expression):
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
level = 0
|
||||
for i in range(len(l)):
|
||||
l[i] = level_string(l[i])
|
||||
@@ -381,6 +394,7 @@ def tokenize_select(expression):
|
||||
|
||||
return l
|
||||
|
||||
|
||||
def swap_rename_projection(n):
|
||||
'''This function locates things like π k(ρ j(R))
|
||||
and replaces them with ρ j(π k(R)).
|
||||
@@ -422,9 +436,9 @@ def swap_rename_projection(n):
|
||||
n.child.prop += i + ','
|
||||
n.child.prop = n.child.prop[:-1]
|
||||
|
||||
|
||||
return changes + recoursive_scan(swap_rename_projection, n)
|
||||
|
||||
|
||||
def swap_rename_select(n):
|
||||
'''This function locates things like σ k(ρ j(R)) and replaces
|
||||
them with ρ j(σ k(R)). Renaming the attributes used in the
|
||||
@@ -449,7 +463,8 @@ def swap_rename_select(n):
|
||||
if len(splitted) == 1:
|
||||
_tokens[i] = _vars[_tokens[i].split('.')[0]]
|
||||
else:
|
||||
_tokens[i]=_vars[_tokens[i].split('.')[0]]+'.'+splitted[1]
|
||||
_tokens[i] = _vars[
|
||||
_tokens[i].split('.')[0]] + '.' + splitted[1]
|
||||
|
||||
# Swapping operators
|
||||
n.name = RENAME
|
||||
@@ -462,6 +477,7 @@ def swap_rename_select(n):
|
||||
|
||||
return changes + recoursive_scan(swap_rename_select, n)
|
||||
|
||||
|
||||
def select_union_intersect_subtract(n):
|
||||
'''This function locates things like σ i(a) ᑌ σ 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)
|
||||
|
||||
|
||||
def selection_and_product(n, rels):
|
||||
'''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,
|
||||
@@ -597,7 +614,9 @@ def 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]
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@@ -43,6 +43,7 @@ tokenize=parser.tokenize
|
||||
tree = parser.tree
|
||||
# End of the stuff
|
||||
|
||||
|
||||
def optimize_all(expression, rels, specific=True, general=True, debug=None):
|
||||
'''This function performs all the available optimizations.
|
||||
|
||||
@@ -73,15 +74,18 @@ def optimize_all(expression,rels,specific=True,general=True,debug=None):
|
||||
if specific:
|
||||
for i in optimizations.specific_optimizations:
|
||||
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
|
||||
if general:
|
||||
for i in optimizations.general_optimizations:
|
||||
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
|
||||
return n.__str__()
|
||||
|
||||
|
||||
def specific_optimize(expression, rels):
|
||||
'''This function performs specific optimizations. Means that it will need to
|
||||
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 optimize_all(expression, rels, specific=True, general=False)
|
||||
|
||||
|
||||
def general_optimize(expression):
|
||||
'''This function performs general optimizations. Means that it will not need to
|
||||
know the fields used by the relations
|
||||
@@ -110,7 +115,8 @@ if __name__=="__main__":
|
||||
# a= tokenize(u"π a,b (a*b)")
|
||||
# a=tokenize("(a-b*c)*(b-c)")
|
||||
|
||||
import relation,optimizations
|
||||
import relation
|
||||
import optimizations
|
||||
|
||||
'''rels={}
|
||||
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 ((ρ age➡a,id➡i (π 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.result_format(rels)
|
||||
|
@@ -23,6 +23,7 @@ import optimizer
|
||||
import multiprocessing
|
||||
import parser
|
||||
|
||||
|
||||
def execute(tree, rels):
|
||||
'''This funcion executes a query in parallel.
|
||||
Tree is the tree describing the query (usually obtained with
|
||||
@@ -36,6 +37,7 @@ def execute(tree,rels):
|
||||
p.join()
|
||||
return result
|
||||
|
||||
|
||||
def __p_exec__(tree, rels, q):
|
||||
'''q is the queue used for communication'''
|
||||
if tree.kind == parser.RELATION:
|
||||
@@ -52,10 +54,11 @@ def __p_exec__(tree,rels,q):
|
||||
q.put(result)
|
||||
elif tree.kind == parser.BINARY:
|
||||
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_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
|
||||
left_p.start()
|
||||
@@ -72,6 +75,8 @@ def __p_exec__(tree,rels,q):
|
||||
result = __p_exec_binary__(tree, left, right)
|
||||
q.put(result)
|
||||
return
|
||||
|
||||
|
||||
def __p_exec_binary__(tree, left, right):
|
||||
if tree.name == '*':
|
||||
return left.product(right)
|
||||
@@ -92,12 +97,14 @@ def __p_exec_binary__(tree,left,right):
|
||||
else: # tree.name=='ᐅFULLᐊ':
|
||||
return left.outer(right)
|
||||
|
||||
|
||||
def __p_exec_unary__(tree, rel):
|
||||
if tree.name == 'π': # Projection
|
||||
tree.prop = tree.prop.replace(' ', '').split(',')
|
||||
result = rel.projection(tree.prop)
|
||||
elif tree.name == "ρ": # Rename
|
||||
#tree.prop='{\"%s\"}' % tree.prop.replace(',','\",\"').replace('➡','\":\"').replace(' ','')
|
||||
# tree.prop='{\"%s\"}' %
|
||||
# tree.prop.replace(',','\",\"').replace('➡','\":\"').replace(' ','')
|
||||
d = {}
|
||||
tree.prop = tree.prop.replace(' ', '')
|
||||
for i in tree.prop.split(','):
|
||||
@@ -108,4 +115,3 @@ def __p_exec_unary__(tree,rel):
|
||||
else: # Selection
|
||||
result = rel.selection(tree.prop)
|
||||
return result
|
||||
|
@@ -61,18 +61,26 @@ SELECTION=u'σ'
|
||||
RENAME = 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
|
||||
|
||||
# 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):
|
||||
pass
|
||||
|
||||
|
||||
class ParserException (Exception):
|
||||
pass
|
||||
|
||||
|
||||
class node (object):
|
||||
|
||||
'''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.
|
||||
@@ -103,7 +111,8 @@ class node (object):
|
||||
self.kind = RELATION
|
||||
self.name = expression[0]
|
||||
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
|
||||
|
||||
'''Expression from right to left, searching for binary operators
|
||||
@@ -122,10 +131,12 @@ class node (object):
|
||||
self.name = expression[i]
|
||||
|
||||
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:
|
||||
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.right = node(expression[i + 1:])
|
||||
@@ -137,7 +148,8 @@ class node (object):
|
||||
self.name = expression[i]
|
||||
|
||||
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.child = node(expression[2 + i])
|
||||
@@ -145,6 +157,7 @@ class node (object):
|
||||
return
|
||||
raise ParserException(u"Unable to parse tokens")
|
||||
pass
|
||||
|
||||
def toCode(self):
|
||||
'''This method converts the tree into a python code object'''
|
||||
code = self.toPython()
|
||||
@@ -162,7 +175,8 @@ class node (object):
|
||||
if self.name == PROJECTION:
|
||||
prop = '\"%s\"' % prop.replace(' ', '').replace(',', '\",\"')
|
||||
elif self.name == RENAME:
|
||||
prop='{\"%s\"}' % prop.replace(',','\",\"').replace(ARROW,'\":\"').replace(' ','')
|
||||
prop = '{\"%s\"}' % prop.replace(
|
||||
',', '\",\"').replace(ARROW, '\":\"').replace(' ', '')
|
||||
else: # Selection
|
||||
prop = '\"%s\"' % prop
|
||||
|
||||
@@ -170,6 +184,7 @@ class node (object):
|
||||
else:
|
||||
return self.name
|
||||
pass
|
||||
|
||||
def printtree(self, level=0):
|
||||
'''returns a representation of the tree using indentation'''
|
||||
r = ''
|
||||
@@ -184,6 +199,7 @@ class node (object):
|
||||
r += self.child.printtree(level + 1)
|
||||
|
||||
return '\n' + r
|
||||
|
||||
def get_left_leaf(self):
|
||||
'''This function returns the leftmost leaf in the tree. It is needed by some optimizations.'''
|
||||
if self.kind == RELATION:
|
||||
@@ -193,7 +209,6 @@ class node (object):
|
||||
elif self.kind == BINARY:
|
||||
return self.left.get_left_leaf()
|
||||
|
||||
|
||||
def result_format(self, rels):
|
||||
'''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
|
||||
@@ -229,6 +244,7 @@ class node (object):
|
||||
return _fields
|
||||
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))))
|
||||
|
||||
def __eq__(self, other):
|
||||
if not (isinstance(other, node) and self.name == other.name and self.kind == other.kind):
|
||||
return False
|
||||
@@ -258,6 +274,7 @@ class node (object):
|
||||
|
||||
return (le + self.name + re)
|
||||
|
||||
|
||||
def _find_matching_parenthesis(expression, start=0, openpar=u'(', closepar=u')'):
|
||||
'''This function returns the position of the matching
|
||||
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:
|
||||
return i # Closing parenthesis of the parameter
|
||||
|
||||
|
||||
def tokenize(expression):
|
||||
'''This function converts an expression into a list where
|
||||
every token of the expression is an item of a list. Expressions into
|
||||
@@ -307,23 +325,29 @@ def tokenize(expression):
|
||||
state = 2
|
||||
end = _find_matching_parenthesis(expression)
|
||||
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
|
||||
items.append(tokenize(expression[1:end]))
|
||||
# Removes the entire parentesis and content from the expression
|
||||
expression = expression[end + 1:].strip()
|
||||
|
||||
elif expression.startswith((u"σ", u"π", u"ρ")): # Unary 2 bytes
|
||||
items.append(expression[0:1]) #Adding operator in the top of the list
|
||||
expression=expression[1:].strip() #Removing operator from the expression
|
||||
items.append(expression[0:1])
|
||||
#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
|
||||
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
|
||||
par = expression.find('(')
|
||||
|
||||
items.append(expression[:par].strip()) #Inserting parameter of the operator
|
||||
expression=expression[par:].strip() #Removing parameter from the expression
|
||||
items.append(expression[:par].strip())
|
||||
#Inserting parameter of the operator
|
||||
expression = expression[
|
||||
par:].strip() # Removing parameter from the expression
|
||||
elif expression.startswith((u"÷", u"ᑎ", u"ᑌ", u"*", u"-")):
|
||||
items.append(expression[0])
|
||||
expression = expression[1:].strip() # 1 char from the expression
|
||||
@@ -336,26 +360,29 @@ def tokenize(expression):
|
||||
expression = expression[i + 1:].strip()
|
||||
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
|
||||
raise TokenizerException("Unexpected '%c' in '%s'" % (expression[0],expression))
|
||||
raise TokenizerException(
|
||||
"Unexpected '%c' in '%s'" % (expression[0], expression))
|
||||
else: # Relation (hopefully)
|
||||
if state == 1: # Previous was a relation, appending to the last token
|
||||
i = items.pop()
|
||||
items.append(i + expression[0])
|
||||
expression=expression[1:].strip() #1 char from the expression
|
||||
expression = expression[
|
||||
1:].strip() # 1 char from the expression
|
||||
else:
|
||||
state = 1
|
||||
items.append(expression[0])
|
||||
expression=expression[1:].strip() #1 char from the expression
|
||||
expression = expression[
|
||||
1:].strip() # 1 char from the expression
|
||||
|
||||
return items
|
||||
|
||||
|
||||
def tree(expression):
|
||||
'''This function parses a relational algebra expression into a tree and returns
|
||||
the root node using the Node class defined in this module.'''
|
||||
return node(tokenize(expression))
|
||||
|
||||
|
||||
|
||||
def parse(expr):
|
||||
'''This function parses a relational algebra expression, converting it into python,
|
||||
executable by eval function to get the result of the expression.
|
||||
|
@@ -21,10 +21,13 @@
|
||||
|
||||
import parser
|
||||
|
||||
|
||||
class TypeException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Query(object):
|
||||
|
||||
def __init__(self, query):
|
||||
|
||||
if not isinstance(query, unicode):
|
||||
|
@@ -23,7 +23,9 @@
|
||||
from rtypes import *
|
||||
import csv
|
||||
|
||||
|
||||
class relation (object):
|
||||
|
||||
'''This objects defines a relation (as a group of consistent tuples) and operations
|
||||
A relation can be represented using a table
|
||||
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):
|
||||
newt.content.add(i)
|
||||
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
|
||||
|
||||
def product(self, other):
|
||||
'''Cartesian product, attributes must be different to avoid collisions
|
||||
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'''
|
||||
|
||||
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.header = header(self.header.attributes + other.header.attributes)
|
||||
|
||||
@@ -140,7 +145,6 @@ class relation (object):
|
||||
newt.content.add(i + j)
|
||||
return newt
|
||||
|
||||
|
||||
def projection(self, * attributes):
|
||||
'''Projection operator, takes many parameters, for each field to use.
|
||||
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.'''
|
||||
other = self._rearrange_(other) # Rearranges attributes' order
|
||||
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.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.'''
|
||||
other = self._rearrange_(other) # Rearranges attributes' order
|
||||
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.header = header(list(self.header.attributes))
|
||||
|
||||
newt.content = self.content.difference(other.content)
|
||||
return newt
|
||||
|
||||
def division(self, other):
|
||||
'''Division operator
|
||||
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=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:
|
||||
@@ -261,12 +268,14 @@ class relation (object):
|
||||
It is possible to use projection and rename to make headers match.'''
|
||||
other = self._rearrange_(other) # Rearranges attributes' order
|
||||
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.header = header(list(self.header.attributes))
|
||||
|
||||
newt.content = self.content.union(other.content)
|
||||
return newt
|
||||
|
||||
def thetajoin(self, other, expr):
|
||||
'''Defined as product and then selection with the given expression.'''
|
||||
return self.product(other).selection(expr)
|
||||
@@ -347,11 +356,13 @@ class relation (object):
|
||||
shared attributes, it will behave as cartesian product.'''
|
||||
|
||||
# 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
|
||||
|
||||
#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))
|
||||
for i in other.header.attributes:
|
||||
if i not in shared:
|
||||
@@ -382,10 +393,12 @@ class relation (object):
|
||||
newt.content.add(tuple(item))
|
||||
|
||||
return newt
|
||||
|
||||
def __eq__(self, other):
|
||||
'''Returns true if the relations are the same, ignoring order of items.
|
||||
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):
|
||||
return False # Both parameters must be a relation
|
||||
@@ -393,8 +406,6 @@ class relation (object):
|
||||
if set(self.header.attributes) != set(other.header.attributes):
|
||||
return False
|
||||
|
||||
|
||||
|
||||
# comparing content
|
||||
return self.content == other.content
|
||||
|
||||
@@ -416,7 +427,6 @@ class relation (object):
|
||||
for f in range(len(self.header.attributes)):
|
||||
res += "%s" % (self.header.attributes[f].ljust(2 + m_len[f]))
|
||||
|
||||
|
||||
for r in self.content:
|
||||
col = 0
|
||||
res += "\n"
|
||||
@@ -438,7 +448,8 @@ 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) # List of indexes corresponding to keys
|
||||
|
||||
# new_content=[] #New content of the relation
|
||||
for i in self.content:
|
||||
@@ -492,14 +503,15 @@ class relation (object):
|
||||
for j in range(len(self.header.attributes)):
|
||||
attributes[self.header.attributes[j]] = self._autocast(i[j])
|
||||
|
||||
|
||||
if not eval(expr, attributes):
|
||||
affected -= 1
|
||||
new_content.add(i)
|
||||
self.content = new_content
|
||||
return affected
|
||||
|
||||
|
||||
class header (object):
|
||||
|
||||
'''This class defines the header of a relation.
|
||||
It is used within relations to know if requested operations are accepted'''
|
||||
|
||||
@@ -517,7 +529,6 @@ class header (object):
|
||||
def __repr__(self):
|
||||
return "header(%s)" % (self.attributes.__repr__())
|
||||
|
||||
|
||||
def rename(self, old, new):
|
||||
'''Renames a field. Doesn't check if it is a duplicate.
|
||||
Returns True if the field was renamed, False otherwise'''
|
||||
@@ -542,6 +553,7 @@ class header (object):
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.attributes == other.attributes
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.attributes != other.attributes
|
||||
|
||||
@@ -553,4 +565,3 @@ class header (object):
|
||||
if i == self.attributes[j]:
|
||||
res.append(j)
|
||||
return res
|
||||
|
@@ -24,8 +24,11 @@
|
||||
import datetime
|
||||
import re
|
||||
|
||||
|
||||
class rstring (str):
|
||||
|
||||
'''String subclass with some custom methods'''
|
||||
|
||||
def isInt(self):
|
||||
'''Returns true if the string represents an int number
|
||||
it only considers as int numbers the strings matching
|
||||
@@ -36,6 +39,7 @@ class rstring (str):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def isFloat(self):
|
||||
'''Returns true if the string represents a float number
|
||||
it only considers as float numbers, the strings matching
|
||||
@@ -58,7 +62,8 @@ class rstring (str):
|
||||
except:
|
||||
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:
|
||||
self._isdate = False
|
||||
self._date = None
|
||||
@@ -84,8 +89,12 @@ class rstring (str):
|
||||
except:
|
||||
self.isDate()
|
||||
return self._date
|
||||
|
||||
|
||||
class rdate (object):
|
||||
|
||||
'''Represents a date'''
|
||||
|
||||
def __init__(self, date):
|
||||
'''date: A string representing a date'''
|
||||
if not isinstance(date, rstring):
|
||||
@@ -99,23 +108,32 @@ class rdate (object):
|
||||
|
||||
def __hash__(self):
|
||||
return self.intdate.__hash__()
|
||||
|
||||
def __str__(self):
|
||||
return self.intdate.__str__()
|
||||
|
||||
def __add__(self, days):
|
||||
res = self.intdate + datetime.timedelta(days)
|
||||
return rdate(res.__str__())
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.intdate == other.intdate
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.intdate >= other.intdate
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.intdate > other.intdate
|
||||
|
||||
def __le__(self, other):
|
||||
return self.intdate <= other.intdate
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.intdate < other.intdate
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.intdate != other.intdate
|
||||
|
||||
def __sub__(self, other):
|
||||
return (self.intdate - other.intdate).days
|
||||
|
||||
|
@@ -23,6 +23,7 @@ import signal
|
||||
import sys
|
||||
from relational import *
|
||||
|
||||
|
||||
def terminate(*a):
|
||||
'''Restores the terminal and terminates'''
|
||||
curses.nocbreak()
|
||||
@@ -32,6 +33,7 @@ def terminate(*a):
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def main():
|
||||
global stdscr
|
||||
# Initializes the signal
|
||||
@@ -52,15 +54,11 @@ def main():
|
||||
|
||||
win = curses.panel.new_panel(curses.newwin(termsize[0], termsize[1]))
|
||||
|
||||
|
||||
|
||||
# win.window().box()
|
||||
win.window().addstr(0, (termsize[1] / 2) - 5, "Relational")
|
||||
win.window().refresh()
|
||||
# curses.napms(1000)
|
||||
|
||||
|
||||
|
||||
query = curses.panel.new_panel(curses.newwin(3, termsize[1], 1, 0))
|
||||
query.window().box()
|
||||
query.window().addstr(1, 1, "")
|
||||
@@ -71,9 +69,7 @@ def main():
|
||||
|
||||
# curses.napms(1000)
|
||||
|
||||
|
||||
# qq=curses.textpad.Textbox(stdscr)
|
||||
|
||||
'''win = curses.newwin(0, 0)#New windows for the entire screen
|
||||
#stdscr.border(0)
|
||||
stdscr.addstr(str(dir (win)))
|
||||
@@ -97,13 +93,11 @@ def main():
|
||||
if c == 27: # Escape
|
||||
squery += add_symbol(symselect)
|
||||
|
||||
|
||||
# elif c==curses.KEY_BACKSPACE: #Delete
|
||||
elif c == 13:
|
||||
squery = squery[:-1]
|
||||
else:
|
||||
squery+=chr(c);
|
||||
|
||||
squery += chr(c)
|
||||
|
||||
query.window().box()
|
||||
query.top()
|
||||
@@ -111,10 +105,13 @@ def main():
|
||||
query.window().addstr(1, 1, squery)
|
||||
|
||||
query.window().refresh()
|
||||
|
||||
|
||||
def init_symbol_list(termsize, create=True):
|
||||
|
||||
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:
|
||||
p = termsize
|
||||
p.window().box()
|
||||
@@ -135,13 +132,15 @@ def init_symbol_list(termsize,create=True):
|
||||
|
||||
# p.hide()
|
||||
return p
|
||||
|
||||
|
||||
def add_symbol(p):
|
||||
'''Shows the panel to add a symbol
|
||||
and then returns the choosen symbol itself'''
|
||||
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.top()
|
||||
@@ -156,6 +155,7 @@ def add_symbol(p):
|
||||
char = ''
|
||||
return char
|
||||
|
||||
|
||||
def spaces(t):
|
||||
'''Returns a number of spaces specified t'''
|
||||
s = ''
|
||||
|
@@ -42,6 +42,7 @@ def printver(exit=True):
|
||||
if exit:
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def printhelp(code=0):
|
||||
print "Relational"
|
||||
print
|
||||
@@ -92,7 +93,6 @@ if __name__ == "__main__":
|
||||
from PySide import QtCore, QtGui
|
||||
pyqt = False
|
||||
|
||||
|
||||
if pyqt:
|
||||
try:
|
||||
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."
|
||||
sys.exit(3)
|
||||
|
||||
|
||||
about.version = version
|
||||
surveyForm.version = version
|
||||
guihandler.version = version
|
||||
|
||||
app = QtGui.QApplication(sys.argv)
|
||||
app.setOrganizationName('None');
|
||||
app.setApplicationName('relational');
|
||||
app.setOrganizationName('None')
|
||||
app.setApplicationName('relational')
|
||||
|
||||
ui = maingui.Ui_MainWindow()
|
||||
Form = guihandler.relForm(ui)
|
||||
@@ -146,4 +145,3 @@ if __name__ == "__main__":
|
||||
sys.exit(3)
|
||||
relational_readline.linegui.version = version
|
||||
relational_readline.linegui.main(files)
|
||||
|
||||
|
@@ -37,7 +37,9 @@ except:
|
||||
|
||||
version = 0
|
||||
|
||||
|
||||
class Ui_Dialog(object):
|
||||
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(510, 453)
|
||||
@@ -96,14 +98,16 @@ class Ui_Dialog(object):
|
||||
self.verticalLayout_7.setObjectName("verticalLayout_7")
|
||||
if (webk):
|
||||
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.verticalLayout_7.addWidget(self.webView)
|
||||
else:
|
||||
self.webLink = QtGui.QLabel(self.groupBox)
|
||||
self.webLink.setFont(font)
|
||||
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.setTextFormat(QtCore.Qt.AutoText)
|
||||
self.webLink.setTextInteractionFlags(
|
||||
@@ -126,24 +130,39 @@ class Ui_Dialog(object):
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
self.tabWidget.setCurrentIndex(0)
|
||||
QtCore.QObject.connect(self.buttonBox,QtCore.SIGNAL("accepted()"),Dialog.accept)
|
||||
QtCore.QObject.connect(self.buttonBox,QtCore.SIGNAL("rejected()"),Dialog.reject)
|
||||
QtCore.QObject.connect(
|
||||
self.buttonBox, QtCore.SIGNAL("accepted()"), Dialog.accept)
|
||||
QtCore.QObject.connect(
|
||||
self.buttonBox, QtCore.SIGNAL("rejected()"), Dialog.reject)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Documentation", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.groupBox.setTitle(QtGui.QApplication.translate("Dialog", "Relational", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.label.setText(QtGui.QApplication.translate("Dialog", "Relational", 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 <<a href=\"mailto:tiposchi@tiscali.it\">tiposchi@tiscali.it</a>><br>Emilio Di Prima <emiliodiprima[at]msn[dot]com> (For the windows setup)", None, QtGui.QApplication.UnicodeUTF8))
|
||||
Dialog.setWindowTitle(QtGui.QApplication.translate(
|
||||
"Dialog", "Documentation", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.groupBox.setTitle(QtGui.QApplication.translate(
|
||||
"Dialog", "Relational", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.label.setText(QtGui.QApplication.translate(
|
||||
"Dialog", "Relational", 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 <<a href=\"mailto:tiposchi@tiscali.it\">tiposchi@tiscali.it</a>><br>Emilio Di Prima <emiliodiprima[at]msn[dot]com> (For the windows setup)", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.label_2.setOpenExternalLinks(True)
|
||||
self.label_2.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse)
|
||||
self.groupBox_2.setTitle(QtGui.QApplication.translate("Dialog", "Links", None, QtGui.QApplication.UnicodeUTF8))
|
||||
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.label_2.setTextInteractionFlags(
|
||||
QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextSelectableByMouse)
|
||||
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.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse)
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), QtGui.QApplication.translate("Dialog", "About", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.label_4.setTextInteractionFlags(
|
||||
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"
|
||||
"<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"
|
||||
@@ -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;\">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 <http://www.gnu.org/licenses/>. </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 <http://www.gnu.org/philosophy/why-not-lgpl.html>. </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.tab_2), QtGui.QApplication.translate("Dialog", "Docs", 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.tab_2), QtGui.QApplication.translate(
|
||||
"Dialog", "Docs", None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@@ -299,4 +319,3 @@ if __name__ == "__main__":
|
||||
ui.setupUi(Dialog)
|
||||
Dialog.show()
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
@@ -34,15 +34,20 @@ def get_py_str(a):
|
||||
return unicode(a.toUtf8(), 'utf-8')
|
||||
return a # Already a python string in PySide
|
||||
|
||||
|
||||
def set_utf8_text(component, text):
|
||||
if not pyqt:
|
||||
component.setText(text)
|
||||
else:
|
||||
component.setText(QtCore.QString.fromUtf8(text))
|
||||
|
||||
|
||||
def get_filename(filename):
|
||||
if pyqt:
|
||||
return str(filename.toUtf8())
|
||||
return filename[0]
|
||||
|
||||
|
||||
def add_list_item(l, item):
|
||||
if pyqt:
|
||||
history_item = QtCore.QString()
|
||||
|
@@ -28,12 +28,14 @@ import rel_edit
|
||||
|
||||
|
||||
class creatorForm(QtGui.QDialog):
|
||||
|
||||
def __init__(self, rel=None):
|
||||
QtGui.QDialog.__init__(self)
|
||||
|
||||
self.setSizeGripEnabled(True)
|
||||
self.result_relation = None
|
||||
self.rel = rel
|
||||
|
||||
def setUi(self, ui):
|
||||
self.ui = ui
|
||||
self.table = self.ui.table
|
||||
@@ -42,6 +44,7 @@ class creatorForm(QtGui.QDialog):
|
||||
self.setup_empty()
|
||||
else:
|
||||
self.setup_relation(self.rel)
|
||||
|
||||
def setup_relation(self, rel):
|
||||
|
||||
self.table.insertRow(0)
|
||||
@@ -60,6 +63,7 @@ class creatorForm(QtGui.QDialog):
|
||||
self.table.setItem(self.table.rowCount() - 1, j, item)
|
||||
|
||||
pass
|
||||
|
||||
def setup_empty(self):
|
||||
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(1, 0, i10)
|
||||
self.table.setItem(1, 1, i11)
|
||||
|
||||
def create_relation(self):
|
||||
hlist = []
|
||||
|
||||
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:
|
||||
header = relation.header(hlist)
|
||||
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
|
||||
r = relation.relation()
|
||||
r.header = header
|
||||
@@ -96,9 +103,11 @@ class creatorForm(QtGui.QDialog):
|
||||
hlist = []
|
||||
for j in range(self.table.columnCount()):
|
||||
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:
|
||||
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
|
||||
r.content.add(tuple(hlist))
|
||||
return r
|
||||
@@ -111,20 +120,25 @@ class creatorForm(QtGui.QDialog):
|
||||
if self.result_relation != None:
|
||||
QtGui.QDialog.accept(self)
|
||||
pass
|
||||
|
||||
def reject(self):
|
||||
self.result_relation = None
|
||||
QtGui.QDialog.reject(self)
|
||||
pass
|
||||
|
||||
def addColumn(self):
|
||||
self.table.insertColumn(self.table.columnCount())
|
||||
pass
|
||||
|
||||
def addRow(self):
|
||||
self.table.insertRow(1)
|
||||
pass
|
||||
|
||||
def deleteColumn(self):
|
||||
if self.table.columnCount() > 1:
|
||||
self.table.removeColumn(self.table.currentColumn())
|
||||
pass
|
||||
|
||||
def deleteRow(self):
|
||||
if self.table.rowCount() > 2:
|
||||
self.table.removeRow(self.table.currentRow())
|
||||
@@ -149,5 +163,6 @@ def edit_relation(rel=None):
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
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)
|
||||
|
@@ -26,7 +26,6 @@ except:
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
|
||||
|
||||
from relational import relation, parser, optimizer, rtypes
|
||||
|
||||
import about
|
||||
@@ -55,14 +54,17 @@ class relForm(QtGui.QMainWindow):
|
||||
online = maintenance.check_latest_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:
|
||||
r=QtGui.QApplication.translate("Form", "Latest version installed.")
|
||||
r = QtGui.QApplication.translate(
|
||||
"Form", "Latest version installed.")
|
||||
else:
|
||||
r=QtGui.QApplication.translate("Form", "You are using an unstable version.")
|
||||
|
||||
QtGui.QMessageBox.information(self,QtGui.QApplication.translate("Form", "Version"),r)
|
||||
r = QtGui.QApplication.translate(
|
||||
"Form", "You are using an unstable version.")
|
||||
|
||||
QtGui.QMessageBox.information(
|
||||
self, QtGui.QApplication.translate("Form", "Version"), r)
|
||||
|
||||
def load_query(self, *index):
|
||||
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)
|
||||
compatibility.set_utf8_text(self.ui.txtQuery, result)
|
||||
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):
|
||||
itm = compatibility.get_py_str(item.text()).split(' = ', 1)
|
||||
@@ -94,10 +95,12 @@ class relForm(QtGui.QMainWindow):
|
||||
'''Executes the query'''
|
||||
|
||||
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):
|
||||
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
|
||||
|
||||
try:
|
||||
@@ -106,22 +109,27 @@ class relForm(QtGui.QMainWindow):
|
||||
print query, "-->", expr # Printing debug
|
||||
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.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:
|
||||
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
|
||||
|
||||
# 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'))
|
||||
compatibility.add_list_item(self.ui.lstHistory, item)
|
||||
|
||||
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):
|
||||
'''Shows the selected relation into the table'''
|
||||
@@ -143,11 +151,12 @@ class relForm(QtGui.QMainWindow):
|
||||
# Sets columns
|
||||
for i in range(len(rel.header.attributes)):
|
||||
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):
|
||||
self.selectedRelation=self.relations[compatibility.get_py_str(item.text())]
|
||||
self.selectedRelation = self.relations[
|
||||
compatibility.get_py_str(item.text())]
|
||||
self.showRelation(self.selectedRelation)
|
||||
|
||||
def showAttributes(self, item):
|
||||
@@ -162,25 +171,31 @@ class relForm(QtGui.QMainWindow):
|
||||
for i in self.relations:
|
||||
if i != "__builtins__":
|
||||
self.ui.lstRelations.addItem(i)
|
||||
|
||||
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)
|
||||
if (len(filename) == 0): # Returns if no file was selected
|
||||
return
|
||||
self.selectedRelation.save(filename)
|
||||
return
|
||||
|
||||
def unloadRelation(self):
|
||||
for i in self.ui.lstRelations.selectedItems():
|
||||
del self.relations[compatibility.get_py_str(i.text())]
|
||||
self.updateRelations()
|
||||
|
||||
def editRelation(self):
|
||||
import creator
|
||||
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:
|
||||
self.relations[compatibility.get_py_str(i.text())] = result
|
||||
self.updateRelations()
|
||||
|
||||
def newRelation(self):
|
||||
import creator
|
||||
result = creator.edit_relation()
|
||||
@@ -190,7 +205,8 @@ class relForm(QtGui.QMainWindow):
|
||||
res = QtGui.QInputDialog.getText(
|
||||
self,
|
||||
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, '')
|
||||
if res[1] == False or len(res[0]) == 0:
|
||||
return
|
||||
@@ -199,22 +215,26 @@ class relForm(QtGui.QMainWindow):
|
||||
name = compatibility.get_py_str(res[0])
|
||||
|
||||
if not rtypes.is_valid_relation_name(name):
|
||||
r=QtGui.QApplication.translate("Form", str("Wrong name for destination relation: %s." % name))
|
||||
QtGui.QMessageBox.information(self,QtGui.QApplication.translate("Form", "Error"),r)
|
||||
r = QtGui.QApplication.translate(
|
||||
"Form", str("Wrong name for destination relation: %s." % name))
|
||||
QtGui.QMessageBox.information(
|
||||
self, QtGui.QApplication.translate("Form", "Error"), r)
|
||||
return
|
||||
|
||||
try:
|
||||
self.relations[name] = result
|
||||
except Exception, 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
|
||||
|
||||
|
||||
self.updateRelations()
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.save_settings()
|
||||
event.accept()
|
||||
|
||||
def save_settings(self):
|
||||
# self.settings.setValue("width",)
|
||||
pass
|
||||
@@ -245,7 +265,8 @@ class relForm(QtGui.QMainWindow):
|
||||
It shouldn't be called giving filename but not giving name.'''
|
||||
# Asking for file to load
|
||||
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)
|
||||
|
||||
# Default relation's name
|
||||
@@ -259,7 +280,9 @@ class relForm(QtGui.QMainWindow):
|
||||
defname = defname[:-4]
|
||||
|
||||
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)
|
||||
if res[1] == False or len(res[0]) == 0:
|
||||
return
|
||||
@@ -268,44 +291,58 @@ class relForm(QtGui.QMainWindow):
|
||||
name = compatibility.get_py_str(res[0])
|
||||
|
||||
if not rtypes.is_valid_relation_name(name):
|
||||
r=QtGui.QApplication.translate("Form", str("Wrong name for destination relation: %s." % name))
|
||||
QtGui.QMessageBox.information(self,QtGui.QApplication.translate("Form", "Error"),r)
|
||||
r = QtGui.QApplication.translate(
|
||||
"Form", str("Wrong name for destination relation: %s." % name))
|
||||
QtGui.QMessageBox.information(
|
||||
self, QtGui.QApplication.translate("Form", "Error"), r)
|
||||
return
|
||||
|
||||
try:
|
||||
self.relations[name] = relation.relation(filename)
|
||||
except Exception, 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
|
||||
|
||||
|
||||
self.updateRelations()
|
||||
|
||||
def addProduct(self):
|
||||
self.addSymbolInQuery(u"*")
|
||||
|
||||
def addDifference(self):
|
||||
self.addSymbolInQuery(u"-")
|
||||
|
||||
def addUnion(self):
|
||||
self.addSymbolInQuery(u"ᑌ")
|
||||
|
||||
def addIntersection(self):
|
||||
self.addSymbolInQuery(u"ᑎ")
|
||||
|
||||
def addDivision(self):
|
||||
self.addSymbolInQuery(u"÷")
|
||||
|
||||
def addOLeft(self):
|
||||
self.addSymbolInQuery(u"ᐅLEFTᐊ")
|
||||
|
||||
def addJoin(self):
|
||||
self.addSymbolInQuery(u"ᐅᐊ")
|
||||
|
||||
def addORight(self):
|
||||
self.addSymbolInQuery(u"ᐅRIGHTᐊ")
|
||||
|
||||
def addOuter(self):
|
||||
self.addSymbolInQuery(u"ᐅFULLᐊ")
|
||||
|
||||
def addProjection(self):
|
||||
self.addSymbolInQuery(u"π")
|
||||
|
||||
def addSelection(self):
|
||||
self.addSymbolInQuery(u"σ")
|
||||
|
||||
def addRename(self):
|
||||
self.addSymbolInQuery(u"ρ")
|
||||
|
||||
def addArrow(self):
|
||||
self.addSymbolInQuery(u"➡")
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
# 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
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
# 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
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
# 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
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@
|
||||
|
||||
# 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
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
# 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
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
# 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
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
@@ -17,7 +17,8 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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 logging
|
||||
@@ -31,7 +32,9 @@ from xtermcolor import colorize
|
||||
PROMPT_COLOR = 0xffff00
|
||||
ERROR_COLOR = 0xff0000
|
||||
|
||||
|
||||
class SimpleCompleter(object):
|
||||
|
||||
'''Handles completion'''
|
||||
|
||||
def __init__(self, options):
|
||||
@@ -95,11 +98,15 @@ class SimpleCompleter(object):
|
||||
|
||||
|
||||
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):
|
||||
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
|
||||
|
||||
f = filename.split('/')
|
||||
@@ -109,7 +116,8 @@ def load_relation(filename,defname=None):
|
||||
defname = defname[:-4]
|
||||
|
||||
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
|
||||
try:
|
||||
relations[defname] = relation.relation(filename)
|
||||
@@ -121,18 +129,21 @@ def load_relation(filename,defname=None):
|
||||
print >>sys.stderr, colorize(e, ERROR_COLOR)
|
||||
return None
|
||||
|
||||
|
||||
def survey():
|
||||
'''performs a survey'''
|
||||
from relational import maintenance
|
||||
|
||||
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:
|
||||
a = raw_input('%s: ' % i)
|
||||
post[i] = a
|
||||
maintenance.send_survey(post)
|
||||
|
||||
|
||||
def help(command):
|
||||
'''Prints help on the various functions'''
|
||||
p = command.split(' ', 1)
|
||||
@@ -225,6 +236,7 @@ def exec_line(command):
|
||||
else:
|
||||
exec_query(command)
|
||||
|
||||
|
||||
def replacements(query):
|
||||
'''This funcion replaces ascii easy operators with the correct ones'''
|
||||
query = query.replace(u'_PRODUCT', u'*')
|
||||
@@ -242,6 +254,7 @@ def replacements(query):
|
||||
query = query.replace(u'_DIVISION', u'÷')
|
||||
return query
|
||||
|
||||
|
||||
def exec_query(command):
|
||||
'''This function executes a query and prints the result on the screen
|
||||
if the command terminates with ";" the result will not be printed
|
||||
@@ -255,8 +268,6 @@ def exec_query(command):
|
||||
else:
|
||||
printrel = True
|
||||
|
||||
|
||||
|
||||
# Performs replacements for weird operators
|
||||
command = replacements(command)
|
||||
|
||||
@@ -270,7 +281,6 @@ def exec_query(command):
|
||||
relname = 'last_'
|
||||
query = command
|
||||
|
||||
|
||||
# Execute query
|
||||
try:
|
||||
pyquery = parser.parse(query)
|
||||
@@ -288,6 +298,7 @@ def exec_query(command):
|
||||
except Exception, e:
|
||||
print colorize(e, ERROR_COLOR)
|
||||
|
||||
|
||||
def main(files=[]):
|
||||
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)"
|
||||
@@ -301,7 +312,6 @@ def main(files=[]):
|
||||
readline.parse_and_bind('set editing-mode emacs')
|
||||
readline.set_completer_delims(" ")
|
||||
|
||||
|
||||
while True:
|
||||
try:
|
||||
line = raw_input(colorize('> ', PROMPT_COLOR))
|
||||
@@ -317,4 +327,3 @@ def main(files=[]):
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
Reference in New Issue
Block a user