def test_union_flags(self): s1 = Set(1) s2 = Set(2) s3 = Set(1, 2) self.assertTrue(is_absolute_member(s1)) self.assertTrue(is_absolute_member(s2)) self.assertTrue(is_absolute_member(s3)) result = union(s1, s2) self.assertEqual(s3, result) self.assertEqual(result.cached_is_absolute, CacheStatus.IS) from algebraixlib.algebras import relations as _rels rel1 = Set(Couplet('a', 1)) rel2 = Set(Couplet('b', 2)) rel3 = Set(Couplet('a', 1), Couplet('b', 2)) self.assertTrue(_rels.is_absolute_member(rel1)) self.assertTrue(_rels.is_absolute_member(rel2)) result = union(rel1, rel2) self.assertEqual(rel3, result) self.assertEqual(result.cached_is_absolute, CacheStatus.IS) from algebraixlib.algebras import clans as _clans clan1 = Set(rel1) clan2 = Set(rel2) clan3 = Set(rel1, rel2) self.assertTrue(_clans.is_absolute_member(clan1)) self.assertTrue(_clans.is_absolute_member(clan2)) self.assertTrue(_clans.is_functional(clan1)) self.assertTrue(_clans.is_functional(clan2)) self.assertTrue(_clans.is_right_functional(clan1)) self.assertTrue(_clans.is_right_functional(clan2)) result = union(clan1, clan2) self.assertEqual(clan3, result) self.assertEqual(result.cached_absolute, CacheStatus.IS) self.assertEqual(result.cached_functional, CacheStatus.IS) self.assertEqual(result.cached_right_functional, CacheStatus.IS) clan4 = Set(Set(Couplet(s1, 1), Couplet(s1, 2))) clan5 = Set(rel1, Set(Couplet(s1, 1), Couplet(s1, 2))) self.assertFalse(_clans.is_absolute_member(clan4)) self.assertFalse(_clans.is_functional(clan4)) result = union(clan1, clan4) self.assertEqual(clan5, result) self.assertEqual(result.cached_absolute, CacheStatus.IS_NOT) self.assertEqual(result.cached_functional, CacheStatus.IS_NOT) rel1 = Set(Couplet('a', 1), Couplet('b', 2)).cache_relation(CacheStatus.IS) rel2 = Set(Couplet('c', 3)) self.assertEqual( union(rel1, rel2).cached_relation, CacheStatus.UNKNOWN) self.assertTrue(_rels.is_member(rel2)) self.assertEqual(union(rel1, rel2).cached_relation, CacheStatus.IS)
def test_union_flags(self): s1 = Set(1) s2 = Set(2) s3 = Set(1, 2) self.assertTrue(is_absolute_member(s1)) self.assertTrue(is_absolute_member(s2)) self.assertTrue(is_absolute_member(s3)) result = union(s1, s2) self.assertEqual(s3, result) self.assertEqual(result.cached_is_absolute, CacheStatus.IS) from algebraixlib.algebras import relations as _rels rel1 = Set(Couplet('a', 1)) rel2 = Set(Couplet('b', 2)) rel3 = Set(Couplet('a', 1), Couplet('b', 2)) self.assertTrue(_rels.is_absolute_member(rel1)) self.assertTrue(_rels.is_absolute_member(rel2)) result = union(rel1, rel2) self.assertEqual(rel3, result) self.assertEqual(result.cached_is_absolute, CacheStatus.IS) from algebraixlib.algebras import clans as _clans clan1 = Set(rel1) clan2 = Set(rel2) clan3 = Set(rel1, rel2) self.assertTrue(_clans.is_absolute_member(clan1)) self.assertTrue(_clans.is_absolute_member(clan2)) self.assertTrue(_clans.is_functional(clan1)) self.assertTrue(_clans.is_functional(clan2)) self.assertTrue(_clans.is_right_functional(clan1)) self.assertTrue(_clans.is_right_functional(clan2)) result = union(clan1, clan2) self.assertEqual(clan3, result) self.assertEqual(result.cached_absolute, CacheStatus.IS) self.assertEqual(result.cached_functional, CacheStatus.IS) self.assertEqual(result.cached_right_functional, CacheStatus.IS) clan4 = Set(Set(Couplet(s1, 1), Couplet(s1, 2))) clan5 = Set(rel1, Set(Couplet(s1, 1), Couplet(s1, 2))) self.assertFalse(_clans.is_absolute_member(clan4)) self.assertFalse(_clans.is_functional(clan4)) result = union(clan1, clan4) self.assertEqual(clan5, result) self.assertEqual(result.cached_absolute, CacheStatus.IS_NOT) self.assertEqual(result.cached_functional, CacheStatus.IS_NOT) rel1 = Set(Couplet('a', 1), Couplet('b', 2)).cache_relation(CacheStatus.IS) rel2 = Set(Couplet('c', 3)) self.assertEqual(union(rel1, rel2).cached_relation, CacheStatus.UNKNOWN) self.assertTrue(_rels.is_member(rel2)) self.assertEqual(union(rel1, rel2).cached_relation, CacheStatus.IS)
def export_csv(absolute_clan: 'PP(A x A)', file_or_path, column_order=None, sort_key=None): """This function takes an absolute, left regular clan and produces a CSV file, where the left components are in the header line and the rows are the individual relations. :param absolute_clan: A :class:`algebraixlib.mathobjects.set.Set`. It must be an absolute and left-regular clan. :param file_or_path: Either a file path (in this case the CSV data is written to a file at this location) or a file object (in this case the CSV data is written to its ``.write()`` function). :param column_order: The optional left set to be exported in the specified order. :param sort_key: The optional key to be provided to sorted (sorted not called if None). :return: ``True`` if the CSV export succeeded. """ if not _clans.is_absolute_member(absolute_clan) \ and not _multiclans.is_absolute_member(absolute_clan): return _ud.make_or_raise_undef() if column_order is None and not absolute_clan.is_left_regular(): return _ud.make_or_raise_undef() if column_order is None: # Since this clan is left regular, get first relation to acquire left set. rel = next(iter(absolute_clan)) # left_set is sorted to guarantee consistent iterations column_order = sorted([left.value for left in rel.get_left_set()]) # Build list of dictionaries that associates left components with their right components for each relation. clan_as_list_of_dicts = _convert_clan_to_list_of_dicts(column_order, (absolute_clan if sort_key is None else sorted(absolute_clan, key=sort_key))) # Write that dictionary. _csv_dict_writer(file_or_path, column_order, clan_as_list_of_dicts) return True
def export_csv(absolute_clan_or_multiclan, file_or_path, ordered_lefts=None, sort_key=None): r"""Export an absolute clan or absolute multiclan as CSV file with header row. The :term:`left component`\s of the :term:`clan` or term:`multiclan` are interpreted as column names and are exported as header row. Every :term:`relation` in the input becomes a data row in the CSV file. :param absolute_clan_or_multiclan: An :term:`absolute clan` or term:`absolute multiclan`. If it is not :term:`regular`, ``ordered_lefts`` must be given. :param file_or_path: Either a file path (in this case the CSV data is written to a file at this location) or a file object (in this case the CSV data is written to its ``.write()`` function). :param ordered_lefts: (Optional) A ``Sequence`` of :term:`left`\s that are exported in the given order. Default is the sequence that is the lexically sorted :term:`left set` of the (multi)clan. This parameter is required if ``absolute_clan_or_multiclan`` is not term:`regular`. :param sort_key: (Optional) A function that compares two row-:term:`relation`\s and provides an order (for use with :func:`sorted`). The output is not sorted if ``sort_key`` is missing. :return: ``True`` if the CSV export succeeded, ``False`` if not. """ if not _clans.is_absolute_member(absolute_clan_or_multiclan) \ and not _multiclans.is_absolute_member(absolute_clan_or_multiclan): return False regular_clan = _clans.is_member(absolute_clan_or_multiclan) \ and _clans.is_regular(absolute_clan_or_multiclan) regular_mclan = _multiclans.is_member(absolute_clan_or_multiclan) \ and _multiclans.is_regular(absolute_clan_or_multiclan) if ordered_lefts is None and not (regular_clan or regular_mclan): return False if ordered_lefts is None: # Since this clan is regular, get first relation to acquire left set. rel = next(iter(absolute_clan_or_multiclan)) # left_set is sorted to guarantee consistent iterations ordered_lefts = sorted([left.value for left in rel.get_left_set()]) # Generate dictionaries that associates left components with their right components for each # relation. clan_as_list_of_dicts = _convert_clan_to_list_of_dicts( ordered_lefts, (absolute_clan_or_multiclan if sort_key is None else sorted(absolute_clan_or_multiclan, key=sort_key))) # Write the dictionaries. _csv_dict_writer(file_or_path, ordered_lefts, clan_as_list_of_dicts) return True
def export_table(file_or_path, lefts: 'P( A )', table: 'PP(A x A)', out_format: str = 'csv'): r"""Return a serialized table as string in a supported RDF format for table serialization. **Limitations**: - Leading '?' and '$' are not stripped from lefts (variable names). - Non-printable characters are backslash-escaped. - ``table`` must be an :term:`absolute` :term:`graph`. :param file_or_path: Either a file path (in this case the data is written to a file at this location) or a file object (in this case the data is written to its ``.write()`` function). :param lefts: The set of the :term:`left component`\s in ``table`` that is exported. :param table: An :term:`absolute clan` that contains the data to be exported. :param out_format: A supported RDF table format. Supported are ``'csv'`` (`SPARQL 1.1 Query Results CSV and TSV Formats`_) and ``'json'`` (`SPARQL 1.1 Query Results JSON Format`_). .. _SPARQL 1.1 Query Results CSV and TSV Formats: http://www.w3.org/TR/2013/REC-sparql11-results-csv-tsv-20130321/ .. _SPARQL 1.1 Query Results JSON Format: http://www.w3.org/TR/2013/REC-sparql11-results-json-20130321/ """ # noinspection PyPep8 class Csv(_ExportTable): """Specialize ``_ExportTable`` for RDF CSV.""" def __init__(self, clan, ordered_lefts): super().__init__(clan=clan, ordered_lefts=ordered_lefts) def _doc_start(self): pass def _doc_end(self): pass def _header_start(self): pass def _header_between_lefts(self): self._file.write(', ') def _header_end(self): self._file.write('\n') def _body_start(self): pass def _body_end(self): pass def _row_start(self): pass def _row_between_relations(self): pass def _row_end(self): self._file.write('\n') def _item_between_couplets(self): self._file.write(', ') def _write_item(self, left, right, prefix_separator): if right is not _ud.Undef(): self._write_atom(right) def _write_atom(self, atom: _mo.Atom): data = str(atom.value).replace('"', '""') self._file.write('"' + data + '"') # noinspection PyPep8 class Json(_ExportTable): """Specialize ``_ExportTable`` for RDF JSON.""" def __init__(self, clan, ordered_lefts): super().__init__(clan=clan, ordered_lefts=ordered_lefts) def _doc_start(self): self._file.write('{') def _doc_end(self): self._file.write('}') def _header_start(self): self._file.write('"head":{"vars":[') def _header_between_lefts(self): self._file.write(', ') def _header_end(self): self._file.write(']},\n') def _body_start(self): self._file.write('"results":{"bindings":[\n') def _body_end(self): self._file.write(']}') def _row_start(self): self._file.write('{') def _row_between_relations(self): self._file.write(',') def _row_end(self): self._file.write('}\n') def _item_between_couplets(self): pass def _write_item(self, left, right, prefix_separator): if right is not _ud.Undef(): if prefix_separator: self._file.write(', ') self._write_atom(left) self._file.write(': {"type":') if isinstance(right.value, _rdflib.URIRef): self._file.write('"uri"') elif isinstance(right.value, _rdflib.BNode): self._file.write('"bnode"') else: self._file.write('"literal"') lit = _rdflib.Literal(right.value) if isinstance(lit.datatype, str): self._file.write(', "datatype":"') self._file.write(lit.datatype) self._file.write('"') self._file.write(', "value":') self._write_atom(right) self._file.write('}\n') def _write_atom(self, atom: _mo.Atom): self._file.write('"' + str(atom.value) + '"') assert _clans.is_absolute_member(table) sorted_lefts = sorted(lefts) if out_format == 'csv': writer = Csv(clan=table, ordered_lefts=sorted_lefts) elif out_format == 'json': writer = Json(clan=table, ordered_lefts=sorted_lefts) else: raise AssertionError("'out_format' must be 'csv' or 'json'") writer.export(file_or_path)
def export_table(file_or_path, lefts: 'P( A )', table: 'PP(A x A)', out_format: str='csv'): """Return a serialized table as string in a supported RDF format for table serialization. **Limitations**: - Leading '?' and '$' are not stripped from lefts (variable names). - Non-printable characters are backslash-escaped. - ``table`` must be an :term:`absolute` :term:`graph`. :param file_or_path: Either a file path (in this case the data is written to a file at this location) or a file object (in this case the data is written to its ``.write()`` function). :param lefts: The set of the left components in ``table`` that is exported. :param table: A :term:`clan` that contains the data to be exported. :param out_format: A supported RDF table format. Supported are ``'csv'`` (`<SPARQL 1.1 Query Results CSV and TSV Formats>`_) and ``'json'`` (`<SPARQL 1.1 Query Results JSON Format>`_). .. _SPARQL 1.1 Query Results CSV and TSV Formats: http://www.w3.org/TR/2013/REC-sparql11-results-csv-tsv-20130321/ .. _SPARQL 1.1 Query Results JSON Format: http://www.w3.org/TR/2013/REC-sparql11-results-json-20130321/ """ # noinspection PyPep8 class Csv(_ExportTable): """Specialize _ExportTable for RDF CSV.""" def __init__(self, clan, ordered_lefts): _ExportTable.__init__(self, clan=clan, ordered_lefts=ordered_lefts) def _doc_start(self): pass def _doc_end(self): pass def _header_start(self): pass def _header_between_lefts(self): self._file.write(', ') def _header_end(self): self._file.write('\n') def _body_start(self): pass def _body_end(self): pass def _row_start(self): pass def _row_between_relations(self): pass def _row_end(self): self._file.write('\n') def _item_between_couplets(self): self._file.write(', ') def _write_item(self, left, right, prefix_separator): if right is not _ud.Undef(): self._write_atom(right) def _write_atom(self, atom: _mo.Atom): data = str(atom.value).replace('"', '""') self._file.write('"' + data + '"') # noinspection PyPep8 class Json(_ExportTable): """Specialize _ExportTable for RDF JSON.""" def __init__(self, clan, ordered_lefts): _ExportTable.__init__(self, clan=clan, ordered_lefts=ordered_lefts) def _doc_start(self): self._file.write('{') def _doc_end(self): self._file.write('}') def _header_start(self): self._file.write('"head":{"vars":[') def _header_between_lefts(self): self._file.write(', ') def _header_end(self): self._file.write(']},\n') def _body_start(self): self._file.write('"results":{"bindings":[\n') def _body_end(self): self._file.write(']}') def _row_start(self): self._file.write('{') def _row_between_relations(self): self._file.write(',') def _row_end(self): self._file.write('}\n') def _item_between_couplets(self): pass def _write_item(self, left, right, prefix_separator): if right is not _ud.Undef(): if prefix_separator: self._file.write(', ') self._write_atom(left) self._file.write(': {"type":') if isinstance(right.value, _rdflib.URIRef): self._file.write('"uri"') elif isinstance(right.value, _rdflib.BNode): self._file.write('"bnode"') else: self._file.write('"literal"') lit = _rdflib.Literal(right.value) if isinstance(lit.datatype, str): self._file.write(', "datatype":"') self._file.write(lit.datatype) self._file.write('"') self._file.write(', "value":') self._write_atom(right) self._file.write('}\n') def _write_atom(self, atom: _mo.Atom): self._file.write('"' + str(atom.value) + '"') assert(_clans.is_absolute_member(table)) sorted_lefts = sorted(lefts) if out_format == 'csv': writer = Csv(clan=table, ordered_lefts=sorted_lefts) elif out_format == 'json': writer = Json(clan=table, ordered_lefts=sorted_lefts) else: raise AssertionError("'out_format' must be 'csv' or 'json'") writer.export(file_or_path)
def is_absolute_graph(obj: _mo.MathObject) -> bool: """Return ``True`` if ``obj`` is an :term:`absolute` `graph`, ``False`` if not.""" return _clans.is_absolute_member(obj) and _check_graph(obj)
def is_absolute_graph(obj: _mo.MathObject) -> bool: """Return ``True`` if ``obj`` is an :term:`absolute` `graph`.""" return _clans.is_absolute_member(obj) and _check_graph(obj)