From c4bc74d61253734df2c3adee37ee6839b5070665 Mon Sep 17 00:00:00 2001 From: Salvo 'LtWorf' Tomaselli Date: Mon, 24 Aug 2020 17:55:13 +0200 Subject: [PATCH] Add a new json format --- driver.py | 4 +-- relational/maintenance.py | 19 +++++++++--- relational/relation.py | 62 +++++++++++++++++++++++++++------------ 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/driver.py b/driver.py index df92aa2..acdb381 100755 --- a/driver.py +++ b/driver.py @@ -57,7 +57,7 @@ def load_relations(): print ("Loading relation %s with name %s..." % (i, relname)) - rels[relname] = relation.Relation.load('%s%s' % (examples_path, i)) + rels[relname] = relation.Relation.load_csv('%s%s' % (examples_path, i)) print('done') @@ -239,7 +239,7 @@ def run_test(testname): o_result = None try: - result_rel = relation.Relation.load('%s%s.result' % (tests_path, testname)) + result_rel = relation.Relation.load_csv('%s%s.result' % (tests_path, testname)) query = readfile('%s%s.query' % (tests_path, testname)).strip() o_query = optimizer.optimize_all(query, rels) diff --git a/relational/maintenance.py b/relational/maintenance.py index 5afa527..d50c3b4 100644 --- a/relational/maintenance.py +++ b/relational/maintenance.py @@ -90,8 +90,15 @@ class UserInterface: def load(self, filename: str, name: str) -> None: '''Loads a relation from file, and gives it a name to - be used in subsequent queries.''' - rel = Relation.load(filename) + be used in subsequent queries. + + Files ending with .csv are loaded as csv, the others are + loaded as json. + ''' + if filename.endswith('.csv'): + rel = Relation.load_csv(filename) + else: + rel = Relation.load(filename) self.set_relation(name, rel) def unload(self, name: str) -> None: @@ -161,8 +168,12 @@ class UserInterface: if len(name) == 0: return None - if (name.endswith(".csv")): # removes the extension - name = name[:-4] + # Removing the extension + try: + pos = name.rindex('.') + except ValueError: + return None + name = name[:pos] if not is_valid_relation_name(name): return None diff --git a/relational/relation.py b/relational/relation.py index 51e3e5a..01a3a4d 100644 --- a/relational/relation.py +++ b/relational/relation.py @@ -19,7 +19,6 @@ # This module provides a classes to represent relations and to perform # relational operations on them. -import csv from itertools import chain, repeat, product as iproduct from collections import deque from typing import FrozenSet, Iterable, List, Dict, Tuple @@ -62,21 +61,62 @@ class Relation: content: FrozenSet[Tuple[CastValue, ...]] @staticmethod - def load(filename: Union[str, Path]) -> 'Relation': + def load_csv(filename: Union[str, Path]) -> 'Relation': ''' Load a relation object from a csv file. The 1st row is the header and the other rows are the content. + + Types will be inferred automatically ''' + import csv with open(filename) as fp: reader = csv.reader(fp) # Creating a csv reader header = Header(next(reader)) # read 1st line return Relation.create_from(header, reader) + @staticmethod + def load(filename: Union[str, Path]) -> 'Relation': + ''' + Load a relation object from a json file. + ''' + with open(filename) as fp: + from json import load as jload + from typedload import load + return load(jload(fp), Relation) + + def save(self, filename: Union[Path, str]) -> None: + ''' + Saves the relation in a file. + Will save using the json format + ''' + with open(filename, 'w') as fp: + from json import dump as jdump + from typedload import dump + jdump(dump(self), fp) + + def save_csv(self, filename: Union[Path, str]) -> None: + ''' + Saves the relation in a file. Will save using the csv + format as defined in RFC4180. + ''' + import csv + with open(filename, 'w') as fp: + writer = csv.writer(fp) # Creating csv writer + + # It wants an iterable containing iterables + head = (self.header,) + writer.writerows(head) + + # Writing content, already in the correct format + writer.writerows(self.content) + @staticmethod def create_from(header: Iterable[str], content: Iterable[List[str]]) -> 'Relation': ''' Iterator for the header, and iterator for the content. + + This will infer types. ''' header = Header(header) r_content = [] @@ -105,22 +145,6 @@ class Relation: def __contains__(self, key): return key in self.content - def save(self, filename: Union[Path, str]) -> None: - ''' - Saves the relation in a file. Will save using the csv - format as defined in RFC4180. - ''' - - with open(filename, 'w') as fp: - writer = csv.writer(fp) # Creating csv writer - - # It wants an iterable containing iterables - head = (self.header,) - writer.writerows(head) - - # Writing content, already in the correct format - writer.writerows(self.content) - def _rearrange(self, other: 'Relation') -> 'Relation': '''If two relations share the same attributes in a different order, this method will use projection to make them have the same attributes' order. @@ -317,7 +341,7 @@ class Relation: added = True # If it didn't partecipate, adds it if not added: - item = chain(i, repeat(None, len(noid))) #FIXME + item = chain(i, repeat(None, len(noid))) content.append(tuple(item)) return Relation(header, frozenset(content))