From f12f3f59d144a62b4ec3900331b54ba077dd20b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Wed, 8 Jan 2020 15:23:59 +0100 Subject: [PATCH 01/99] The new lxml version requires python3>=3.5 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 33193a3b..3532d4c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: python python: - "2.7" - - "3.4" - "3.5" - "3.6" - "pypy-5.3.1" From c4fdc8f00dc14d8df25c9ee7331b7eeaafa7adbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Wed, 8 Jan 2020 15:25:49 +0100 Subject: [PATCH 02/99] Test with newer Python3 versions --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3532d4c4..5fed49f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,8 @@ python: - "2.7" - "3.5" - "3.6" + - "3.7" + - "3.8" - "pypy-5.3.1" # command to install dependencies install: From d2e27e72d9b588231a96bef0bc3c70d0127464dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Wed, 8 Jan 2020 15:30:03 +0100 Subject: [PATCH 03/99] Drop support for py3.4 --- docs/install.rst | 2 +- setup.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/install.rst b/docs/install.rst index 04d42531..54cb6482 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -45,7 +45,7 @@ Supported platforms agate supports the following versions of Python: * Python 2.7 -* Python 3.4+ +* Python 3.5+ * `PyPy `_ versions >= 4.0.0 It is tested primarily on OSX, but due to its minimal dependencies it should work perfectly on both Linux and Windows. diff --git a/setup.py b/setup.py index 71e02db2..2f89942d 100644 --- a/setup.py +++ b/setup.py @@ -33,9 +33,10 @@ 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Scientific/Engineering :: Information Analysis', From e2ffc175cbfcf1ba38b5367e959b8201710cc995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Wed, 8 Jan 2020 15:51:37 +0100 Subject: [PATCH 04/99] Fix pypy versions --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 33193a3b..92094283 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,8 @@ python: - "3.4" - "3.5" - "3.6" - - "pypy-5.3.1" + - "pypy2.7-6.0" + - "pypy3.5-6.0" # command to install dependencies install: - if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip install -r requirements-py3.txt; else pip install -r requirements-py2.txt; fi From a10ea7055ef3259b63e588280863bd5a694111dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Wed, 8 Jan 2020 15:55:14 +0100 Subject: [PATCH 05/99] Use the pypy aliases to always match the default release for Travis CI --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 92094283..c2faf7db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,8 @@ python: - "3.4" - "3.5" - "3.6" - - "pypy2.7-6.0" - - "pypy3.5-6.0" + - "pypy" + - "pypy3" # command to install dependencies install: - if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip install -r requirements-py3.txt; else pip install -r requirements-py2.txt; fi From 53a5ed68e6ce3167d59cb30b85d86652914babda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Wed, 8 Jan 2020 16:06:30 +0100 Subject: [PATCH 06/99] Revert to non-aliased versions to avoid getting bugs from a beta version --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c2faf7db..92094283 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,8 @@ python: - "3.4" - "3.5" - "3.6" - - "pypy" - - "pypy3" + - "pypy2.7-6.0" + - "pypy3.5-6.0" # command to install dependencies install: - if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip install -r requirements-py3.txt; else pip install -r requirements-py2.txt; fi From b5f2faf59860e5d31ea901e9103b8305281f5451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Wed, 8 Jan 2020 16:28:15 +0100 Subject: [PATCH 07/99] Fix UserWarning: __builtin__.type size changed, may indicate binary incompatibility --- requirements-py3.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements-py3.txt b/requirements-py3.txt index d1e9bd40..6d9e716b 100644 --- a/requirements-py3.txt +++ b/requirements-py3.txt @@ -14,3 +14,4 @@ python-slugify>=1.2.1 lxml>=3.6.0 cssselect>=0.9.1 leather>=0.3.2 +pypy-fix-cython-warning From d3fc10dd6bb200e61f56e52e9ba6b4d9da82b66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Wed, 8 Jan 2020 16:33:30 +0100 Subject: [PATCH 08/99] upgrade sqlite in travis test containers travis-ci/travis-ci#7873 --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index 92094283..ac47893a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,3 +12,9 @@ install: # command to run tests script: nosetests tests sudo: false +addons: + apt: + packages: + - sqlite3 + sources: + - travis-ci/sqlite3 From 5a4f7d800f846283fd94b3fd5629c14ab0bc237b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 15:40:26 +0100 Subject: [PATCH 09/99] Try to add new environments --- .travis.yml | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 696a091c..0009c2b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,44 @@ language: python -python: - - "2.7" - - "3.5" - - "3.6" - - "3.7" - - "3.8" - - "pypy2.7-6.0" - - "pypy3.5-6.0" +jobs: + include: + - name: "Python on Linux" + os: linux + python: + - "2.7" + - "3.5" + - "3.6" + - "3.7" + - "3.8" + - "pypy" + - "pypy2.7-6.0" + - "pypy2.7-7.0.0" + - "pypy3" + - "pypy3.5-6.0" + - "pypy3.5-7.0" + - "pypy3.6-7.0.0" + - name: "Python on macOS" + os: osx + osx_image: xcode11.2 # Python 3.7.4 running on macOS 10.14.4 + language: shell # 'language: python' is an error on Travis CI macOS + - name: "Python on Windows" + os: windows # Windows 10.0.17134 N/A Build 17134 + language: shell # 'language: python' is an error on Travis CI Windows + before_install: + - choco install python --version 3.8.0 + - choco install sqlite + - python -m pip install --upgrade pip + env: PATH=/c/Python38:/c/Python38/Scripts:$PATH # command to install dependencies install: - - if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip install -r requirements-py3.txt; else pip install -r requirements-py2.txt; fi + - if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip3 install -r requirements-py3.txt; else pip install -r requirements-py2.txt; fi # command to run tests script: nosetests tests -sudo: false addons: apt: packages: - sqlite3 sources: - travis-ci/sqlite3 + homebrew: + packages: + - sqlite3 From 98b621f5941f8898a0baab5c424d08834e670f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 15:40:45 +0100 Subject: [PATCH 10/99] Update Python versions --- tox.ini | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tox.ini b/tox.ini index 3cde685d..d4962599 100644 --- a/tox.ini +++ b/tox.ini @@ -19,6 +19,12 @@ deps = {[testenv:py33]deps} [testenv:py36] deps = {[testenv:py33]deps} +[testenv:py37] +deps = {[testenv:py33]deps} + +[testenv:py38] +deps = {[testenv:py33]deps} + [testenv:pypy] deps = {[testenv:py27]deps} From 1250066ee4148e040ab6add2e1ced908da24d3d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 15:54:29 +0100 Subject: [PATCH 11/99] Correct Linux builds; allow failure on OSes other than Linux --- .travis.yml | 66 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0009c2b4..eba70432 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,33 +1,67 @@ language: python jobs: include: - - name: "Python on Linux" - os: linux - python: - - "2.7" - - "3.5" - - "3.6" - - "3.7" - - "3.8" - - "pypy" - - "pypy2.7-6.0" - - "pypy2.7-7.0.0" - - "pypy3" - - "pypy3.5-6.0" - - "pypy3.5-7.0" - - "pypy3.6-7.0.0" + - name: "Python 2.7 on Linux" + os: linux + python: "2.7" + - name: "Python 3.5 on Linux" + os: linux + python: "3.5" + - name: "Python 3.6 on Linux" + os: linux + python: "3.6" + - name: "Python 3.7 on Linux" + os: linux + python: "3.7" + - name: "Python 3.8 on Linux" + os: linux + python: "3.8" + - name: "Python pypy on Linux" + os: linux + python: "pypy" + - name: "Python pypy2.7-6.0 on Linux" + os: linux + python: "pypy2.7-6.0" + - name: "Python pypy2.7-7.0.0 on Linux" + os: linux + python: "pypy2.7-7.0.0" + - name: "Python pypy3 on Linux" + os: linux + python: "pypy3" + - name: "Python pypy3.5-6.0 on Linux" + os: linux + python: "pypy3.5-6.0" + - name: "Python pypy3.5-7.0 on Linux" + os: linux + python: "pypy3.5-7.0" + - name: "Python pypy3.6-7.0.0 on Linux" + os: linux + python: "pypy3.6-7.0.0" - name: "Python on macOS" os: osx + python: "3.7" osx_image: xcode11.2 # Python 3.7.4 running on macOS 10.14.4 language: shell # 'language: python' is an error on Travis CI macOS + before_install: + - python3 -m pip install --upgrade pip + - python3 --version - name: "Python on Windows" os: windows # Windows 10.0.17134 N/A Build 17134 + python: "3.8" language: shell # 'language: python' is an error on Travis CI Windows before_install: - choco install python --version 3.8.0 - choco install sqlite - - python -m pip install --upgrade pip + - python3 -m pip install --upgrade pip + - python3 --version env: PATH=/c/Python38:/c/Python38/Scripts:$PATH +# allow failure on OSes other than Linux +matrix: + - allow_failures: + - os: + - osx + - windows +fast_finish: true # command to install dependencies install: - if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip3 install -r requirements-py3.txt; else pip install -r requirements-py2.txt; fi From dc65b15c481b2f6f03664103f9493387ff9256e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 15:57:54 +0100 Subject: [PATCH 12/99] Merge jobs and matrix --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index eba70432..48477cc6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,13 +55,12 @@ jobs: - python3 -m pip install --upgrade pip - python3 --version env: PATH=/c/Python38:/c/Python38/Scripts:$PATH -# allow failure on OSes other than Linux -matrix: + # allow failure on OSes other than Linux - allow_failures: - os: - osx - windows -fast_finish: true + - fast_finish: true # command to install dependencies install: - if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip3 install -r requirements-py3.txt; else pip install -r requirements-py2.txt; fi From 54235c730b4f7006de679a6afe08d0d94830df52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 16:09:33 +0100 Subject: [PATCH 13/99] Fix YAML --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 48477cc6..e2678d61 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: python jobs: - include: + - include: - name: "Python 2.7 on Linux" os: linux python: "2.7" From f076fed4d4b8dffed92852d8c11de6f4a16e3230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 16:10:51 +0100 Subject: [PATCH 14/99] Move recent versions to the top -- making the most recent version the default one --- .travis.yml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index e2678d61..a07e121a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,30 +1,21 @@ language: python jobs: - include: - - name: "Python 2.7 on Linux" - os: linux - python: "2.7" - - name: "Python 3.5 on Linux" - os: linux - python: "3.5" - - name: "Python 3.6 on Linux" + - name: "Python 3.8 on Linux" os: linux - python: "3.6" + python: "3.8" - name: "Python 3.7 on Linux" os: linux python: "3.7" - - name: "Python 3.8 on Linux" - os: linux - python: "3.8" - - name: "Python pypy on Linux" + - name: "Python 3.6 on Linux" os: linux - python: "pypy" - - name: "Python pypy2.7-6.0 on Linux" + python: "3.6" + - name: "Python 3.5 on Linux" os: linux - python: "pypy2.7-6.0" - - name: "Python pypy2.7-7.0.0 on Linux" + python: "3.5" + - name: "Python 2.7 on Linux" os: linux - python: "pypy2.7-7.0.0" + python: "2.7" - name: "Python pypy3 on Linux" os: linux python: "pypy3" @@ -37,6 +28,15 @@ jobs: - name: "Python pypy3.6-7.0.0 on Linux" os: linux python: "pypy3.6-7.0.0" + - name: "Python pypy on Linux" + os: linux + python: "pypy" + - name: "Python pypy2.7-6.0 on Linux" + os: linux + python: "pypy2.7-6.0" + - name: "Python pypy2.7-7.0.0 on Linux" + os: linux + python: "pypy2.7-7.0.0" - name: "Python on macOS" os: osx python: "3.7" From 930631fa4f4df1291b3f757df5c551e85a22e654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 16:14:13 +0100 Subject: [PATCH 15/99] Try a simplification for the default Linux OS --- .travis.yml | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index a07e121a..0c731cae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,41 +1,30 @@ language: python +os: linux jobs: - include: - name: "Python 3.8 on Linux" - os: linux python: "3.8" - name: "Python 3.7 on Linux" - os: linux python: "3.7" - name: "Python 3.6 on Linux" - os: linux python: "3.6" - name: "Python 3.5 on Linux" - os: linux python: "3.5" - name: "Python 2.7 on Linux" - os: linux python: "2.7" - name: "Python pypy3 on Linux" - os: linux python: "pypy3" - name: "Python pypy3.5-6.0 on Linux" - os: linux python: "pypy3.5-6.0" - name: "Python pypy3.5-7.0 on Linux" - os: linux python: "pypy3.5-7.0" - name: "Python pypy3.6-7.0.0 on Linux" - os: linux python: "pypy3.6-7.0.0" - name: "Python pypy on Linux" - os: linux python: "pypy" - name: "Python pypy2.7-6.0 on Linux" - os: linux python: "pypy2.7-6.0" - name: "Python pypy2.7-7.0.0 on Linux" - os: linux python: "pypy2.7-7.0.0" - name: "Python on macOS" os: osx From 78bb2e6070d6ef9559faf59971432a817ea979a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 16:21:47 +0100 Subject: [PATCH 16/99] Try to make it even more simple --- .travis.yml | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0c731cae..facd3f71 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,31 +1,20 @@ language: python os: linux +python: + - "3.8" + - "3.7" + - "3.6" + - "3.5" + - "2.7" + - "pypy3" + - "pypy3.5-6.0" + - "pypy3.5-7.0" + - "pypy3.6-7.0.0" + - "pypy" + - "pypy2.7-6.0" + - "pypy2.7-7.0.0" jobs: - include: - - name: "Python 3.8 on Linux" - python: "3.8" - - name: "Python 3.7 on Linux" - python: "3.7" - - name: "Python 3.6 on Linux" - python: "3.6" - - name: "Python 3.5 on Linux" - python: "3.5" - - name: "Python 2.7 on Linux" - python: "2.7" - - name: "Python pypy3 on Linux" - python: "pypy3" - - name: "Python pypy3.5-6.0 on Linux" - python: "pypy3.5-6.0" - - name: "Python pypy3.5-7.0 on Linux" - python: "pypy3.5-7.0" - - name: "Python pypy3.6-7.0.0 on Linux" - python: "pypy3.6-7.0.0" - - name: "Python pypy on Linux" - python: "pypy" - - name: "Python pypy2.7-6.0 on Linux" - python: "pypy2.7-6.0" - - name: "Python pypy2.7-7.0.0 on Linux" - python: "pypy2.7-7.0.0" - name: "Python on macOS" os: osx python: "3.7" From 31df35c0432e3f4b4c7257b4d7cdc784c3bccb19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 16:29:08 +0100 Subject: [PATCH 17/99] Fix the macOS lxml build --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index facd3f71..c6264de1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,7 @@ jobs: language: shell # 'language: python' is an error on Travis CI macOS before_install: - python3 -m pip install --upgrade pip + - CFLAGS="-O0" STATIC_DEPS=true python3 -m pip install lxml - python3 --version - name: "Python on Windows" os: windows # Windows 10.0.17134 N/A Build 17134 From 047e1a1c018e29d300899204cc7e8a9b1f2431ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 16:30:27 +0100 Subject: [PATCH 18/99] Names are not necessary --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index c6264de1..020bc3dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,8 +15,7 @@ python: - "pypy2.7-7.0.0" jobs: - include: - - name: "Python on macOS" - os: osx + - os: osx python: "3.7" osx_image: xcode11.2 # Python 3.7.4 running on macOS 10.14.4 language: shell # 'language: python' is an error on Travis CI macOS @@ -24,8 +23,7 @@ jobs: - python3 -m pip install --upgrade pip - CFLAGS="-O0" STATIC_DEPS=true python3 -m pip install lxml - python3 --version - - name: "Python on Windows" - os: windows # Windows 10.0.17134 N/A Build 17134 + - os: windows # Windows 10.0.17134 N/A Build 17134 python: "3.8" language: shell # 'language: python' is an error on Travis CI Windows before_install: From 7a4ad8baa832f8c21cb8efb62588a5231eef0beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 16:33:10 +0100 Subject: [PATCH 19/99] Fix the Windows build; trace Python versions better --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 020bc3dd..efe60dee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,14 +23,15 @@ jobs: - python3 -m pip install --upgrade pip - CFLAGS="-O0" STATIC_DEPS=true python3 -m pip install lxml - python3 --version + - python --version - os: windows # Windows 10.0.17134 N/A Build 17134 python: "3.8" language: shell # 'language: python' is an error on Travis CI Windows before_install: - choco install python --version 3.8.0 - choco install sqlite - - python3 -m pip install --upgrade pip - - python3 --version + - python -m pip install --upgrade pip + - python --version env: PATH=/c/Python38:/c/Python38/Scripts:$PATH # allow failure on OSes other than Linux - allow_failures: From 0d10e25353f18fe2117b7d6523694af6fd2e56ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 16:45:14 +0100 Subject: [PATCH 20/99] Add --user to pip install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index efe60dee..4b9cde8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ jobs: - fast_finish: true # command to install dependencies install: - - if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip3 install -r requirements-py3.txt; else pip install -r requirements-py2.txt; fi + - if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip3 install --user -r requirements-py3.txt; else pip install --user -r requirements-py2.txt; fi # command to run tests script: nosetests tests addons: From 90237c8c1368bfff93e0af0babd5802b72616633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 17:08:18 +0100 Subject: [PATCH 21/99] Remove --user from pip install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4b9cde8d..efe60dee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ jobs: - fast_finish: true # command to install dependencies install: - - if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip3 install --user -r requirements-py3.txt; else pip install --user -r requirements-py2.txt; fi + - if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip3 install -r requirements-py3.txt; else pip install -r requirements-py2.txt; fi # command to run tests script: nosetests tests addons: From 45823ef59d98c82f8bd5c7f1ce886529da15c1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 30 Jan 2020 17:14:23 +0100 Subject: [PATCH 22/99] Add a virtualenv on macOS, and some caching --- .travis.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.travis.yml b/.travis.yml index efe60dee..ec10f0d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,9 +21,20 @@ jobs: language: shell # 'language: python' is an error on Travis CI macOS before_install: - python3 -m pip install --upgrade pip + - python3 -m pip install --upgrade virtualenv + - virtualenv -p python3 --system-site-packages "$HOME/venv" + - source "$HOME/venv/bin/activate" - CFLAGS="-O0" STATIC_DEPS=true python3 -m pip install lxml - python3 --version - python --version + env: + - HOMEBREW_NO_INSTALL_CLEANUP=1 + - HOMEBREW_NO_ANALYTICS=1 + before_cache: + - rm -f "$HOME/Library/Caches/pip/log/debug.log" + cache: + directories: + - "$HOME/Library/Caches/pip" - os: windows # Windows 10.0.17134 N/A Build 17134 python: "3.8" language: shell # 'language: python' is an error on Travis CI Windows From 4b80d0bb2592fce0d0488747c9a92b596785bf9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Fri, 31 Jan 2020 01:09:42 +0100 Subject: [PATCH 23/99] Add lxml for win64 from a pre-built wheel --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index ec10f0d0..56c1d329 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,6 +42,7 @@ jobs: - choco install python --version 3.8.0 - choco install sqlite - python -m pip install --upgrade pip + - python -m pip install "https://files.pythonhosted.org/packages/82/99/6f9263fda49f7c5c768386826aa0a829cbebc2719a911e50f9e582b96cfb/lxml-4.5.0-cp38-cp38-win_amd64.whl" - python --version env: PATH=/c/Python38:/c/Python38/Scripts:$PATH # allow failure on OSes other than Linux From be174734391fd2ad16f1b85b8ba8d90c6c86513b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Fri, 31 Jan 2020 01:19:12 +0100 Subject: [PATCH 24/99] Make Python 3 the default (fixes build issues on Win64 and macOS, too, where TRAVIS_PYTHON_VERSION is not defined) --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 56c1d329..af80cd23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,7 +42,7 @@ jobs: - choco install python --version 3.8.0 - choco install sqlite - python -m pip install --upgrade pip - - python -m pip install "https://files.pythonhosted.org/packages/82/99/6f9263fda49f7c5c768386826aa0a829cbebc2719a911e50f9e582b96cfb/lxml-4.5.0-cp38-cp38-win_amd64.whl" + - python -m pip install "https://files.pythonhosted.org/packages/82/99/6f9263fda49f7c5c768386826aa0a829cbebc2719a911e50f9e582b96cfb/lxml-4.5.0-cp38-cp38-win_amd64.whl" # see https://pypi.org/simple/lxml/ - python --version env: PATH=/c/Python38:/c/Python38/Scripts:$PATH # allow failure on OSes other than Linux @@ -53,7 +53,7 @@ jobs: - fast_finish: true # command to install dependencies install: - - if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip3 install -r requirements-py3.txt; else pip install -r requirements-py2.txt; fi + - if [[ $TRAVIS_PYTHON_VERSION == 2* ]]; then pip install -r requirements-py2.txt; else pip3 install -r requirements-py3.txt; fi # command to run tests script: nosetests tests addons: From 683907079276d4cb7964e79cbbe42966fc863dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Fri, 31 Jan 2020 01:25:58 +0100 Subject: [PATCH 25/99] Give it a try without specifying the lxml wheel --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index af80cd23..c2103e4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,7 +42,6 @@ jobs: - choco install python --version 3.8.0 - choco install sqlite - python -m pip install --upgrade pip - - python -m pip install "https://files.pythonhosted.org/packages/82/99/6f9263fda49f7c5c768386826aa0a829cbebc2719a911e50f9e582b96cfb/lxml-4.5.0-cp38-cp38-win_amd64.whl" # see https://pypi.org/simple/lxml/ - python --version env: PATH=/c/Python38:/c/Python38/Scripts:$PATH # allow failure on OSes other than Linux From d1b38863ab5795926476e61d125f95bd2e1c8ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 16:28:12 +0100 Subject: [PATCH 26/99] Fix YAML typos --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index c2103e4d..aad9bc39 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ python: - "pypy2.7-6.0" - "pypy2.7-7.0.0" jobs: - - include: + include: - os: osx python: "3.7" osx_image: xcode11.2 # Python 3.7.4 running on macOS 10.14.4 @@ -45,11 +45,11 @@ jobs: - python --version env: PATH=/c/Python38:/c/Python38/Scripts:$PATH # allow failure on OSes other than Linux - - allow_failures: + allow_failures: - os: - osx - windows - - fast_finish: true + fast_finish: true # command to install dependencies install: - if [[ $TRAVIS_PYTHON_VERSION == 2* ]]; then pip install -r requirements-py2.txt; else pip3 install -r requirements-py3.txt; fi From 86e1a85c83f9fc7318dee63d4f99c6828198918d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 16:34:10 +0100 Subject: [PATCH 27/99] Correct TRAVIS_PYTHON_VERSION for pypy --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index aad9bc39..b64f0641 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ jobs: fast_finish: true # command to install dependencies install: - - if [[ $TRAVIS_PYTHON_VERSION == 2* ]]; then pip install -r requirements-py2.txt; else pip3 install -r requirements-py3.txt; fi + - if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then pip install -r requirements-py2.txt; else pip3 install -r requirements-py3.txt; fi # command to run tests script: nosetests tests addons: From dd1e3ccded44c545ed8f923213affb846a643529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 16:36:31 +0100 Subject: [PATCH 28/99] Fix YAML typos for allow_failures --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b64f0641..d94633d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,9 +46,8 @@ jobs: env: PATH=/c/Python38:/c/Python38/Scripts:$PATH # allow failure on OSes other than Linux allow_failures: - - os: - - osx - - windows + - os: osx + - os: windows fast_finish: true # command to install dependencies install: From 480f7984a1dc4f599a898f92b2b9077cbd2398cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 18:41:13 +0100 Subject: [PATCH 29/99] Investigate on failing on tests on PyPy3 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d94633d8..7c14e091 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,7 +53,7 @@ jobs: install: - if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then pip install -r requirements-py2.txt; else pip3 install -r requirements-py3.txt; fi # command to run tests -script: nosetests tests +script: for s in tests/*.py; do nosetests -v "$f"; done addons: apt: packages: From 3bfdfc511676fd4b9e8452b0923c627480f7de23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 18:52:02 +0100 Subject: [PATCH 30/99] Keep the older command --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7c14e091..fea8ba47 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,7 +53,8 @@ jobs: install: - if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then pip install -r requirements-py2.txt; else pip3 install -r requirements-py3.txt; fi # command to run tests -script: for s in tests/*.py; do nosetests -v "$f"; done +#script: nosetests tests +script: for s in tests/*.py; do nosetests -v "$s"; done addons: apt: packages: From 1de2039beb6887b3045cb2a14ef9a6e7079d87fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 18:57:21 +0100 Subject: [PATCH 31/99] Temporarily deactivate the working Python versions --- .travis.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index fea8ba47..8d4cff2c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,19 @@ language: python os: linux python: - - "3.8" - - "3.7" - - "3.6" - - "3.5" - - "2.7" +# These now work; we deactivate them to investigate pypy3 quicker +#OK - "3.8" +#OK - "3.7" +#OK - "3.6" +#OK - "3.5" +#OK - "2.7" - "pypy3" - "pypy3.5-6.0" - "pypy3.5-7.0" - "pypy3.6-7.0.0" - - "pypy" - - "pypy2.7-6.0" - - "pypy2.7-7.0.0" +#OK - "pypy" +#OK - "pypy2.7-6.0" +#OK - "pypy2.7-7.0.0" jobs: include: - os: osx From 31757dded59c769303a01263737f70f571b6663c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 18:58:27 +0100 Subject: [PATCH 32/99] SQLite is not needed --- .travis.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8d4cff2c..17033fe3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,12 +56,3 @@ install: # command to run tests #script: nosetests tests script: for s in tests/*.py; do nosetests -v "$s"; done -addons: - apt: - packages: - - sqlite3 - sources: - - travis-ci/sqlite3 - homebrew: - packages: - - sqlite3 From 5cae04d444dea2ec65462a62ad89db83fd97211c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 18:59:44 +0100 Subject: [PATCH 33/99] Exit with nosetests's status code if a test fails --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 17033fe3..9f202594 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,4 +55,4 @@ install: - if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then pip install -r requirements-py2.txt; else pip3 install -r requirements-py3.txt; fi # command to run tests #script: nosetests tests -script: for s in tests/*.py; do nosetests -v "$s"; done +script: for s in tests/*.py; do nosetests -v "$s" || exit $?; done From 9d8ab67f52038861c0c01a37f91a4d5e727dbaee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 19:14:57 +0100 Subject: [PATCH 34/99] =?UTF-8?q?Was=20'=F0=9F=91=8D'=20too=20funky=20for?= =?UTF-8?q?=20PyPy3=3F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_data_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_data_types.py b/tests/test_data_types.py index 2a51bc42..1520f05b 100644 --- a/tests/test_data_types.py +++ b/tests/test_data_types.py @@ -139,7 +139,7 @@ def test_test(self): self.assertEqual(self.type.test(datetime.timedelta(hours=4, minutes=10)), False) self.assertEqual(self.type.test('a'), False) self.assertEqual(self.type.test('A\nB'), False) - self.assertEqual(self.type.test(u'👍'), False) + self.assertEqual(self.type.test(u'⇔'), False) self.assertEqual(self.type.test('05_leslie3d_base'), False) self.assertEqual(self.type.test('2016-12-29'), False) self.assertEqual(self.type.test('2016-12-29T11:43:30Z'), False) From ae87ec7512fffe564239ee4c784529b5abb7254f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 19:22:44 +0100 Subject: [PATCH 35/99] cast() raises ValueError on PyPy when we use a Unicode string --- agate/data_types/number.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agate/data_types/number.py b/agate/data_types/number.py index d5fdc158..d24a2b8d 100644 --- a/agate/data_types/number.py +++ b/agate/data_types/number.py @@ -94,7 +94,7 @@ def cast(self, d): try: return Decimal(d) * sign - except InvalidOperation: + except (InvalidOperation, ValueError): pass raise CastError('Can not parse value "%s" as Decimal.' % d) From 0727093c6467357ed8ff57c2352908c6bbef2e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 19:51:01 +0100 Subject: [PATCH 36/99] JSON files shall be Unicode files (UTF-8 encoded by default). Make this explicit for platforms which may have different default encodings (cp1252, ...) --- agate/table/from_json.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/agate/table/from_json.py b/agate/table/from_json.py index 41956728..ef7fb60a 100644 --- a/agate/table/from_json.py +++ b/agate/table/from_json.py @@ -6,7 +6,7 @@ @classmethod -def from_json(cls, path, row_names=None, key=None, newline=False, column_types=None, **kwargs): +def from_json(cls, path, row_names=None, key=None, newline=False, column_types=None, encoding='utf-8', **kwargs): """ Create a new table from a JSON file. @@ -29,6 +29,11 @@ def from_json(cls, path, row_names=None, key=None, newline=False, column_types=N If `True` then the file will be parsed as "newline-delimited JSON". :param column_types: See :meth:`.Table.__init__`. + :param encoding: + According to RFC4627, JSON text shall be encoded in Unicode; the default encoding is + UTF-8. You can override this by using any encoding supported by your Python's open() function + if :code:`path` is a filepath. If passing in a file handle, it is assumed you have already opened it with the correct + encoding specified. """ from agate.table import Table @@ -42,7 +47,7 @@ def from_json(cls, path, row_names=None, key=None, newline=False, column_types=N for line in path: js.append(json.loads(line, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs)) else: - with open(path, 'r') as f: + with open(path, 'r', encoding=encoding) as f: for line in f: js.append(json.loads(line, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs)) else: From bea4eafe175d88b3c6af7a1315d1af6edfdf0ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 19:54:17 +0100 Subject: [PATCH 37/99] =?UTF-8?q?=F0=9F=91=8D=20was=20not=20the=20culprit;?= =?UTF-8?q?=20revert=20to=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_data_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_data_types.py b/tests/test_data_types.py index 1520f05b..2a51bc42 100644 --- a/tests/test_data_types.py +++ b/tests/test_data_types.py @@ -139,7 +139,7 @@ def test_test(self): self.assertEqual(self.type.test(datetime.timedelta(hours=4, minutes=10)), False) self.assertEqual(self.type.test('a'), False) self.assertEqual(self.type.test('A\nB'), False) - self.assertEqual(self.type.test(u'⇔'), False) + self.assertEqual(self.type.test(u'👍'), False) self.assertEqual(self.type.test('05_leslie3d_base'), False) self.assertEqual(self.type.test('2016-12-29'), False) self.assertEqual(self.type.test('2016-12-29T11:43:30Z'), False) From a437e6369a3f21412886d565fe0a8d5ffe13d422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 19:55:45 +0100 Subject: [PATCH 38/99] Re-enable all Python versions --- .travis.yml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9f202594..b0fba096 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,18 @@ language: python os: linux python: -# These now work; we deactivate them to investigate pypy3 quicker -#OK - "3.8" -#OK - "3.7" -#OK - "3.6" -#OK - "3.5" -#OK - "2.7" + - "3.8" + - "3.7" + - "3.6" + - "3.5" + - "2.7" - "pypy3" - "pypy3.5-6.0" - "pypy3.5-7.0" - "pypy3.6-7.0.0" -#OK - "pypy" -#OK - "pypy2.7-6.0" -#OK - "pypy2.7-7.0.0" + - "pypy" + - "pypy2.7-6.0" + - "pypy2.7-7.0.0" jobs: include: - os: osx @@ -54,5 +53,4 @@ jobs: install: - if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then pip install -r requirements-py2.txt; else pip3 install -r requirements-py3.txt; fi # command to run tests -#script: nosetests tests script: for s in tests/*.py; do nosetests -v "$s" || exit $?; done From c5355a9e207dc326134edead87dbd5ae9cbf7fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 20:16:54 +0100 Subject: [PATCH 39/99] Align from_json()'s logic on from_csv()'s logic; fixes issues with Python 2.7 --- agate/table/from_json.py | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/agate/table/from_json.py b/agate/table/from_json.py index ef7fb60a..f5163abd 100644 --- a/agate/table/from_json.py +++ b/agate/table/from_json.py @@ -2,7 +2,9 @@ from collections import OrderedDict from decimal import Decimal +import io import json +import six @classmethod @@ -40,6 +42,8 @@ def from_json(cls, path, row_names=None, key=None, newline=False, column_types=N if key is not None and newline: raise ValueError('key and newline may not be specified together.') + close = False + if newline: js = [] @@ -47,15 +51,33 @@ def from_json(cls, path, row_names=None, key=None, newline=False, column_types=N for line in path: js.append(json.loads(line, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs)) else: - with open(path, 'r', encoding=encoding) as f: - for line in f: - js.append(json.loads(line, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs)) + if six.PY2: + f = open(path, 'Urb') + else: + f = io.open(path, encoding=encoding) + + close = True + + if six.PY2: + kwargs['encoding'] = encoding + + for line in f: + js.append(json.loads(line, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs)) else: if hasattr(path, 'read'): js = json.load(path, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs) else: - with open(path, 'r') as f: - js = json.load(f, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs) + if six.PY2: + f = open(path, 'Urb') + else: + f = io.open(path, encoding=encoding) + + close = True + + if six.PY2: + kwargs['encoding'] = encoding + + js = json.load(f, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs) if isinstance(js, dict): if not key: @@ -63,4 +85,7 @@ def from_json(cls, path, row_names=None, key=None, newline=False, column_types=N js = js[key] + if close: + f.close() + return Table.from_object(js, row_names=row_names, column_types=column_types) From ba7406d72be98502a2d311dc0f7a00b43f4f38df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 20:19:58 +0100 Subject: [PATCH 40/99] Remove unnecessary modules --- requirements-py3.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements-py3.txt b/requirements-py3.txt index 6d9e716b..d1e9bd40 100644 --- a/requirements-py3.txt +++ b/requirements-py3.txt @@ -14,4 +14,3 @@ python-slugify>=1.2.1 lxml>=3.6.0 cssselect>=0.9.1 leather>=0.3.2 -pypy-fix-cython-warning From 295bcf46259ae18250abc7ded4c2e38eff7871b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 20:36:11 +0100 Subject: [PATCH 41/99] test_from_json_file_like_object() : Make sure we open as UTF-8 with Python>=3 --- tests/test_from_json.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/test_from_json.py b/tests/test_from_json.py index 0f8aa5b6..3674711d 100644 --- a/tests/test_from_json.py +++ b/tests/test_from_json.py @@ -5,6 +5,7 @@ from agate.testcase import AgateTestCase from agate.data_types import * from agate.type_tester import TypeTester +import six class TestJSON(AgateTestCase): @@ -34,8 +35,12 @@ def test_from_json(self): def test_from_json_file_like_object(self): table1 = Table(self.rows, self.column_names, self.column_types) - with open('examples/test.json') as f: - table2 = Table.from_json(f) + if six.PY2: + with open('examples/test.json') as f: + table2 = Table.from_json(f) + else: + with open('examples/test.json', encoding='utf-8') as f: + table2 = Table.from_json(f) self.assertColumnNames(table2, self.column_names) self.assertColumnTypes(table2, [Number, Text, Boolean, Date, DateTime, TimeDelta]) From 8381a88d9a17d2476608f32681f96de4c23a8679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 20:36:47 +0100 Subject: [PATCH 42/99] Always transmit the encoding to json.loads() in Python2 --- agate/table/from_json.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/agate/table/from_json.py b/agate/table/from_json.py index f5163abd..14a00994 100644 --- a/agate/table/from_json.py +++ b/agate/table/from_json.py @@ -44,6 +44,9 @@ def from_json(cls, path, row_names=None, key=None, newline=False, column_types=N close = False + if six.PY2: + kwargs['encoding'] = encoding + if newline: js = [] @@ -58,9 +61,6 @@ def from_json(cls, path, row_names=None, key=None, newline=False, column_types=N close = True - if six.PY2: - kwargs['encoding'] = encoding - for line in f: js.append(json.loads(line, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs)) else: @@ -74,9 +74,6 @@ def from_json(cls, path, row_names=None, key=None, newline=False, column_types=N close = True - if six.PY2: - kwargs['encoding'] = encoding - js = json.load(f, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs) if isinstance(js, dict): From fbf11921e9178c4a5b9087511059f57b3c4bb323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Mon, 3 Feb 2020 20:46:53 +0100 Subject: [PATCH 43/99] Always specify the encoding -- the platform's default encoding may vary --- tests/test_py3.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_py3.py b/tests/test_py3.py index be3e6066..1a85d9c0 100644 --- a/tests/test_py3.py +++ b/tests/test_py3.py @@ -50,7 +50,7 @@ def test_properties(self): self.assertEqual(reader.line_num, 1) def test_line_numbers(self): - with open('examples/test.csv') as f: + with open('examples/test.csv', encoding='utf-8') as f: rows = list(csv_py3.Reader(f, line_numbers=True)) sample_rows = [ @@ -69,7 +69,7 @@ class TestFieldSizeLimit(unittest.TestCase): def setUp(self): self.lim = csv.field_size_limit() - with open('.test.csv', 'w') as f: + with open('.test.csv', 'w', encoding='utf-8') as f: f.write('a' * 10) def tearDown(self): @@ -79,7 +79,7 @@ def tearDown(self): def test_field_size_limit(self): # Testing field_size_limit for failure. Creating data using str * int. - with open('.test.csv', 'r') as f: + with open('.test.csv', 'r', encoding='utf-8') as f: c = csv_py3.Reader(f, field_size_limit=9) try: c.__next__() @@ -89,7 +89,7 @@ def test_field_size_limit(self): raise AssertionError('Expected FieldSizeLimitError') # Now testing higher field_size_limit. - with open('.test.csv', 'r') as f: + with open('.test.csv', 'r', encoding='utf-8') as f: c = csv_py3.Reader(f, field_size_limit=11) self.assertEqual(['a' * 10], c.__next__()) @@ -165,7 +165,7 @@ def setUp(self): ['', 'b', '', '', '', ''] ] - self.f = open('examples/test.csv') + self.f = open('examples/test.csv', encoding='utf-8') def tearDown(self): self.f.close() @@ -248,6 +248,6 @@ def setUp(self): pass def test_sniffer(self): - with open('examples/test.csv') as f: + with open('examples/test.csv', encoding='utf-8') as f: contents = f.read() self.assertEqual(csv_py3.Sniffer().sniff(contents).__dict__, csv.Sniffer().sniff(contents).__dict__) From 1a0128a0e86c3239a7eb07f57bb5fd6165d0e316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Wed, 5 Feb 2020 12:05:44 +0100 Subject: [PATCH 44/99] Explain the rationale behind adding ValueError to the exception handling --- agate/data_types/number.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/agate/data_types/number.py b/agate/data_types/number.py index d24a2b8d..192621c0 100644 --- a/agate/data_types/number.py +++ b/agate/data_types/number.py @@ -94,6 +94,8 @@ def cast(self, d): try: return Decimal(d) * sign + # The Decimal class will return an InvalidOperation exception on most Python implementations, + # but PyPy3 may return a ValueError if the string is not translatable to ASCII except (InvalidOperation, ValueError): pass From 7ccb858ba387546020d657cd945bf745922f6b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 12:07:54 +0100 Subject: [PATCH 45/99] Update testenv to py35 --- tox.ini | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/tox.ini b/tox.ini index d4962599..8f414440 100644 --- a/tox.ini +++ b/tox.ini @@ -7,23 +7,17 @@ commands=nosetests tests [testenv:py27] deps = -rrequirements-py2.txt -[testenv:py33] -deps = -rrequirements-py3.txt - -[testenv:py34] -deps = {[testenv:py33]deps} - [testenv:py35] -deps = {[testenv:py33]deps} +deps = -rrequirements-py3.txt [testenv:py36] -deps = {[testenv:py33]deps} +deps = {[testenv:py35]deps} [testenv:py37] -deps = {[testenv:py33]deps} +deps = {[testenv:py35]deps} [testenv:py38] -deps = {[testenv:py33]deps} +deps = {[testenv:py35]deps} [testenv:pypy] deps = {[testenv:py27]deps} From a69dc78b8bc5bf6779314de1331c443f208dbb47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 12:14:46 +0100 Subject: [PATCH 46/99] Rename pypy to pypy2; add pypy3 for coherence with Travis CI --- tox.ini | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 8f414440..0ab57e4e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27,py33,py34,py35,py36,pypy +envlist = py27,py33,py34,py35,py36,pypy2,pypy3 [testenv] commands=nosetests tests @@ -19,9 +19,12 @@ deps = {[testenv:py35]deps} [testenv:py38] deps = {[testenv:py35]deps} -[testenv:pypy] +[testenv:pypy2] deps = {[testenv:py27]deps} +[testenv:pypy3] +deps = {[testenv:py35]deps} + [flake8] ignore=E128,E402,E501,F403 # E128 continuation line under-indented for visual indent From 127e57c37cafeb9554afcb4f987d30cf734870fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 12:32:50 +0100 Subject: [PATCH 47/99] Run 'nosetests tests' for all Python versions except PyPy3 Also: make sure all tests, in whatever subdirectory, are run on PyPy3 --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b0fba096..e6813028 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,4 +53,6 @@ jobs: install: - if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then pip install -r requirements-py2.txt; else pip3 install -r requirements-py3.txt; fi # command to run tests -script: for s in tests/*.py; do nosetests -v "$s" || exit $?; done +script: + # pypy3 segfaults if running all tests in the same process + - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy3"* ]]; then find tests -name "*.py" -print0 | xargs -0 -n1 nosetests -v; else nosetests tests; fi From 706506f604900dd1b39a625d66b196124c517f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 12:45:08 +0100 Subject: [PATCH 48/99] Add a try/finally to make sure we close the file if an error occurs --- agate/table/from_json.py | 58 +++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/agate/table/from_json.py b/agate/table/from_json.py index 14a00994..f85f431d 100644 --- a/agate/table/from_json.py +++ b/agate/table/from_json.py @@ -44,45 +44,47 @@ def from_json(cls, path, row_names=None, key=None, newline=False, column_types=N close = False - if six.PY2: - kwargs['encoding'] = encoding + try: + if six.PY2: + kwargs['encoding'] = encoding - if newline: - js = [] + if newline: + js = [] - if hasattr(path, 'read'): - for line in path: - js.append(json.loads(line, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs)) - else: - if six.PY2: - f = open(path, 'Urb') + if hasattr(path, 'read'): + for line in path: + js.append(json.loads(line, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs)) else: - f = io.open(path, encoding=encoding) + if six.PY2: + f = open(path, 'Urb') + else: + f = io.open(path, encoding=encoding) - close = True + close = True - for line in f: - js.append(json.loads(line, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs)) - else: - if hasattr(path, 'read'): - js = json.load(path, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs) + for line in f: + js.append(json.loads(line, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs)) else: - if six.PY2: - f = open(path, 'Urb') + if hasattr(path, 'read'): + js = json.load(path, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs) else: - f = io.open(path, encoding=encoding) + if six.PY2: + f = open(path, 'Urb') + else: + f = io.open(path, encoding=encoding) - close = True + close = True - js = json.load(f, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs) + js = json.load(f, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs) - if isinstance(js, dict): - if not key: - raise TypeError('When converting a JSON document with a top-level dictionary element, a key must be specified.') + if isinstance(js, dict): + if not key: + raise TypeError('When converting a JSON document with a top-level dictionary element, a key must be specified.') - js = js[key] + js = js[key] - if close: - f.close() + finally: + if close: + f.close() return Table.from_object(js, row_names=row_names, column_types=column_types) From cba042e147ceee90bb93086d759c5135abe73e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 12:49:21 +0100 Subject: [PATCH 49/99] io.open() should work with any encoding on both Python 2 and 3 --- agate/table/from_json.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/agate/table/from_json.py b/agate/table/from_json.py index f85f431d..8516702a 100644 --- a/agate/table/from_json.py +++ b/agate/table/from_json.py @@ -45,9 +45,6 @@ def from_json(cls, path, row_names=None, key=None, newline=False, column_types=N close = False try: - if six.PY2: - kwargs['encoding'] = encoding - if newline: js = [] @@ -55,11 +52,7 @@ def from_json(cls, path, row_names=None, key=None, newline=False, column_types=N for line in path: js.append(json.loads(line, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs)) else: - if six.PY2: - f = open(path, 'Urb') - else: - f = io.open(path, encoding=encoding) - + f = io.open(path, encoding=encoding) close = True for line in f: @@ -68,11 +61,7 @@ def from_json(cls, path, row_names=None, key=None, newline=False, column_types=N if hasattr(path, 'read'): js = json.load(path, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs) else: - if six.PY2: - f = open(path, 'Urb') - else: - f = io.open(path, encoding=encoding) - + f = io.open(path, encoding=encoding) close = True js = json.load(f, object_pairs_hook=OrderedDict, parse_float=Decimal, **kwargs) From af1adf47fa0c8401278c1c7a222dfb38d44a3293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 12:55:38 +0100 Subject: [PATCH 50/99] Like in from_json.py, use io.open() on both Python 2 and 3 --- agate/table/from_csv.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/agate/table/from_csv.py b/agate/table/from_csv.py index 6c2f8037..d3596b0d 100644 --- a/agate/table/from_csv.py +++ b/agate/table/from_csv.py @@ -1,7 +1,6 @@ #!/usr/bin/env python import io - import six @@ -48,10 +47,7 @@ def from_csv(cls, path, column_names=None, column_types=None, row_names=None, sk if hasattr(path, 'read'): f = path else: - if six.PY2: - f = open(path, 'Urb') - else: - f = io.open(path, encoding=encoding) + f = io.open(path, encoding=encoding) close = True @@ -70,7 +66,8 @@ def from_csv(cls, path, column_names=None, column_types=None, row_names=None, sk kwargs['dialect'] = csv.Sniffer().sniff(contents.getvalue()[:sniff_limit]) if six.PY2: - kwargs['encoding'] = encoding + # On Python 2, we need to specify the encoding to csv.reader(); io.open() translated it to UTF-8 + kwargs['encoding'] = 'utf-8' reader = csv.reader(contents, header=header, **kwargs) From 681ec43078e3acc2a97a29ecf0a54afa34757fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 13:21:20 +0100 Subject: [PATCH 51/99] Do not stop testing on the first error on PyPy3: make test behaviour coherent with 'nosetests tests' --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e6813028..fd700de6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,4 +55,4 @@ install: # command to run tests script: # pypy3 segfaults if running all tests in the same process - - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy3"* ]]; then find tests -name "*.py" -print0 | xargs -0 -n1 nosetests -v; else nosetests tests; fi + - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy3"* ]]; then FAILURES=0; find tests -name "*.py" | while read s; do nosetests "$s" || ((FAILURES++)); done; [ "$FAILURES" -ne 0 ] && exit 1; else nosetests tests; fi From 47e9c3f57710b6bb521120a9efae207372cc5c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 13:40:32 +0100 Subject: [PATCH 52/99] Make nosetests verbose --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fd700de6..220806ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,4 +55,4 @@ install: # command to run tests script: # pypy3 segfaults if running all tests in the same process - - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy3"* ]]; then FAILURES=0; find tests -name "*.py" | while read s; do nosetests "$s" || ((FAILURES++)); done; [ "$FAILURES" -ne 0 ] && exit 1; else nosetests tests; fi + - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy3"* ]]; then FAILURES=0; find tests -name "*.py" | while read s; do nosetests -v "$s" || ((FAILURES++)); done; [ "$FAILURES" -ne 0 ] && exit 1; else nosetests -v tests; fi From 8e681b7a6d2ae5a2ba9408ca0e5d52d723b90ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 13:42:17 +0100 Subject: [PATCH 53/99] Add try/finally to make sure we close the file(s) even if an error occurs --- agate/table/from_csv.py | 58 ++++++++++++++++++++------------------- agate/table/from_fixed.py | 36 ++++++++++++------------ 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/agate/table/from_csv.py b/agate/table/from_csv.py index d3596b0d..f7b652ae 100644 --- a/agate/table/from_csv.py +++ b/agate/table/from_csv.py @@ -44,42 +44,44 @@ def from_csv(cls, path, column_names=None, column_types=None, row_names=None, sk close = False - if hasattr(path, 'read'): - f = path - else: - f = io.open(path, encoding=encoding) + try: + if hasattr(path, 'read'): + f = path + else: + f = io.open(path, encoding=encoding) - close = True + close = True - if isinstance(skip_lines, int): - while skip_lines > 0: - f.readline() - skip_lines -= 1 - else: - raise ValueError('skip_lines argument must be an int') + if isinstance(skip_lines, int): + while skip_lines > 0: + f.readline() + skip_lines -= 1 + else: + raise ValueError('skip_lines argument must be an int') - contents = six.StringIO(f.read()) + contents = six.StringIO(f.read()) - if sniff_limit is None: - kwargs['dialect'] = csv.Sniffer().sniff(contents.getvalue()) - elif sniff_limit > 0: - kwargs['dialect'] = csv.Sniffer().sniff(contents.getvalue()[:sniff_limit]) + if sniff_limit is None: + kwargs['dialect'] = csv.Sniffer().sniff(contents.getvalue()) + elif sniff_limit > 0: + kwargs['dialect'] = csv.Sniffer().sniff(contents.getvalue()[:sniff_limit]) - if six.PY2: - # On Python 2, we need to specify the encoding to csv.reader(); io.open() translated it to UTF-8 - kwargs['encoding'] = 'utf-8' + if six.PY2: + # On Python 2, we need to specify the encoding to csv.reader(); io.open() translated it to UTF-8 + kwargs['encoding'] = 'utf-8' - reader = csv.reader(contents, header=header, **kwargs) + reader = csv.reader(contents, header=header, **kwargs) - if header: - if column_names is None: - column_names = next(reader) - else: - next(reader) + if header: + if column_names is None: + column_names = next(reader) + else: + next(reader) - rows = tuple(reader) + rows = tuple(reader) - if close: - f.close() + finally: + if close: + f.close() return Table(rows, column_names, column_types, row_names=row_names) diff --git a/agate/table/from_fixed.py b/agate/table/from_fixed.py index 7a05bd78..f73fee85 100644 --- a/agate/table/from_fixed.py +++ b/agate/table/from_fixed.py @@ -38,28 +38,30 @@ def from_fixed(cls, path, schema_path, column_names=utils.default, column_types= close_f = False - if not hasattr(path, 'read'): - f = io.open(path, encoding=encoding) - close_f = True - else: - f = path - close_schema_f = False - if not hasattr(schema_path, 'read'): - schema_f = io.open(schema_path, encoding=schema_encoding) - close_schema_f = True - else: - schema_f = path + try: + if not hasattr(path, 'read'): + f = io.open(path, encoding=encoding) + close_f = True + else: + f = path + + if not hasattr(schema_path, 'read'): + schema_f = io.open(schema_path, encoding=schema_encoding) + close_schema_f = True + else: + schema_f = path - reader = fixed.reader(f, schema_f) - rows = list(reader) + reader = fixed.reader(f, schema_f) + rows = list(reader) - if close_f: - f.close() + finally: + if close_f: + f.close() - if close_schema_f: - schema_f.close() + if close_schema_f: + schema_f.close() if column_names == utils.default: column_names = reader.fieldnames From 50363097e0dcdff516af174b653c3cc3b6d11318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 13:43:07 +0100 Subject: [PATCH 54/99] Fix csv.reader() for Python 2 --- agate/table/from_csv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/agate/table/from_csv.py b/agate/table/from_csv.py index f7b652ae..01503372 100644 --- a/agate/table/from_csv.py +++ b/agate/table/from_csv.py @@ -67,8 +67,8 @@ def from_csv(cls, path, column_names=None, column_types=None, row_names=None, sk kwargs['dialect'] = csv.Sniffer().sniff(contents.getvalue()[:sniff_limit]) if six.PY2: - # On Python 2, we need to specify the encoding to csv.reader(); io.open() translated it to UTF-8 - kwargs['encoding'] = 'utf-8' + # On Python 2, we need to specify the encoding to csv.reader() + kwargs['encoding'] = encoding reader = csv.reader(contents, header=header, **kwargs) From b5854a972dde48e86c8cdb8507c5596f4d1804d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 13:49:08 +0100 Subject: [PATCH 55/99] Extra verbosity is only needed when running nosetests on a single file --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 220806ef..f6bbfed2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,4 +55,4 @@ install: # command to run tests script: # pypy3 segfaults if running all tests in the same process - - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy3"* ]]; then FAILURES=0; find tests -name "*.py" | while read s; do nosetests -v "$s" || ((FAILURES++)); done; [ "$FAILURES" -ne 0 ] && exit 1; else nosetests -v tests; fi + - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy3"* ]]; then FAILURES=0; find tests -name "*.py" | while read s; do nosetests -v "$s" || ((FAILURES++)); done; [ "$FAILURES" -ne 0 ] && exit 1; else nosetests tests; fi From fe729a3ece8e2cad334c37d6780e9d49ee086706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 14:24:53 +0100 Subject: [PATCH 56/99] Make test detection on PyPy3 more coherent with standard nosetests behaviour --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f6bbfed2..d80aa699 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,4 +55,4 @@ install: # command to run tests script: # pypy3 segfaults if running all tests in the same process - - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy3"* ]]; then FAILURES=0; find tests -name "*.py" | while read s; do nosetests -v "$s" || ((FAILURES++)); done; [ "$FAILURES" -ne 0 ] && exit 1; else nosetests tests; fi + - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy3"* ]]; then FAILURES=0; find tests -type f -name "*.py" | while read s; do ( [ ! -x "$s" ] && nosetests -v "$s" ) || ((FAILURES++)); done; [ "$FAILURES" -ne 0 ] && exit 1; else nosetests tests; fi From 15bb1b28829371cc27236975354e5c697bea972b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 14:35:54 +0100 Subject: [PATCH 57/99] PyPy3: Show better where tests fail --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d80aa699..95cd27dc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,4 +55,4 @@ install: # command to run tests script: # pypy3 segfaults if running all tests in the same process - - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy3"* ]]; then FAILURES=0; find tests -type f -name "*.py" | while read s; do ( [ ! -x "$s" ] && nosetests -v "$s" ) || ((FAILURES++)); done; [ "$FAILURES" -ne 0 ] && exit 1; else nosetests tests; fi + - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy3"* ]]; then FAILURES=(); find tests -type f -name "*.py" | while read s; do ( [ ! -x "$s" ] && nosetests -v "$s" ) || FAILURES+=("$s"); done; [ "${#FAILURES[@]}" -ne 0 ] && ( echo "Tests failed in the following files:\n\t${FAILURES[@]}"; exit 1 ); else nosetests tests; fi From 257c472c84bba35740a30fc9dae0df6ae559b3f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 14:45:09 +0100 Subject: [PATCH 58/99] Convert any Unicode strings in the arguments to bytes, as awaited by Python2's csv module --- agate/csv_py2.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/agate/csv_py2.py b/agate/csv_py2.py index 1ee20545..791da209 100644 --- a/agate/csv_py2.py +++ b/agate/csv_py2.py @@ -43,7 +43,8 @@ def __init__(self, f, encoding='utf-8', field_size_limit=None, line_numbers=Fals f = UTF8Recoder(f, encoding) - self.reader = csv.reader(f, **kwargs) + str_kwargs = _key_to_str_value_map(kwargs) + self.reader = csv.reader(f, **str_kwargs) if field_size_limit: csv.field_size_limit(field_size_limit) @@ -88,13 +89,14 @@ class UnicodeWriter(object): def __init__(self, f, encoding='utf-8', **kwargs): self.encoding = encoding self._eight_bit = (self.encoding.lower().replace('_', '-') in EIGHT_BIT_ENCODINGS) + str_kwargs = _key_to_str_value_map(kwargs) if self._eight_bit: - self.writer = csv.writer(f, **kwargs) + self.writer = csv.writer(f, **str_kwargs) else: # Redirect output to a queue for reencoding self.queue = six.StringIO() - self.writer = csv.writer(self.queue, **kwargs) + self.writer = csv.writer(self.queue, **str_kwargs) self.stream = f self.encoder = codecs.getincrementalencoder(encoding)() @@ -254,6 +256,20 @@ def sniff(self, sample): return dialect +_binary_type = str +_text_type = unicode +def _key_to_str_value_map(key_to_value_map): + """ + Similar to ``key_to_value_map`` but with values of type `unicode` + converted to `str` because in Python 2 `csv.reader` can only process + byte strings for formatting parameters, e.g. delimiter=b';' instead of + delimiter=u';'. This quickly becomes an annoyance to the caller, in + particular with `from __future__ import unicode_literals` enabled. + """ + return dict((key, value if not isinstance(value, _text_type) else _binary_type(value)) + for key, value in key_to_value_map.items()) + + def reader(*args, **kwargs): """ A replacement for Python's :func:`csv.reader` that uses From e843a05f611fe2b74e27447c8fc2ff07c7480b53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 15:58:49 +0100 Subject: [PATCH 59/99] Make the reader work for files opened in binary or text (io.open()) mode --- agate/csv_py2.py | 27 +++++++++++++++++++++++++-- agate/table/from_csv.py | 4 ---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/agate/csv_py2.py b/agate/csv_py2.py index 791da209..fa403792 100644 --- a/agate/csv_py2.py +++ b/agate/csv_py2.py @@ -18,6 +18,28 @@ POSSIBLE_DELIMITERS = [',', '\t', ';', ' ', ':', '|'] +_binary_type = str +_text_type = unicode + + +class BytesIOWrapper: + def __init__(self, string_buffer, encoding='utf-8'): + self.string_buffer = string_buffer + self.encoding = encoding + + def __getattr__(self, attr): + return getattr(self.string_buffer, attr) + + def read(self, size=-1): + content = self.string_buffer.read(size) + if isinstance(content, _text_type): + content = content.encode(self.encoding) + return _binary_type(content) + + def write(self, b): + content = b.decode(self.encoding) + return self.string_buffer.write(content) + class UTF8Recoder(six.Iterator): """ @@ -41,6 +63,9 @@ def __init__(self, f, encoding='utf-8', field_size_limit=None, line_numbers=Fals self.line_numbers = line_numbers self.header = header + if isinstance(f, six.StringIO): + f = BytesIOWrapper(f) + f = UTF8Recoder(f, encoding) str_kwargs = _key_to_str_value_map(kwargs) @@ -256,8 +281,6 @@ def sniff(self, sample): return dialect -_binary_type = str -_text_type = unicode def _key_to_str_value_map(key_to_value_map): """ Similar to ``key_to_value_map`` but with values of type `unicode` diff --git a/agate/table/from_csv.py b/agate/table/from_csv.py index 01503372..f402e704 100644 --- a/agate/table/from_csv.py +++ b/agate/table/from_csv.py @@ -66,10 +66,6 @@ def from_csv(cls, path, column_names=None, column_types=None, row_names=None, sk elif sniff_limit > 0: kwargs['dialect'] = csv.Sniffer().sniff(contents.getvalue()[:sniff_limit]) - if six.PY2: - # On Python 2, we need to specify the encoding to csv.reader() - kwargs['encoding'] = encoding - reader = csv.reader(contents, header=header, **kwargs) if header: From 3a60e344e869d6bd8571de5be9db6e8d7cc06246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 16:17:54 +0100 Subject: [PATCH 60/99] Avoid Python>=3 looking for what 'unicode' means during nosetests --- agate/csv_py2.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/agate/csv_py2.py b/agate/csv_py2.py index fa403792..8ec477ad 100644 --- a/agate/csv_py2.py +++ b/agate/csv_py2.py @@ -18,8 +18,9 @@ POSSIBLE_DELIMITERS = [',', '\t', ';', ' ', ':', '|'] -_binary_type = str -_text_type = unicode +if six.PY2: + _binary_type = str + _text_type = unicode class BytesIOWrapper: From 626c5b25eac5f837da03372e9d36933c238931d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 16:56:54 +0100 Subject: [PATCH 61/99] nosetests also segfaults on PyPy2 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 95cd27dc..34453be2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,4 +55,4 @@ install: # command to run tests script: # pypy3 segfaults if running all tests in the same process - - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy3"* ]]; then FAILURES=(); find tests -type f -name "*.py" | while read s; do ( [ ! -x "$s" ] && nosetests -v "$s" ) || FAILURES+=("$s"); done; [ "${#FAILURES[@]}" -ne 0 ] && ( echo "Tests failed in the following files:\n\t${FAILURES[@]}"; exit 1 ); else nosetests tests; fi + - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then FAILURES=(); find tests -type f -name "*.py" | while read s; do ( [ ! -x "$s" ] && nosetests -v "$s" ) || FAILURES+=("$s"); done; [ "${#FAILURES[@]}" -ne 0 ] && ( echo "Tests failed in the following files:\n\t${FAILURES[@]}"; exit 1 ); else nosetests tests; fi From 1805997cb2e2d33abd217115a57331572fd6573c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 16:59:02 +0100 Subject: [PATCH 62/99] Write long commands on several lines for clarity --- .travis.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 34453be2..dc741bc5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,8 +51,20 @@ jobs: fast_finish: true # command to install dependencies install: - - if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then pip install -r requirements-py2.txt; else pip3 install -r requirements-py3.txt; fi + - if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then \ + pip install -r requirements-py2.txt; \ + else \ + pip3 install -r requirements-py3.txt; \ + fi # command to run tests script: # pypy3 segfaults if running all tests in the same process - - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then FAILURES=(); find tests -type f -name "*.py" | while read s; do ( [ ! -x "$s" ] && nosetests -v "$s" ) || FAILURES+=("$s"); done; [ "${#FAILURES[@]}" -ne 0 ] && ( echo "Tests failed in the following files:\n\t${FAILURES[@]}"; exit 1 ); else nosetests tests; fi + - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then \ + FAILURES=(); \ + find tests -type f -name "*.py" | while read s; do \ + ( [ ! -x "$s" ] && nosetests -v "$s" ) || FAILURES+=("$s"); \ + done; \ + [ "${#FAILURES[@]}" -ne 0 ] && ( echo "Tests failed in the following files:\n\t${FAILURES[@]}"; exit 1 ); \ + else \ + nosetests tests; \ + fi From 4e078d9ec6344b3dea3fdfb1f1d27b026314ac35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 17:05:16 +0100 Subject: [PATCH 63/99] Fix typos --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f53a6ca6..7a654def 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,7 +51,8 @@ jobs: fast_finish: true # command to install dependencies install: - - if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then \ + - > + if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then \ pip install -r requirements-py2.txt; \ else \ pip3 install -r requirements-py3.txt; \ @@ -59,7 +60,8 @@ install: # command to run tests script: # pypy3 segfaults if running all tests in the same process - - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then \ + - > + if [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then \ FAILURES=(); \ find tests -type f -name "*.py" | while read s; do \ ( [ ! -x "$s" ] && nosetests -v "$s" ) || FAILURES+=("$s"); \ From 03d58c503b6e741a6de7ee5a843028559406626e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 17:14:20 +0100 Subject: [PATCH 64/99] Store PyPy3 failures to a file with hope that they will be printed --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7a654def..e69dc46b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,14 +62,15 @@ script: # pypy3 segfaults if running all tests in the same process - > if [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then \ - FAILURES=(); \ find tests -type f -name "*.py" | while read s; do \ - ( [ ! -x "$s" ] && nosetests -v "$s" ) || FAILURES+=("$s"); \ + ( [ ! -x "$s" ] && nosetests -v "$s" ) || echo "$s" >> "script-failures.log" \ done; \ - [ "${#FAILURES[@]}" -ne 0 ] && ( echo "Tests failed in the following files:\n\t${FAILURES[@]}"; exit 1 ); \ + [ -e "script-failures.log" ] && exit 1; \ else \ nosetests tests; \ fi +after_script: + - echo $(cat "script-failures.log") addons: apt: packages: From ca32854290c590b52101cb6f221d984b119bf745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 17:22:10 +0100 Subject: [PATCH 65/99] Add tests for csv in text mode and unicode delimiters --- examples/test_unicode_delimiter.csv | 4 ++++ tests/test_table/test_from_csv.py | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 examples/test_unicode_delimiter.csv diff --git a/examples/test_unicode_delimiter.csv b/examples/test_unicode_delimiter.csv new file mode 100644 index 00000000..d49edaa9 --- /dev/null +++ b/examples/test_unicode_delimiter.csv @@ -0,0 +1,4 @@ +numberĂȘtextĂȘbooleanĂȘdateĂȘdatetimeĂȘtimedelta +1ĂȘaĂȘTrueĂȘ2015-11-04ĂȘ2015-11-04T12:22:00ĂȘ0:04:15 +2ĂȘ👍ĂȘFalseĂȘ2015-11-05ĂȘ2015-11-04T12:45:00ĂȘ0:06:18 +ĂȘbĂȘĂȘĂȘĂȘ diff --git a/tests/test_table/test_from_csv.py b/tests/test_table/test_from_csv.py index 560813d8..0823c7f6 100644 --- a/tests/test_table/test_from_csv.py +++ b/tests/test_table/test_from_csv.py @@ -71,6 +71,19 @@ def test_from_csv_file_like_object(self): self.assertRows(table2, table1.rows) + def test_from_csv_file_like_object_in_text_mode(self): + table1 = Table(self.rows, self.column_names, self.column_types) + + f = io.open('examples/test.csv', encoding='utf-8') + + table2 = Table.from_csv(f) + f.close() + + self.assertColumnNames(table2, table1.column_names) + self.assertColumnTypes(table2, [Number, Text, Boolean, Date, DateTime, TimeDelta]) + + self.assertRows(table2, table1.rows) + def test_from_csv_type_tester(self): tester = TypeTester(force={ 'number': Text() @@ -170,3 +183,16 @@ def test_from_csv_skip_lines_cr(self): self.assertColumnTypes(table2, [Number, Text, Boolean, Date, DateTime, TimeDelta]) self.assertRows(table2, table1.rows) + + def test_from_csv_unicode_delimiter(self): + table1 = Table(self.rows, self.column_names, self.column_types) + if six.PY2: + # the Python2 csv module is limited to 8-bit encodings and a single char for delimiters + table2 = Table.from_csv('examples/test.csv', delimiter=unicode(',')) + else: + table2 = Table.from_csv('examples/test_unicode_delimiter.csv', delimiter='ĂȘ') + + self.assertColumnNames(table2, table1.column_names) + self.assertColumnTypes(table2, [Number, Text, Boolean, Date, DateTime, TimeDelta]) + + self.assertRows(table2, table1.rows) From a0f478e1ce40a90e0a376993b8eb05160b61c81f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 17:25:55 +0100 Subject: [PATCH 66/99] Add if/then/fi to avoid always failing --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e69dc46b..7631a321 100644 --- a/.travis.yml +++ b/.travis.yml @@ -65,7 +65,9 @@ script: find tests -type f -name "*.py" | while read s; do \ ( [ ! -x "$s" ] && nosetests -v "$s" ) || echo "$s" >> "script-failures.log" \ done; \ - [ -e "script-failures.log" ] && exit 1; \ + if [ -e "script-failures.log" ]; then \ + exit 1; \ + fi; \ else \ nosetests tests; \ fi From 165f6048d48c364ec213c13642fc9a8ea726e74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 17:30:17 +0100 Subject: [PATCH 67/99] Correct multi-line yaml/bash --- .travis.yml | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7631a321..36503b60 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,27 +52,30 @@ jobs: # command to install dependencies install: - > - if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then \ - pip install -r requirements-py2.txt; \ - else \ - pip3 install -r requirements-py3.txt; \ + if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then + pip install -r requirements-py2.txt; + else + pip3 install -r requirements-py3.txt; fi # command to run tests script: # pypy3 segfaults if running all tests in the same process - > - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then \ - find tests -type f -name "*.py" | while read s; do \ - ( [ ! -x "$s" ] && nosetests -v "$s" ) || echo "$s" >> "script-failures.log" \ - done; \ - if [ -e "script-failures.log" ]; then \ - exit 1; \ - fi; \ - else \ - nosetests tests; \ + if [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then + find tests -type f -name "*.py" | while read s; do + ( [ ! -x "$s" ] && nosetests -v "$s" ) || echo "$s" >> "script-failures.log"; + done; + if [ -e "script-failures.log" ]; then + exit 1; + fi; + else + nosetests tests; + fi +after_failure: + - > + if [ -e "script-failures.log" ]; then + echo $(cat "script-failures.log"); fi -after_script: - - echo $(cat "script-failures.log") addons: apt: packages: From 0ab8bb342fcdc5c6c413a86acc9f0c33a3035523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 18:06:22 +0100 Subject: [PATCH 68/99] Fix decimal formats when running the tests on non-English locales --- tests/test_table/test_bins.py | 13 ++++--- tests/test_table/test_print_bars.py | 5 ++- tests/test_table/test_print_table.py | 55 ++++++++++++++++++---------- 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/tests/test_table/test_bins.py b/tests/test_table/test_bins.py index cabff86a..4245d3ee 100644 --- a/tests/test_table/test_bins.py +++ b/tests/test_table/test_bins.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf8 -*- +from babel.numbers import get_decimal_symbol try: from cdecimal import Decimal except ImportError: # pragma: no cover @@ -110,9 +111,9 @@ def test_bins_decimals(self): self.assertColumnNames(new_table, ['number', 'Count']) self.assertColumnTypes(new_table, [Text, Number]) - self.assertSequenceEqual(new_table.rows[0], ['[0.0 - 0.1)', 10]) - self.assertSequenceEqual(new_table.rows[3], ['[0.3 - 0.4)', 10]) - self.assertSequenceEqual(new_table.rows[9], ['[0.9 - 1.0]', 10]) + self.assertSequenceEqual(new_table.rows[0], [u'[0' + get_decimal_symbol() + u'0 - 0' + get_decimal_symbol() + u'1)', 10]) + self.assertSequenceEqual(new_table.rows[3], [u'[0' + get_decimal_symbol() + u'3 - 0' + get_decimal_symbol() + u'4)', 10]) + self.assertSequenceEqual(new_table.rows[9], [u'[0' + get_decimal_symbol() + u'9 - 1' + get_decimal_symbol() + u'0]', 10]) def test_bins_nulls(self): rows = [] @@ -127,7 +128,7 @@ def test_bins_nulls(self): self.assertColumnNames(new_table, ['number', 'Count']) self.assertColumnTypes(new_table, [Text, Number]) - self.assertSequenceEqual(new_table.rows[0], ['[0.0 - 0.1)', 10]) - self.assertSequenceEqual(new_table.rows[3], ['[0.3 - 0.4)', 10]) - self.assertSequenceEqual(new_table.rows[9], ['[0.9 - 1.0]', 10]) + self.assertSequenceEqual(new_table.rows[0], [u'[0' + get_decimal_symbol() + u'0 - 0' + get_decimal_symbol() + u'1)', 10]) + self.assertSequenceEqual(new_table.rows[3], [u'[0' + get_decimal_symbol() + u'3 - 0' + get_decimal_symbol() + u'4)', 10]) + self.assertSequenceEqual(new_table.rows[9], [u'[0' + get_decimal_symbol() + u'9 - 1' + get_decimal_symbol() + u'0]', 10]) self.assertSequenceEqual(new_table.rows[10], [None, 1]) diff --git a/tests/test_table/test_print_bars.py b/tests/test_table/test_print_bars.py index 847227a1..5026280f 100644 --- a/tests/test_table/test_print_bars.py +++ b/tests/test_table/test_print_bars.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf8 -*- +from babel.numbers import format_decimal import six from agate import Table @@ -98,8 +99,8 @@ def test_print_bars_with_nulls(self): output=output) self.assertEqual(output.getvalue(), "three two\n" - "a 2,000 |:::::::\n" + "a " + format_decimal(2000, format=u'#,##0') + " |:::::::\n" "None - | \n" "c 1 | \n" " +------+\n" - " 0 2,000\n") + " 0 " + format_decimal(2000, format=u'#,##0') + "\n") diff --git a/tests/test_table/test_print_table.py b/tests/test_table/test_print_table.py index e15197f9..7efc3079 100644 --- a/tests/test_table/test_print_table.py +++ b/tests/test_table/test_print_table.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf8 -*- +from babel.numbers import get_decimal_symbol import six from agate import Table @@ -11,19 +12,21 @@ class TestPrintTable(AgateTestCase): def setUp(self): self.rows = ( - ('1.7', 2000, 'a'), - ('11.18', None, None), - ('0', 1, 'c') + ('1.7', 2000, 2000, 'a'), + ('11.18', None, None, None), + ('0', 1, 1, 'c') ) self.number_type = Number() - self.international_number_type = Number(locale='de_DE') + self.american_number_type = Number(locale='en_US') + self.german_number_type = Number(locale='de_DE') self.text_type = Text() - self.column_names = ['one', 'two', 'three'] + self.column_names = ['one', 'two', 'three', 'four'] self.column_types = [ self.number_type, - self.international_number_type, + self.american_number_type, + self.german_number_type, self.text_type ] @@ -35,7 +38,7 @@ def test_print_table(self): lines = output.getvalue().split('\n') self.assertEqual(len(lines), 6) - self.assertEqual(len(lines[0]), 25) + self.assertEqual(len(lines[0]), 32) def test_print_table_max_rows(self): table = Table(self.rows, self.column_names, self.column_types) @@ -45,7 +48,7 @@ def test_print_table_max_rows(self): lines = output.getvalue().split('\n') self.assertEqual(len(lines), 6) - self.assertEqual(len(lines[0]), 25) + self.assertEqual(len(lines[0]), 32) def test_print_table_max_columns(self): table = Table(self.rows, self.column_names, self.column_types) @@ -81,22 +84,22 @@ def test_print_table_max_precision(self): self.assertIn(u' 11.123456 ', lines[3]) self.assertIn(u' 0 ', lines[4]) # Test real precision above max - self.assertIn(u' 1.74
 ', lines[2]) - self.assertIn(u' 11.12
 ', lines[3]) - self.assertIn(u' 0.00
 ', lines[4]) + self.assertIn(u' 1' + get_decimal_symbol() + u'74
 ', lines[2]) + self.assertIn(u' 11' + get_decimal_symbol() + u'12
 ', lines[3]) + self.assertIn(u' 0' + get_decimal_symbol() + u'00
 ', lines[4]) # Test real precision below max - self.assertIn(u' 1.72 ', lines[2]) - self.assertIn(u' 5.10 ', lines[3]) - self.assertIn(u' 0.10 ', lines[4]) + self.assertIn(u' 1' + get_decimal_symbol() + u'72 ', lines[2]) + self.assertIn(u' 5' + get_decimal_symbol() + u'10 ', lines[3]) + self.assertIn(u' 0' + get_decimal_symbol() + u'10 ', lines[4]) def test_print_table_max_column_width(self): rows = ( - ('1.7', 2, 'this is long'), - ('11.18', None, None), - ('0', 1, 'nope') + ('1.7', 2, 2, 'this is long'), + ('11.18', None, None, None), + ('0', 1, 1, 'nope') ) - column_names = ['one', 'two', 'also, this is long'] + column_names = ['one', 'two', 'three', 'also, this is long'] table = Table(rows, column_names, self.column_types) output = six.StringIO() @@ -107,9 +110,21 @@ def test_print_table_max_column_width(self): self.assertIn(' this... ', lines[2]) self.assertIn(' nope ', lines[4]) - def test_print_table_locale(self): + def test_print_table_locale_american(self): """ - Verify that the locale of the international number is correctly + Verify that the locale of the german number is correctly + controlling the format of how it is printed. + """ + table = Table(self.rows, self.column_names, self.column_types) + + output = six.StringIO() + table.print_table(max_columns=2, output=output, locale='en_US') + # If it's working, 2000 should appear as the english '2,000' + self.assertTrue("2,000" in output.getvalue()) + + def test_print_table_locale_german(self): + """ + Verify that the locale of the german number is correctly controlling the format of how it is printed. """ table = Table(self.rows, self.column_names, self.column_types) From e4155a97ab025db8ee868eccd22432350125f74c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 18:35:16 +0100 Subject: [PATCH 69/99] Clarify pypy versions --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 36503b60..d8c9b41a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ jobs: # command to install dependencies install: - > - if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then + if [[ "$TRAVIS_PYTHON_VERSION" == "2"* ]] || [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]] && [[ "$TRAVIS_PYTHON_VERSION" != "pypy3"* ]]; then pip install -r requirements-py2.txt; else pip3 install -r requirements-py3.txt; @@ -63,7 +63,7 @@ script: - > if [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then find tests -type f -name "*.py" | while read s; do - ( [ ! -x "$s" ] && nosetests -v "$s" ) || echo "$s" >> "script-failures.log"; + ( [ ! -x "$s" ] && nosetests -v "$s" ) || ( echo "$s" >> "script-failures.log" ); done; if [ -e "script-failures.log" ]; then exit 1; From 77dbd7ca5861041f9ce20261bbb70c09539b449b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 19:19:07 +0100 Subject: [PATCH 70/99] Revert to binary mode only for csv files under Python 2, to make it work with PyPy --- agate/csv_py2.py | 46 ++----------------------------- agate/table/from_csv.py | 8 +++++- tests/test_table/test_from_csv.py | 26 ----------------- 3 files changed, 10 insertions(+), 70 deletions(-) diff --git a/agate/csv_py2.py b/agate/csv_py2.py index c5865ff1..034c5877 100644 --- a/agate/csv_py2.py +++ b/agate/csv_py2.py @@ -18,29 +18,6 @@ POSSIBLE_DELIMITERS = [',', '\t', ';', ' ', ':', '|'] -if six.PY2: - _binary_type = str - _text_type = unicode - - -class BytesIOWrapper: - def __init__(self, string_buffer, encoding='utf-8'): - self.string_buffer = string_buffer - self.encoding = encoding - - def __getattr__(self, attr): - return getattr(self.string_buffer, attr) - - def read(self, size=-1): - content = self.string_buffer.read(size) - if isinstance(content, _text_type): - content = content.encode(self.encoding) - return _binary_type(content) - - def write(self, b): - content = b.decode(self.encoding) - return self.string_buffer.write(content) - class UTF8Recoder(six.Iterator): """ @@ -64,13 +41,9 @@ def __init__(self, f, encoding='utf-8', field_size_limit=None, line_numbers=Fals self.line_numbers = line_numbers self.header = header - if isinstance(f, six.StringIO): - f = BytesIOWrapper(f) - f = UTF8Recoder(f, encoding) - str_kwargs = _key_to_str_value_map(kwargs) - self.reader = csv.reader(f, **str_kwargs) + self.reader = csv.reader(f, **kwargs) if field_size_limit: csv.field_size_limit(field_size_limit) @@ -115,14 +88,13 @@ class UnicodeWriter(object): def __init__(self, f, encoding='utf-8', **kwargs): self.encoding = encoding self._eight_bit = (self.encoding.lower().replace('_', '-') in EIGHT_BIT_ENCODINGS) - str_kwargs = _key_to_str_value_map(kwargs) if self._eight_bit: - self.writer = csv.writer(f, **str_kwargs) + self.writer = csv.writer(f, **kwargs) else: # Redirect output to a queue for reencoding self.queue = six.StringIO() - self.writer = csv.writer(self.queue, **str_kwargs) + self.writer = csv.writer(self.queue, **kwargs) self.stream = f self.encoder = codecs.getincrementalencoder(encoding)() @@ -282,18 +254,6 @@ def sniff(self, sample): return dialect -def _key_to_str_value_map(key_to_value_map): - """ - Similar to ``key_to_value_map`` but with values of type `unicode` - converted to `str` because in Python 2 `csv.reader` can only process - byte strings for formatting parameters, e.g. delimiter=b';' instead of - delimiter=u';'. This quickly becomes an annoyance to the caller, in - particular with `from __future__ import unicode_literals` enabled. - """ - return dict((key, value if not isinstance(value, _text_type) else _binary_type(value)) - for key, value in key_to_value_map.items()) - - def reader(*args, **kwargs): """ A replacement for Python's :func:`csv.reader` that uses diff --git a/agate/table/from_csv.py b/agate/table/from_csv.py index f402e704..1e962a97 100644 --- a/agate/table/from_csv.py +++ b/agate/table/from_csv.py @@ -48,7 +48,10 @@ def from_csv(cls, path, column_names=None, column_types=None, row_names=None, sk if hasattr(path, 'read'): f = path else: - f = io.open(path, encoding=encoding) + if six.PY2: + f = open(path, 'Urb') + else: + f = io.open(path, encoding=encoding) close = True @@ -66,6 +69,9 @@ def from_csv(cls, path, column_names=None, column_types=None, row_names=None, sk elif sniff_limit > 0: kwargs['dialect'] = csv.Sniffer().sniff(contents.getvalue()[:sniff_limit]) + if six.PY2: + kwargs['encoding'] = encoding + reader = csv.reader(contents, header=header, **kwargs) if header: diff --git a/tests/test_table/test_from_csv.py b/tests/test_table/test_from_csv.py index 0823c7f6..560813d8 100644 --- a/tests/test_table/test_from_csv.py +++ b/tests/test_table/test_from_csv.py @@ -71,19 +71,6 @@ def test_from_csv_file_like_object(self): self.assertRows(table2, table1.rows) - def test_from_csv_file_like_object_in_text_mode(self): - table1 = Table(self.rows, self.column_names, self.column_types) - - f = io.open('examples/test.csv', encoding='utf-8') - - table2 = Table.from_csv(f) - f.close() - - self.assertColumnNames(table2, table1.column_names) - self.assertColumnTypes(table2, [Number, Text, Boolean, Date, DateTime, TimeDelta]) - - self.assertRows(table2, table1.rows) - def test_from_csv_type_tester(self): tester = TypeTester(force={ 'number': Text() @@ -183,16 +170,3 @@ def test_from_csv_skip_lines_cr(self): self.assertColumnTypes(table2, [Number, Text, Boolean, Date, DateTime, TimeDelta]) self.assertRows(table2, table1.rows) - - def test_from_csv_unicode_delimiter(self): - table1 = Table(self.rows, self.column_names, self.column_types) - if six.PY2: - # the Python2 csv module is limited to 8-bit encodings and a single char for delimiters - table2 = Table.from_csv('examples/test.csv', delimiter=unicode(',')) - else: - table2 = Table.from_csv('examples/test_unicode_delimiter.csv', delimiter='ĂȘ') - - self.assertColumnNames(table2, table1.column_names) - self.assertColumnTypes(table2, [Number, Text, Boolean, Date, DateTime, TimeDelta]) - - self.assertRows(table2, table1.rows) From 525ff80360fef10ee896ea47f045785f65ca560b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 19:28:01 +0100 Subject: [PATCH 71/99] Stop being stalled by PyPy segfaults on Travis CI --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index d8c9b41a..fc0bc4b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,9 +45,13 @@ jobs: - python --version env: PATH=/c/Python38:/c/Python38/Scripts:$PATH # allow failure on OSes other than Linux + # and on PyPy, which regularly segfaults on Travis CI + # because of resource exhaustion allow_failures: - os: osx - os: windows + - python: pypy3 + - python: pypy fast_finish: true # command to install dependencies install: From a7c5774ed651676e753203c31c6d2dbf8c3be647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 19:47:38 +0100 Subject: [PATCH 72/99] Try to fix errors with PyICU --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index fc0bc4b4..a323644e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,8 @@ jobs: osx_image: xcode11.2 # Python 3.7.4 running on macOS 10.14.4 language: shell # 'language: python' is an error on Travis CI macOS before_install: + - brew install pkg-config + - brew install icu4c - python3 -m pip install --upgrade pip - python3 -m pip install --upgrade virtualenv - virtualenv -p python3 --system-site-packages "$HOME/venv" @@ -39,6 +41,7 @@ jobs: python: "3.8" language: shell # 'language: python' is an error on Travis CI Windows before_install: + - choco install pkgconfiglite - choco install python --version 3.8.0 - choco install sqlite - python -m pip install --upgrade pip @@ -86,3 +89,4 @@ addons: - language-pack-fr - language-pack-de - language-pack-ko + - pkg-config From f71bc98d21829db16971ebaad18a3828b4480f95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 19:57:02 +0100 Subject: [PATCH 73/99] Allow failures on all PyPy builds --- .travis.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a323644e..0789804c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,8 +53,13 @@ jobs: allow_failures: - os: osx - os: windows - - python: pypy3 - - python: pypy + - python: "pypy3" + - python: "pypy3.5-6.0" + - python: "pypy3.5-7.0" + - python: "pypy3.6-7.0.0" + - python: "pypy" + - python: "pypy2.7-6.0" + - python: "pypy2.7-7.0.0" fast_finish: true # command to install dependencies install: From f1563b32917a42266038ea14d01fdba8a12a136b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 20:00:56 +0100 Subject: [PATCH 74/99] Unicode delimiter test not needed anymore --- examples/test_unicode_delimiter.csv | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 examples/test_unicode_delimiter.csv diff --git a/examples/test_unicode_delimiter.csv b/examples/test_unicode_delimiter.csv deleted file mode 100644 index d49edaa9..00000000 --- a/examples/test_unicode_delimiter.csv +++ /dev/null @@ -1,4 +0,0 @@ -numberĂȘtextĂȘbooleanĂȘdateĂȘdatetimeĂȘtimedelta -1ĂȘaĂȘTrueĂȘ2015-11-04ĂȘ2015-11-04T12:22:00ĂȘ0:04:15 -2ĂȘ👍ĂȘFalseĂȘ2015-11-05ĂȘ2015-11-04T12:45:00ĂȘ0:06:18 -ĂȘbĂȘĂȘĂȘĂȘ From 3b28c688332edc646c5eb60ba37988c68a4581d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 20:02:17 +0100 Subject: [PATCH 75/99] Correct envlist --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 0ab57e4e..1fc719e9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27,py33,py34,py35,py36,pypy2,pypy3 +envlist = py27,py35,py36,py37,py38,pypy2,pypy3 [testenv] commands=nosetests tests From e5e0d948a51e7cded1eb32bd81061381ae01c826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 21:05:22 +0100 Subject: [PATCH 76/99] try updating PKG_CONFIG_PATH on macOS --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0789804c..28bd6af6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,7 @@ jobs: before_install: - brew install pkg-config - brew install icu4c + - export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/icu4c/lib/pkgconfig" - python3 -m pip install --upgrade pip - python3 -m pip install --upgrade virtualenv - virtualenv -p python3 --system-site-packages "$HOME/venv" From 64669bbdc8522228cf0c7beb74520ef3c460390d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Wed, 5 Feb 2020 21:19:50 +0100 Subject: [PATCH 77/99] Try running uconv -V to get the ICU version --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 28bd6af6..cafbaf74 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,9 @@ jobs: before_install: - brew install pkg-config - brew install icu4c + - export PATH="$PATH:/usr/local/opt/icu4c/bin" - export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/icu4c/lib/pkgconfig" + - uconv -V - python3 -m pip install --upgrade pip - python3 -m pip install --upgrade virtualenv - virtualenv -p python3 --system-site-packages "$HOME/venv" @@ -43,8 +45,8 @@ jobs: language: shell # 'language: python' is an error on Travis CI Windows before_install: - choco install pkgconfiglite + - uconv -V - choco install python --version 3.8.0 - - choco install sqlite - python -m pip install --upgrade pip - python --version env: PATH=/c/Python38:/c/Python38/Scripts:$PATH From e69bcf7583afdd502406782b2e7f2c3105c22f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Thu, 6 Feb 2020 00:10:23 +0100 Subject: [PATCH 78/99] Download the ICU DLLs for Windows --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index cafbaf74..91349329 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,6 +45,9 @@ jobs: language: shell # 'language: python' is an error on Travis CI Windows before_install: - choco install pkgconfiglite + - wget https://github.com/unicode-org/icu/releases/download/release-65-1/icu4c-65_1-Win64-MSVC2017.zip -O icu4c.zip + - unzip icu4c.zip -d icu4c + - export PATH="$PATH:$PWD/icu4c" - uconv -V - choco install python --version 3.8.0 - python -m pip install --upgrade pip From c5733d1df9e5f7b536fd35160ac2d979623dc51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Thu, 6 Feb 2020 00:21:44 +0100 Subject: [PATCH 79/99] Windows: correct ICU path, silence wget --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 91349329..24a1e362 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,9 +45,9 @@ jobs: language: shell # 'language: python' is an error on Travis CI Windows before_install: - choco install pkgconfiglite - - wget https://github.com/unicode-org/icu/releases/download/release-65-1/icu4c-65_1-Win64-MSVC2017.zip -O icu4c.zip + - wget -q https://github.com/unicode-org/icu/releases/download/release-65-1/icu4c-65_1-Win64-MSVC2017.zip -O icu4c.zip - unzip icu4c.zip -d icu4c - - export PATH="$PATH:$PWD/icu4c" + - export PATH="$PATH:$PWD/icu4c/bin64" - uconv -V - choco install python --version 3.8.0 - python -m pip install --upgrade pip From 1755f2b22596f2643c47443c01fa99ded36229f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Thu, 6 Feb 2020 00:47:25 +0100 Subject: [PATCH 80/99] Windows: Add ICU to various config vars --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 24a1e362..2d96d40e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,9 +46,13 @@ jobs: before_install: - choco install pkgconfiglite - wget -q https://github.com/unicode-org/icu/releases/download/release-65-1/icu4c-65_1-Win64-MSVC2017.zip -O icu4c.zip - - unzip icu4c.zip -d icu4c + - unzip -q icu4c.zip -d icu4c - export PATH="$PATH:$PWD/icu4c/bin64" + - export LD_LIBRARY_PATH="$PATH:$PWD/icu4c/bin64:$PWD/icu4c/lib64" + - export PYICU_INCLUDES="$PWD/icu4c/include" + - export PYICU_LFLAGS='/LIBPATH:$PWD/icu4c/lib64' - uconv -V + - export ICU_VERSION="$(uconv -V | sed -e 's,.*\ Date: Thu, 6 Feb 2020 00:49:16 +0100 Subject: [PATCH 81/99] List available locales on Windows and macOS --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2d96d40e..9c70128a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,7 @@ jobs: - export PATH="$PATH:/usr/local/opt/icu4c/bin" - export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/icu4c/lib/pkgconfig" - uconv -V + - locale --all - python3 -m pip install --upgrade pip - python3 -m pip install --upgrade virtualenv - virtualenv -p python3 --system-site-packages "$HOME/venv" @@ -53,6 +54,7 @@ jobs: - export PYICU_LFLAGS='/LIBPATH:$PWD/icu4c/lib64' - uconv -V - export ICU_VERSION="$(uconv -V | sed -e 's,.*\ Date: Thu, 6 Feb 2020 01:02:32 +0100 Subject: [PATCH 82/99] Add ICU libraries file names --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 9c70128a..4b640824 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,6 +52,7 @@ jobs: - export LD_LIBRARY_PATH="$PATH:$PWD/icu4c/bin64:$PWD/icu4c/lib64" - export PYICU_INCLUDES="$PWD/icu4c/include" - export PYICU_LFLAGS='/LIBPATH:$PWD/icu4c/lib64' + - export PYICU_LIBRARIES="icuin;icuuc;icudt" - uconv -V - export ICU_VERSION="$(uconv -V | sed -e 's,.*\ Date: Thu, 6 Feb 2020 01:05:41 +0100 Subject: [PATCH 83/99] Portability: short options for locale --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4b640824..700d9209 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ jobs: - export PATH="$PATH:/usr/local/opt/icu4c/bin" - export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/icu4c/lib/pkgconfig" - uconv -V - - locale --all + - locale -a - python3 -m pip install --upgrade pip - python3 -m pip install --upgrade virtualenv - virtualenv -p python3 --system-site-packages "$HOME/venv" @@ -55,7 +55,7 @@ jobs: - export PYICU_LIBRARIES="icuin;icuuc;icudt" - uconv -V - export ICU_VERSION="$(uconv -V | sed -e 's,.*\ Date: Thu, 6 Feb 2020 01:12:57 +0100 Subject: [PATCH 84/99] Test Korean date formats on macOS --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 700d9209..a1378934 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,8 @@ jobs: - export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/icu4c/lib/pkgconfig" - uconv -V - locale -a + - LANG=ko_KR.UTF-8 LC_ALL=ko_KR.UTF-8 date -d '1994-03-01 18:30' +'%p' + - LANG=ko_KR.UTF-8 LC_ALL=ko_KR.UTF-8 date -d '1994-03-01 01:30' +'%p' - python3 -m pip install --upgrade pip - python3 -m pip install --upgrade virtualenv - virtualenv -p python3 --system-site-packages "$HOME/venv" From fee7b0904cbe756e440da00835432d41f6774b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Thu, 6 Feb 2020 01:19:34 +0100 Subject: [PATCH 85/99] Win64: Correct flags --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a1378934..7b71287d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,8 +53,7 @@ jobs: - export PATH="$PATH:$PWD/icu4c/bin64" - export LD_LIBRARY_PATH="$PATH:$PWD/icu4c/bin64:$PWD/icu4c/lib64" - export PYICU_INCLUDES="$PWD/icu4c/include" - - export PYICU_LFLAGS='/LIBPATH:$PWD/icu4c/lib64' - - export PYICU_LIBRARIES="icuin;icuuc;icudt" + - export PYICU_LFLAGS='/LIBPATH:icu4c/lib64' - uconv -V - export ICU_VERSION="$(uconv -V | sed -e 's,.*\ Date: Thu, 6 Feb 2020 01:31:53 +0100 Subject: [PATCH 86/99] Add $PWD to LFLAGS --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7b71287d..42bf88c0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,7 +53,7 @@ jobs: - export PATH="$PATH:$PWD/icu4c/bin64" - export LD_LIBRARY_PATH="$PATH:$PWD/icu4c/bin64:$PWD/icu4c/lib64" - export PYICU_INCLUDES="$PWD/icu4c/include" - - export PYICU_LFLAGS='/LIBPATH:icu4c/lib64' + - export PYICU_LFLAGS='/LIBPATH:$PWD/icu4c/lib64' - uconv -V - export ICU_VERSION="$(uconv -V | sed -e 's,.*\ Date: Thu, 6 Feb 2020 01:35:35 +0100 Subject: [PATCH 87/99] Adapt date parameters to macOS --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 42bf88c0..aade16c8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,8 +26,8 @@ jobs: - export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/icu4c/lib/pkgconfig" - uconv -V - locale -a - - LANG=ko_KR.UTF-8 LC_ALL=ko_KR.UTF-8 date -d '1994-03-01 18:30' +'%p' - - LANG=ko_KR.UTF-8 LC_ALL=ko_KR.UTF-8 date -d '1994-03-01 01:30' +'%p' + - LANG=ko_KR.UTF-8 LC_ALL=ko_KR.UTF-8 date -r 762543000 +'%p' # 18:30 + - LANG=ko_KR.UTF-8 LC_ALL=ko_KR.UTF-8 date -r 762481800 +'%p' # 01:30 - python3 -m pip install --upgrade pip - python3 -m pip install --upgrade virtualenv - virtualenv -p python3 --system-site-packages "$HOME/venv" From 0b81a8eeaa4bba82228e2a0e839e22167aefbb83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Thu, 6 Feb 2020 02:12:18 +0100 Subject: [PATCH 88/99] Windows: try vcpkg --- .travis.yml | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index aade16c8..d7108660 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,8 +26,8 @@ jobs: - export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/icu4c/lib/pkgconfig" - uconv -V - locale -a - - LANG=ko_KR.UTF-8 LC_ALL=ko_KR.UTF-8 date -r 762543000 +'%p' # 18:30 - - LANG=ko_KR.UTF-8 LC_ALL=ko_KR.UTF-8 date -r 762481800 +'%p' # 01:30 + - LANG=sv_SV.UTF-8 LC_ALL=ko_KR.UTF-8 date -r 762543000 +'%p' # 18:30 + - LANG=sv_SV.UTF-8 LC_ALL=ko_KR.UTF-8 date -r 762481800 +'%p' # 01:30 - python3 -m pip install --upgrade pip - python3 -m pip install --upgrade virtualenv - virtualenv -p python3 --system-site-packages "$HOME/venv" @@ -48,12 +48,18 @@ jobs: language: shell # 'language: python' is an error on Travis CI Windows before_install: - choco install pkgconfiglite - - wget -q https://github.com/unicode-org/icu/releases/download/release-65-1/icu4c-65_1-Win64-MSVC2017.zip -O icu4c.zip - - unzip -q icu4c.zip -d icu4c - - export PATH="$PATH:$PWD/icu4c/bin64" - - export LD_LIBRARY_PATH="$PATH:$PWD/icu4c/bin64:$PWD/icu4c/lib64" - - export PYICU_INCLUDES="$PWD/icu4c/include" - - export PYICU_LFLAGS='/LIBPATH:$PWD/icu4c/lib64' +# - wget -q https://github.com/unicode-org/icu/releases/download/release-65-1/icu4c-65_1-Win64-MSVC2017.zip -O icu4c.zip +# - unzip -q icu4c.zip -d icu4c + - git clone https://github.com/Microsoft/vcpkg.git + - pushd vcpkg + - ./bootstrap-vcpkg.bat + - ./vcpkg integrate install + - ./vcpkg install icu:x64-windows + - popd +# - export PATH="$PATH:$PWD/icu4c/bin64" +# - export LD_LIBRARY_PATH="$PATH:$PWD/icu4c/bin64:$PWD/icu4c/lib64" +# - export PYICU_INCLUDES="$PWD/icu4c/include" +# - export PYICU_LFLAGS='/LIBPATH:$PWD/icu4c/lib64' - uconv -V - export ICU_VERSION="$(uconv -V | sed -e 's,.*\ Date: Thu, 6 Feb 2020 10:16:50 +0100 Subject: [PATCH 89/99] Disable vcpkg metrics --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d7108660..8ae2b6a4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ jobs: # - unzip -q icu4c.zip -d icu4c - git clone https://github.com/Microsoft/vcpkg.git - pushd vcpkg - - ./bootstrap-vcpkg.bat + - ./bootstrap-vcpkg.bat -disableMetrics - ./vcpkg integrate install - ./vcpkg install icu:x64-windows - popd From 730b9f77645c153e2abcd91ff9d34a157b985a46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Thu, 6 Feb 2020 10:24:05 +0100 Subject: [PATCH 90/99] Try to find vcpkg files --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 8ae2b6a4..495ee4db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,6 +56,7 @@ jobs: - ./vcpkg integrate install - ./vcpkg install icu:x64-windows - popd + - find . -type f # - export PATH="$PATH:$PWD/icu4c/bin64" # - export LD_LIBRARY_PATH="$PATH:$PWD/icu4c/bin64:$PWD/icu4c/lib64" # - export PYICU_INCLUDES="$PWD/icu4c/include" From 4f85d18e48d755a35e021774b1d80766206d914e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Thu, 6 Feb 2020 11:44:27 +0100 Subject: [PATCH 91/99] Windows: update env vars with the paths of the ICU vcpkg package --- .travis.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 495ee4db..a053b671 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,15 +48,19 @@ jobs: language: shell # 'language: python' is an error on Travis CI Windows before_install: - choco install pkgconfiglite -# - wget -q https://github.com/unicode-org/icu/releases/download/release-65-1/icu4c-65_1-Win64-MSVC2017.zip -O icu4c.zip -# - unzip -q icu4c.zip -d icu4c - git clone https://github.com/Microsoft/vcpkg.git - pushd vcpkg - ./bootstrap-vcpkg.bat -disableMetrics - ./vcpkg integrate install - ./vcpkg install icu:x64-windows + - cp buildtrees/icu/x64-windows-rel/bin/uconv.exe installed/x64-windows/bin/ - popd - - find . -type f + - export PATH="$PATH:$PWD/vcpkg/installed/x64-windows/bin" + - export LD_LIBRARY_PATH="$PATH:$PWD/vcpkg/installed/x64-windows/bin:$PWD/vcpkg/installed/x64-windows/lib" + - export PYICU_INCLUDES="$PWD/vcpkg/installed/x64-windows/include" + - export PYICU_LFLAGS='/LIBPATH:$PWD/vcpkg/installed/x64-windows/bin' +# - wget -q https://github.com/unicode-org/icu/releases/download/release-65-1/icu4c-65_1-Win64-MSVC2017.zip -O icu4c.zip +# - unzip -q icu4c.zip -d icu4c # - export PATH="$PATH:$PWD/icu4c/bin64" # - export LD_LIBRARY_PATH="$PATH:$PWD/icu4c/bin64:$PWD/icu4c/lib64" # - export PYICU_INCLUDES="$PWD/icu4c/include" From 80d95165f56b9bfe8606b7642e4a0de40d8f9589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 6 Feb 2020 02:15:32 +0100 Subject: [PATCH 92/99] Adjust am/pm tests for platforms that do not localize them --- tests/test_data_types.py | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/tests/test_data_types.py b/tests/test_data_types.py index ab0c7de7..e07849c6 100644 --- a/tests/test_data_types.py +++ b/tests/test_data_types.py @@ -376,15 +376,29 @@ def test_cast_format(self): def test_cast_format_locale(self): date_type = DateTime(datetime_format='%Y-%m-%d %I:%M %p', locale='ko_KR') - values = ('1994-03-01 12:30 였후', '2011-02-17 06:30 였전', None, '1984-01-05 06:30 였후', 'n/a') - casted = tuple(date_type.cast(v) for v in values) - self.assertSequenceEqual(casted, ( - datetime.datetime(1994, 3, 1, 12, 30, 0), - datetime.datetime(2011, 2, 17, 6, 30, 0), - None, - datetime.datetime(1984, 1, 5, 18, 30, 0), - None - )) + # Date formats depend on the platform's strftime/strptime implementation; + # some platforms like macOS always return AM/PM for day periods (%p) + possible_values = ( + ('1994-03-01 12:30 였후', '2011-02-17 06:30 였전', None, '1984-01-05 06:30 였후', 'n/a'), + ('1994-03-01 12:30 PM', '2011-02-17 06:30 AM', None, '1984-01-05 06:30 PM', 'n/a'), + ) + valid = False + exceptions = [] + for values in possible_values: + try: + casted = tuple(date_type.cast(v) for v in values) + self.assertSequenceEqual(casted, ( + datetime.datetime(1994, 3, 1, 12, 30, 0), + datetime.datetime(2011, 2, 17, 6, 30, 0), + None, + datetime.datetime(1984, 1, 5, 18, 30, 0), + None + )) + valid = True + except CastError as e: + exceptions.append(e) + if not valid: + raise CastError(exceptions) def test_cast_locale(self): date_type = DateTime(locale='fr_FR') From a7039577075492610e8a41b8f16a24a1b3b55d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 6 Feb 2020 10:04:55 +0100 Subject: [PATCH 93/99] test_cast_format_locale(): Better position for try/except, and raise AssertionError if invalid --- tests/test_data_types.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/test_data_types.py b/tests/test_data_types.py index e07849c6..b9f1e55b 100644 --- a/tests/test_data_types.py +++ b/tests/test_data_types.py @@ -377,7 +377,8 @@ def test_cast_format_locale(self): date_type = DateTime(datetime_format='%Y-%m-%d %I:%M %p', locale='ko_KR') # Date formats depend on the platform's strftime/strptime implementation; - # some platforms like macOS always return AM/PM for day periods (%p) + # some platforms like macOS always return AM/PM for day periods (%p), + # so we will catch any CastError that may arise from the conversion possible_values = ( ('1994-03-01 12:30 였후', '2011-02-17 06:30 였전', None, '1984-01-05 06:30 였후', 'n/a'), ('1994-03-01 12:30 PM', '2011-02-17 06:30 AM', None, '1984-01-05 06:30 PM', 'n/a'), @@ -387,18 +388,19 @@ def test_cast_format_locale(self): for values in possible_values: try: casted = tuple(date_type.cast(v) for v in values) - self.assertSequenceEqual(casted, ( - datetime.datetime(1994, 3, 1, 12, 30, 0), - datetime.datetime(2011, 2, 17, 6, 30, 0), - None, - datetime.datetime(1984, 1, 5, 18, 30, 0), - None - )) - valid = True except CastError as e: - exceptions.append(e) + exceptions.append(repr(e)) + continue + self.assertSequenceEqual(casted, ( + datetime.datetime(1994, 3, 1, 12, 30, 0), + datetime.datetime(2011, 2, 17, 6, 30, 0), + None, + datetime.datetime(1984, 1, 5, 18, 30, 0), + None + )) + valid = True if not valid: - raise CastError(exceptions) + raise AssertionError('\n\n'.join(exceptions)) def test_cast_locale(self): date_type = DateTime(locale='fr_FR') From fe73ca7552af1635792f2811793d14b0395f1275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20CORBASSON?= Date: Thu, 6 Feb 2020 12:15:48 +0100 Subject: [PATCH 94/99] Add ICU_VERSION to macOS build --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a053b671..95049dec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,10 +24,12 @@ jobs: - brew install icu4c - export PATH="$PATH:/usr/local/opt/icu4c/bin" - export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/icu4c/lib/pkgconfig" + - which uconv - uconv -V + - export ICU_VERSION="$(uconv -V | sed -e 's,.*\ Date: Thu, 6 Feb 2020 12:29:19 +0100 Subject: [PATCH 95/99] Remove date samples --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 95049dec..c568e9d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,8 +28,6 @@ jobs: - uconv -V - export ICU_VERSION="$(uconv -V | sed -e 's,.*\ Date: Thu, 6 Feb 2020 19:16:16 +0100 Subject: [PATCH 96/99] Optimize nosetests --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c568e9d2..71206212 100644 --- a/.travis.yml +++ b/.travis.yml @@ -100,13 +100,13 @@ script: - > if [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then find tests -type f -name "*.py" | while read s; do - ( [ ! -x "$s" ] && nosetests -v "$s" ) || ( echo "$s" >> "script-failures.log" ); + ( [ ! -x "$s" ] && nosetests -s -v --no-byte-compile "$s" ) || ( echo "$s" >> "script-failures.log" ); done; if [ -e "script-failures.log" ]; then exit 1; fi; else - nosetests tests; + nosetests --no-byte-compile --with-coverage tests; fi after_failure: - > From c17fe89180dab449274bf90c51ce5fa1d31f7dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Thu, 6 Feb 2020 19:31:14 +0100 Subject: [PATCH 97/99] Run each test in its own process on PyPy* The previous commit was sufficient for PyPy3 and to fix tests.test_py3.TestSniffer.test_sniffer() where csv_py3.Sniffer().sniff(contents).__dict__ on some Python versions where it was empty. This commit tries to fix segfault issues on PyPy by breaking the tests in yet more processes. --- .travis.yml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 71206212..27576add 100644 --- a/.travis.yml +++ b/.travis.yml @@ -96,11 +96,22 @@ install: fi # command to run tests script: - # pypy3 segfaults if running all tests in the same process + # pypy2 and pypy3 segfault on Travis CI if running all tests in the same process - > - if [[ "$TRAVIS_PYTHON_VERSION" == "pypy"* ]]; then + if [[ "$TRAVIS_PYTHON_VERSION" == "pypy" ]]; then + nosetests --collect-only -v tests 2>&1 + | grep -e 'ok$' + | while read func class etc; do + class="${class//[()]/}"; + class="${class%.*}:${class##*.}"; + python3 -m nose -v "$class.$func"; + done || ( echo "$s" >> "script-failures.log" ); + if [ -e "script-failures.log" ]; then + exit 1; + fi; + elif [[ "$TRAVIS_PYTHON_VERSION" == "pypy3" ]]; then find tests -type f -name "*.py" | while read s; do - ( [ ! -x "$s" ] && nosetests -s -v --no-byte-compile "$s" ) || ( echo "$s" >> "script-failures.log" ); + ( [ ! -x "$s" ] && nosetests --no-byte-compile -s -v "$s" ) || ( echo "$s" >> "script-failures.log" ); done; if [ -e "script-failures.log" ]; then exit 1; From bf694ad3c05ce8b9e97537afcb9cdf17fdc6a22d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Thu, 6 Feb 2020 19:34:33 +0100 Subject: [PATCH 98/99] fix typos --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 27576add..d94f7bf2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -99,8 +99,8 @@ script: # pypy2 and pypy3 segfault on Travis CI if running all tests in the same process - > if [[ "$TRAVIS_PYTHON_VERSION" == "pypy" ]]; then - nosetests --collect-only -v tests 2>&1 - | grep -e 'ok$' + nosetests --collect-only -v tests 2>&1 \ + | grep -e 'ok$' \ | while read func class etc; do class="${class//[()]/}"; class="${class%.*}:${class##*.}"; From f070b71a8edb8b46cf6492215146979d661c36dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Corbasson?= Date: Thu, 6 Feb 2020 19:49:01 +0100 Subject: [PATCH 99/99] Fix typo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d94f7bf2..74b429f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -104,7 +104,7 @@ script: | while read func class etc; do class="${class//[()]/}"; class="${class%.*}:${class##*.}"; - python3 -m nose -v "$class.$func"; + nosetests -v "$class.$func"; done || ( echo "$s" >> "script-failures.log" ); if [ -e "script-failures.log" ]; then exit 1;