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)
Example #3
0
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
Example #4
0
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
Example #5
0
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
Example #6
0
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)
Example #7
0
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)
Example #8
0
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)
Example #9
0
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)