diff --git a/tabulator/__init__.py b/tabulator/__init__.py index d3a4b553..af7ccafe 100644 --- a/tabulator/__init__.py +++ b/tabulator/__init__.py @@ -3,10 +3,22 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals +import io +import os + + +# General from .stream import Stream from . import exceptions # Deprecated + from .topen import topen from .stream import Stream as Table + +# Version + +__version__ = io.open( + os.path.join(os.path.dirname(__file__), 'VERSION'), + encoding='utf-8').read().strip() diff --git a/tabulator/cli.py b/tabulator/cli.py index 88d21799..3572f626 100644 --- a/tabulator/cli.py +++ b/tabulator/cli.py @@ -6,7 +6,7 @@ import six import click -from .stream import Stream +import tabulator # Module API @@ -18,9 +18,10 @@ @click.option('--format') @click.option('--encoding') @click.option('--limit', type=click.INT) +@click.version_option(tabulator.__version__, message='%(version)s') def cli(source, limit, **options): options = {key: value for key, value in options.items() if value is not None} - with Stream(source, **options) as stream: + with tabulator.Stream(source, **options) as stream: cast = str if six.PY2: cast = unicode # noqa diff --git a/tabulator/config.py b/tabulator/config.py index ee6fd9bc..b48d97cf 100644 --- a/tabulator/config.py +++ b/tabulator/config.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals -# Module API +# General DEFAULT_SCHEME = 'file' DEFAULT_ENCODING = 'utf-8' diff --git a/tabulator/stream.py b/tabulator/stream.py index 55f8f801..7c109af6 100644 --- a/tabulator/stream.py +++ b/tabulator/stream.py @@ -304,6 +304,31 @@ def save(self, target, format=None, encoding=None, **options): writer = writer_class(**writer_options) writer.write(target, encoding, extended_rows) + @staticmethod + def test(source, scheme=None, format=None): + """Test if this source has supported scheme and format. + + Args: + source (str): stream source + scheme (str): stream scheme + format (str): stream format + + Returns: + bool: True if source source has supported scheme and format + + """ + if scheme is None: + scheme = helpers.detect_scheme(source) + if not scheme: + scheme = config.DEFAULT_SCHEME + if scheme not in config.LOADERS: + return False + if format is None: + format = helpers.detect_format(source) + if format not in config.PARSERS: + return False + return True + # Private def __extract_sample(self): diff --git a/tests/test_cli.py b/tests/test_cli.py index a8e893d5..682c6300 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -13,3 +13,10 @@ def test_cli(): result = runner.invoke(cli, ['data/table.csv']) assert result.exit_code == 0 assert result.output.startswith('id, name\n1, english\n2,') + + +def test_cli_version(): + runner = CliRunner() + result = runner.invoke(cli, ['--version']) + assert result.exit_code == 0 + assert len(result.output.split('.')) == 3 diff --git a/tests/test_init.py b/tests/test_init.py new file mode 100644 index 00000000..171f10df --- /dev/null +++ b/tests/test_init.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +from __future__ import division +from __future__ import print_function +from __future__ import absolute_import +from __future__ import unicode_literals + +import tabulator + + +# Tests + +def test_public_api(): + assert isinstance(tabulator.Stream, type) + assert isinstance(tabulator.exceptions, object) + assert len(tabulator.__version__.split('.')) == 3 diff --git a/tests/test_stream.py b/tests/test_stream.py index 879ad71a..7aee5b68 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -4,6 +4,7 @@ from __future__ import absolute_import from __future__ import unicode_literals +import io import pytest from tabulator import Stream, exceptions @@ -181,3 +182,43 @@ def test_stream_http_error(): stream = Stream('http://github.com/bad_path.csv') with pytest.raises(exceptions.HTTPError) as excinfo: stream.open() + + +# Tests [test] + +def test_stream_test_schemes(): + # Supported + assert Stream.test('path.csv') + assert Stream.test('file://path.csv') + assert Stream.test('http://example.com/path.csv') + assert Stream.test('https://example.com/path.csv') + assert Stream.test('ftp://example.com/path.csv') + assert Stream.test('ftps://example.com/path.csv') + assert Stream.test('path.csv', scheme='file') + # Not supported + assert not Stream.test('ssh://example.com/path.csv') + assert not Stream.test('bad://example.com/path.csv') + +def test_stream_test_formats(): + # Supported + assert Stream.test('path.csv') + assert Stream.test('path.json') + assert Stream.test('path.jsonl') + assert Stream.test('path.ndjson') + assert Stream.test('path.tsv') + assert Stream.test('path.xls') + assert Stream.test('path.ods') + assert Stream.test('path.no-format', format='csv') + # Not supported + assert not Stream.test('path.txt') + assert not Stream.test('path.bad') + +def test_stream_test_special(): + # Gsheet + assert Stream.test('https://docs.google.com/spreadsheets/d/id', format='csv') + # File-like + assert Stream.test(io.open('data/table.csv', encoding='utf-8'), format='csv') + # Text + assert Stream.test('text://name,value\n1,2', format='csv') + # Native + assert Stream.test([{'name': 'value'}])