Example #1
0
    def test_export_to_file_append(self):

        exporter = MagicMock()
        product = {
            'exporter': exporter,
            'format': 'the format',
            'append': True,
            'append_to_filename': 'the filename',
        }

        # Do append, pass value of append_to_filename to exporter
        self.assertEqual(
            exporter(),
            export_to_file('host', product, 'file', 'catalogue', 'collection'))
        exporter.assert_called_with(ANY,
                                    'file',
                                    'the format',
                                    append='the filename',
                                    filter=None)

        # Don't append
        product['append'] = False
        self.assertEqual(
            exporter(),
            export_to_file('host', product, 'file', 'catalogue', 'collection'))
        exporter.assert_called_with(ANY,
                                    'file',
                                    'the format',
                                    append=False,
                                    filter=None)
Example #2
0
    def test_export_encrypt_file(self, mock_encrypt_file):

        exporter = MagicMock()
        product = {
            'exporter': exporter,
            'format': 'the format',
            'encryption_key': 'any key'
        }

        # Do append, pass value of append_to_filename to exporter
        export_to_file('host', product, 'file', 'catalogue', 'collection')
        mock_encrypt_file.assert_called_with('file', 'any key')
Example #3
0
    def test_export_to_file_entity_filters(self, mock_group_filter, mock_buffered_iterable, mock_graphql_streaming):
        from gobexport.exporter import export_to_file
        mock_entity_filter = MagicMock()
        mock_exporter = MagicMock()

        product = {
            'api_type': 'graphql_streaming',
            'query': 'some query',
            'exporter': mock_exporter,
            'format': 'the format',
            'unfold': 'true_or_false',
            'entity_filters': [
                mock_entity_filter,
            ]
        }
        result = export_to_file('host', product, 'file', 'catalogue', 'collection')

        mock_filter = mock_group_filter.return_value

        mock_group_filter.assert_called_with([mock_entity_filter])
        mock_exporter.assert_called_with(mock_buffered_iterable.return_value,
                                         'file',
                                         'the format',
                                         append=False,
                                         filter=mock_group_filter.return_value)

        # Assert the reset function is called on the filter
        mock_filter.reset.assert_called()
Example #4
0
def test_export_to_file(monkeypatch):
    global records
    monkeypatch.setitem(__builtins__, 'open', mock_open)
    monkeypatch.setattr(gobexport.api, 'API', MockAPI)
    monkeypatch.setattr(gobexport.graphql, 'GraphQL', MockGraphQL)

    before_each(monkeypatch)
    from gobexport.exporter import export_to_file

    # Test DAT export
    catalogue = 'meetbouten'
    collection = 'meetbouten'

    # Get the configuration for this collection
    config = CONFIG_MAPPING[catalogue][collection]

    export_to_file('host', config.products['dat'], '/tmp/ttt', catalogue, collection)
    assert(MockFile.s == '$$2$$||125,6|10,1||||||||||||||POINT (125.6 10.1)\n')

    MockFile.s = ''

    catalogue = 'gebieden'
    collection = 'stadsdelen'

    # Get the configuration for this collection
    config = CONFIG_MAPPING[catalogue][collection]
    format = config.products['csv_actueel'].get('format')

    export_to_file('host', config.products['csv_actueel'], '/tmp/ttt', catalogue, collection)
    expected_result = 'identificatie;code;naam;beginGeldigheid;eindGeldigheid;documentdatum;documentnummer;ligtIn:BRK.GME.identificatie;ligtIn:BRK.GME.naam;geometrie\r\n2;;;;;;;;;POINT (125.6 10.1)\r\n'
    assert(MockFile.s == expected_result)

    MockFile.s = ''

    # Get the configuration for this collection
    config = MockConfig

    export_to_file('host', config.products['csv'], '/tmp/ttt', catalogue, collection)
    expected_result = 'identificatie;boolean;geometrie\r\n2;J;POINT (125.6 10.1)\r\n'
    assert(MockFile.s == expected_result)

    format = config.products['shape'].get('format')

    file_name = 'esri.shp'

    # Update records to contain an geometry collection
    records = [{'identificatie': '2', 'boolean': False, 'geometrie': {'type': 'GeometryCollection', 'geometries': [{'type': 'LineString', 'coordinates': [[125891.16, 480253.38], [125891.07, 480253.34]]}, {'type': 'Polygon', 'coordinates': [[[125891.16, 480253.38], [125893.06, 480250.0], [125892.57, 480250.0]]]}]}}]

    export_to_file('host', config.products['shape'], file_name, catalogue, collection)

    # Remove created files
    for file in ['esri.shp', 'esri.dbf', 'esri.shx', 'esri.prj']:
        assert(os.path.isfile(file))
        os.remove(file)
Example #5
0
    def test_export_to_file_objectstore(self, mock_buffered_iterable, mock_objectstore_file):
        from gobexport.exporter import export_to_file

        product = {
            'api_type': 'objectstore',
            'exporter': MagicMock(),
            'format': 'the format',
            'config': 'the config',
        }
        result = export_to_file('host', product, 'file', 'catalogue', 'collection', False)
        mock_objectstore_file.assert_called_with(product['config'], row_formatter=None)

        mock_buffered_iterable.assert_called_with(mock_objectstore_file.return_value, 'source', buffer_items=False)
        product['exporter'].assert_called_with(mock_buffered_iterable.return_value, 'file', 'the format',
                                               append=False, filter=None)
