diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml new file mode 100644 index 0000000..57e57c0 --- /dev/null +++ b/.github/workflows/python-package.yml @@ -0,0 +1,38 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Python package + +on: + push: + paths-ignore: + - 'docs/**' + pull_request: + branches: '*' + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: [3.7, 3.8, 3.9] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install pycodestyle + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with pycodestyle + run: | + pycodestyle tableaudocumentapi test samples + - name: Test + run: | + python setup.py test diff --git a/.travis.yml b/.travis.yml index 392878d..1926a25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,11 +2,10 @@ language: python cache: pip python: - - "2.7" - "3.4" - "3.5" - "3.6" - - "pypy" + - "pypy3" # command to install dependencies install: - "pip install -e ." diff --git a/README.md b/README.md index 3f0d872..11ff9cf 100644 --- a/README.md +++ b/README.md @@ -33,3 +33,6 @@ Features include: - Get all fields in use by certain sheets in a workbook We don't yet support creating files from scratch, adding extracts into workbooks or data sources, or updating field information + + +As of 2021, this SDK no longer supports Python 2. \ No newline at end of file diff --git a/publish.sh b/publish.sh index 99a3115..90b42cb 100755 --- a/publish.sh +++ b/publish.sh @@ -5,5 +5,4 @@ set -e rm -rf dist python setup.py sdist python setup.py bdist_wheel -python3 setup.py bdist_wheel twine upload dist/* diff --git a/setup.py b/setup.py index 59270ed..33f724e 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,5 @@ -try: - from setuptools import setup -except ImportError: - from distutils.core import setup - +from setuptools import setup + setup( name='tableaudocumentapi', version='0.6', diff --git a/tableaudocumentapi/datasource.py b/tableaudocumentapi/datasource.py index fa5c7a5..8fa2773 100644 --- a/tableaudocumentapi/datasource.py +++ b/tableaudocumentapi/datasource.py @@ -9,16 +9,6 @@ from tableaudocumentapi.multilookup_dict import MultiLookupDict from tableaudocumentapi.xfile import xml_open -######## -# This is needed in order to determine if something is a string or not. It is necessary because -# of differences between python2 (basestring) and python3 (str). If python2 support is ever -# dropped, remove this and change the basestring references below to str -try: - basestring -except NameError: # pragma: no cover - basestring = str -######## - _ColumnObjectReturnTuple = collections.namedtuple('_ColumnObjectReturnTupleType', ['id', 'object']) @@ -38,7 +28,7 @@ class FieldDictionary(MultiLookupDict): def used_by_sheet(self, name): # If we pass in a string, no need to get complicated, just check to see if name is in # the field's list of worksheets - if isinstance(name, basestring): + if isinstance(name, str): return [x for x in self.values() if name in x.worksheets] # if we pass in a list, we need to check to see if any of the names in the list are in diff --git a/tableaudocumentapi/xfile.py b/tableaudocumentapi/xfile.py index d5568eb..12d7d6e 100644 --- a/tableaudocumentapi/xfile.py +++ b/tableaudocumentapi/xfile.py @@ -5,10 +5,7 @@ import zipfile import xml.etree.ElementTree as ET -try: - from distutils2.version import NormalizedVersion as Version -except ImportError: - from distutils.version import LooseVersion as Version +from distutils.version import LooseVersion as Version MIN_SUPPORTED_VERSION = Version("9.0") @@ -28,7 +25,7 @@ def xml_open(filename, expected_root=None): # Is the file a zip (.twbx or .tdsx) if zipfile.is_zipfile(filename): tree = get_xml_from_archive(filename) - else: + else: _register_all_namespaces() tree = ET.parse(filename) @@ -55,9 +52,11 @@ def temporary_directory(*args, **kwargs): finally: shutil.rmtree(d) -def _register_all_namespaces(): + +def _register_all_namespaces(): # TO DO: should look at the file to find namespaces, not hardcode this one - ET.register_namespace("user","http://www.tableausoftware.com/xml/user") + ET.register_namespace("user", "http://www.tableausoftware.com/xml/user") + def find_file_in_zip(zip_file): '''Returns the twb/tds file from a Tableau packaged file format. Packaged @@ -124,9 +123,9 @@ def save_into_archive(xml_tree, filename, new_filename=None): def _save_file(container_file, xml_tree, new_filename=None): - - _register_all_namespaces() # this shouldn't be necessary, should be done on open - + + _register_all_namespaces() # this shouldn't be necessary, should be done on open + if new_filename is None: new_filename = container_file diff --git a/test/assets/index.py b/test/assets/index.py index d6a8694..8b374c2 100644 --- a/test/assets/index.py +++ b/test/assets/index.py @@ -27,4 +27,3 @@ TWBX_WITH_CACHE_FILES = os.path.join(TEST_DIR, 'Cache.twbx') COMPLEX_TWB = os.path.join(TEST_DIR, 'filtering.twb') - diff --git a/test/bvt.py b/test/bvt.py index b40ffcb..038ba63 100644 --- a/test/bvt.py +++ b/test/bvt.py @@ -6,6 +6,7 @@ from tableaudocumentapi import Workbook, Datasource, Connection, ConnectionParser from tableaudocumentapi.xfile import TableauInvalidFileException, TableauVersionNotSupportedException + class ConnectionParserTests(unittest.TestCase): def test_can_extract_legacy_connection(self): diff --git a/test/test_xfile.py b/test/test_xfile.py index 0da0f73..9cdefd4 100644 --- a/test/test_xfile.py +++ b/test/test_xfile.py @@ -11,12 +11,11 @@ def test_find_file_in_zip_no_xml_file(self): badzip = zipfile.ZipFile(BAD_ZIP_FILE) self.assertIsNone(find_file_in_zip(badzip)) - def test_only_find_twbs(self): twb_from_twbx_with_cache = zipfile.ZipFile(TWBX_WITH_CACHE_FILES) self.assertEqual(find_file_in_zip(twb_from_twbx_with_cache), 'Superstore.twb') - -''' These tests won't pass the python 2 check, disabling until that is removed + + class Namespacing(unittest.TestCase): def assertContainsUserNamespace(self, filename): @@ -28,24 +27,24 @@ def assertContainsUserNamespace(self, filename): doc_beginning_excerpt += (in_file.readline().strip()) # first line should be xml tag lineCount += 1 found = doc_beginning_excerpt.rfind("xmlns:user=") - #print(doc_beginning_excerpt[found:found+10]) + # print(doc_beginning_excerpt[found:found+10]) self.assertRegex(doc_beginning_excerpt, "xmlns:user=") - + def test_save_preserves_namespace_twb(self): - filename = COMPLEX_TWB + filename = COMPLEX_TWB self.assertContainsUserNamespace(filename) wb = Workbook(filename) new_name = 'saved-as-twb.twb' wb.save_as(new_name) self.assertContainsUserNamespace(new_name) -''' -''' + +''' def demo_bug_ns_not_preserved_if_not_used(self): filename = TABLEAU_10_TDS self.assertContainsUserNamespace(filename) wb = Datasource.from_file(filename) - #wb.save() + #wb.save() new_name = 'saved-as-tds.tds' wb.save_as(new_name) self.assertContainsUserNamespace(new_name) <- throws @@ -54,8 +53,6 @@ def demo_bug_ns_not_preserved_if_not_used(self): none will be added. If there is a namespace but it *is not used* in the document, it will be stripped - Fix will be something like + Fix will be something like https://stackoverflow.com/questions/41937624/elementtree-why-are-my-namespace-declarations-stripped-out - ''' -