Example #6
0
    def test_export_to_file_graphql_streaming_with_unfold(self, mock_buffered_iterable, mock_graphql_streaming):
        from gobexport.exporter import export_to_file

        product = {
            'api_type': 'graphql_streaming',
            'query': 'some query',
            'exporter': MagicMock(),
            'format': 'the format',
            'unfold': 'true_or_false',
            'sort': 'sorter',
            'row_formatter': 'row_form',
        }
        result = export_to_file('host', product, 'file', 'catalogue', 'collection', False)
        mock_graphql_streaming.assert_called_with('host', product['query'], unfold='true_or_false', sort='sorter',
                                                  row_formatter='row_form', cross_relations=False, batch_size=None,
                                                  secure_user=None)
Example #7
0
    def test_export_to_file_graphql_streaming(self, mock_buffered_iterable, mock_graphql_streaming):
        from gobexport.exporter import export_to_file

        product = {
            'api_type': 'graphql_streaming',
            'secure_user': '******',
            'query': 'some query',
            'exporter': MagicMock(),
            'format': 'the format',
        }
        result = export_to_file('host', product, 'file', 'catalogue', 'collection', False)
        mock_graphql_streaming.assert_called_with('host', product['query'], row_formatter=None, sort=None,
                                                  unfold=False, cross_relations=False, batch_size=None,
                                                  secure_user='******')

        mock_buffered_iterable.assert_called_with(mock_graphql_streaming.return_value, 'source', buffer_items=False)
        product['exporter'].assert_called_with(mock_buffered_iterable.return_value, 'file', 'the format',
                                               append=False, filter=None)
Example #8
0
def _export_collection(host, catalogue, collection, product_name,
                       destination):  # noqa: C901
    """Export a collection from a catalog

    :param host: The API host to retrieve the catalog and collection from
    :param catalog: The name of the catalog
    :param collection: The name of the collection
    :param product_name: The name of the product to export
    :param destination: The destination of the resulting output file(s)
    :return:
    """
    logger.info(f"Export {catalogue}:{collection} to {destination} started.")

    # Get the configuration for this collection
    config = CONFIG_MAPPING[catalogue][collection]
    resolve_config_filenames(config)

    files = []

    # If a product has been supplied, export only that product
    try:
        products = {
            product_name: config.products[product_name]
        } if product_name else config.products
    except KeyError:
        logger.error(f"Product '{product_name}' not found")
        return

    # Start exporting each product
    for name, product in products.items():
        logger.info(
            f"Export to file '{name}' started, API type: {product.get('api_type', 'REST')}"
        )

        # Get name of local file to write results to
        results_file = _get_filename(
            product['filename']
        ) if destination == "Objectstore" else product['filename']

        if product.get('append', False):
            # Add .to_append to avoid writing to the previously created file
            results_file = _get_filename(f"{product['filename']}.to_append")
            product['append_to_filename'] = _get_filename(product['filename']) \
                if destination == "Objectstore" \
                else product['filename']

        # Buffer items if they are used multiple times. This prevents calling API multiple times for same data
        source = product_source(product)
        buffer_items = len(
            list(
                filter(lambda p: product_source(p) == source,
                       config.products.values()))) > 1

        logger.info(
            f"Buffering API output {'enabled' if buffer_items else 'disabled'}"
        )
        try:
            row_count = _with_retries(
                lambda: export_to_file(host,
                                       product,
                                       results_file,
                                       catalogue,
                                       product.get('collection', collection),
                                       buffer_items=buffer_items))
        except Exception as e:
            logger.error(f"Export to local file {name} failed: {str(e)}.")
        else:
            logger.info(f"{row_count} records exported to local file {name}.")

            if product.get('append', False):
                # Append temporary file to existing file and cleanup temp file
                _append_to_file(results_file, product['append_to_filename'])
                os.remove(results_file)
            else:
                # Do not add file to files again when appending
                files.append({
                    'temp_location': results_file,
                    'distribution': product['filename'],
                    'mime_type': product['mime_type']
                })

            # Add extra result files (e.g. .prj file)
            extra_files = product.get('extra_files', [])
            files.extend([{
                'temp_location': _get_filename(file['filename']),
                'distribution': file['filename'],
                'mime_type': file['mime_type']
            } for file in extra_files])

    if destination == "Objectstore":
        # Get objectstore connection
        config = get_datastore_config(GOB_OBJECTSTORE)
        datastore = DatastoreFactory.get_datastore(config)
        datastore.connect()

        assert isinstance(datastore, ObjectDatastore)

        connection = datastore.connection
        logger.info(
            f"Connection to {destination} {datastore.user} has been made.")

    # Start distribution of all resulting files
    for file in files:
        logger.info(f"Write file '{file['distribution']}'.")
        if destination == "Objectstore":
            # Distribute to pre-final location
            container = f'{CONTAINER_BASE}/{EXPORT_DIR}/{catalogue}/'
            with open(file['temp_location'], 'rb') as fp:
                try:
                    distribute_to_objectstore(connection, container,
                                              file['distribution'], fp,
                                              file['mime_type'])
                except GOBException as e:
                    logger.error(
                        f"Failed to copy to {destination} on location: {container}{file['distribution']}. \
                                 Error: {e}")
                    return False

            logger.info(
                f"File copied to {destination} on location: {container}{file['distribution']}."
            )

            cleanup_datefiles(
                connection, CONTAINER_BASE,
                f"{EXPORT_DIR}/{catalogue}/{file['distribution']}")

            # Delete temp file
            os.remove(file['temp_location'])

        elif destination == "File":
            logger.info(f"Export is written to {file['distribution']}.")

    logger.info("Export completed")