🤝 merge with master
This commit is contained in:
commit
3408497c81
19
.travis.yml
19
.travis.yml
|
@ -1,4 +1,3 @@
|
|||
|
||||
sudo: false
|
||||
dist: xenial
|
||||
language: python
|
||||
|
@ -18,32 +17,40 @@ stages:
|
|||
- lint
|
||||
|
||||
.disable_global: &disable_global
|
||||
addons: false
|
||||
cache: false
|
||||
env: {}
|
||||
python: false
|
||||
before_install: false
|
||||
install: true
|
||||
install: false
|
||||
before_script: false
|
||||
script: false
|
||||
after_success: false
|
||||
after_failure: false
|
||||
before_deploy: false
|
||||
deploy: false
|
||||
|
||||
.lint: &lint
|
||||
<<: *disable_global
|
||||
git:
|
||||
submodules: false
|
||||
python: 3.6
|
||||
stage: lint
|
||||
install: pip install flake8
|
||||
script: make lint
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- *moban
|
||||
- *lint
|
||||
|
||||
stage: test
|
||||
|
||||
script: make test
|
||||
|
||||
before_install:
|
||||
- if [[ -f min_requirements.txt && "$MINREQ" -eq 1 ]]; then
|
||||
mv min_requirements.txt requirements.txt ;
|
||||
fi
|
||||
- test ! -f rnd_requirements.txt || pip install --no-deps -r rnd_requirements.txt
|
||||
- test ! -f rnd_requirements.txt ||
|
||||
pip install --no-deps -r rnd_requirements.txt
|
||||
- test ! -f rnd_requirements.txt || pip install -r rnd_requirements.txt ;
|
||||
- pip install -r tests/requirements.txt
|
||||
script:
|
||||
|
|
|
@ -1,6 +1,24 @@
|
|||
Change log
|
||||
================================================================================
|
||||
|
||||
0.5.19 - 14.7.2019
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
updated
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
#. `pyexcel#185 <https://github.com/pyexcel/pyexcel/issues/185>`_: handle stream
|
||||
conversion if file type(html) needs string content then bytes to handle
|
||||
|
||||
0.5.18 - 12.06.2019
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
updated
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
#. `#69 <https://github.com/pyexcel/pyexcel-io/issues/69>`_: Force file
|
||||
type(force_file_type) on write
|
||||
|
||||
0.5.17 - 04.04.2019
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
name: pyexcel-io
|
||||
organisation: pyexcel
|
||||
releases:
|
||||
- changes:
|
||||
- action: updated
|
||||
details:
|
||||
- '`pyexcel#185`: handle stream conversion if file type(html) needs string content then bytes to handle'
|
||||
version: 0.5.19
|
||||
date: 14.7.2019
|
||||
- changes:
|
||||
- action: updated
|
||||
details:
|
||||
- '`#69`: Force file type(force_file_type) on write'
|
||||
version: 0.5.18
|
||||
date: 12.06.2019
|
||||
- changes:
|
||||
- action: updated
|
||||
details:
|
||||
|
|
|
@ -22,7 +22,7 @@ author = 'C.W.'
|
|||
# The short X.Y version
|
||||
version = '0.6.0'
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = '0.5.17'
|
||||
release = '0.5.19'
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
|
@ -69,4 +69,4 @@ html_static_path = ['static']
|
|||
# -- Options for intersphinx extension ---------------------------------------
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
1
lint.sh
1
lint.sh
|
@ -1 +1,2 @@
|
|||
pip install flake8
|
||||
flake8 . --exclude=.moban.d,docs --builtins=unicode,xrange,long
|
|
@ -4,8 +4,9 @@ name: pyexcel-io
|
|||
nick_name: io
|
||||
version: 0.6.0
|
||||
current_version: 0.6.0
|
||||
release: 0.5.19
|
||||
copyright_year: 2015-2019
|
||||
release: 0.5.17
|
||||
moban_command: false
|
||||
dependencies:
|
||||
- ordereddict;python_version<"2.7"
|
||||
- lml>=0.0.4
|
||||
|
|
|
@ -232,6 +232,16 @@ class BookWriter(RWInterface):
|
|||
|
||||
def _convert_content_to_stream(file_content, file_type):
|
||||
stream = manager.get_io(file_type)
|
||||
if not PY2:
|
||||
target_content_type = manager.get_io_type(file_type)
|
||||
needs_encode = (target_content_type == 'bytes' and
|
||||
not isinstance(file_content, bytes))
|
||||
needs_decode = (target_content_type == 'string' and
|
||||
isinstance(file_content, bytes))
|
||||
if needs_encode:
|
||||
file_content = file_content.encode('utf-8')
|
||||
elif needs_decode:
|
||||
file_content = file_content.decode('utf-8')
|
||||
stream.write(file_content)
|
||||
stream.seek(0)
|
||||
return stream
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
The io interface to file extensions
|
||||
|
||||
:copyright: (c) 2014-2017 by Onni Software Ltd.
|
||||
:copyright: (c) 2014-2019 by Onni Software Ltd.
|
||||
:license: New BSD License, see LICENSE for more details
|
||||
"""
|
||||
import os
|
||||
|
@ -24,7 +24,7 @@ def iget_data(afile, file_type=None, **keywords):
|
|||
:param sheet_name: the name of the sheet to be loaded
|
||||
:param sheet_index: the index of the sheet to be loaded
|
||||
:param sheets: a list of sheet to be loaded
|
||||
:param file_type: used only when filename is not a physial file name
|
||||
:param file_type: used only when filename is not a physical file name
|
||||
:param force_file_type: used only when filename refers to a physical file
|
||||
and it is intended to open it as forced file type.
|
||||
:param streaming: toggles the type of returned data. The values of the
|
||||
|
@ -99,6 +99,8 @@ def save_data(afile, data, file_type=None, **keywords):
|
|||
:param filename: actual file name, a file stream or actual content
|
||||
:param data: a dictionary but an ordered dictionary is preferred
|
||||
:param file_type: used only when filename is not a physial file name
|
||||
:param force_file_type: used only when filename refers to a physical file
|
||||
and it is intended to open it as forced file type.
|
||||
:param library: explicitly name a library for use.
|
||||
e.g. library='pyexcel-ods'
|
||||
:param keywords: any other parameters that python csv module's
|
||||
|
@ -201,7 +203,8 @@ def load_data(
|
|||
|
||||
|
||||
def get_writer(
|
||||
file_name=None, file_stream=None, file_type=None, library=None, **keywords
|
||||
file_name=None, file_stream=None, file_type=None,
|
||||
library=None, force_file_type=None, **keywords
|
||||
):
|
||||
"""find a suitable writer"""
|
||||
inputs = [file_name, file_stream]
|
||||
|
@ -211,11 +214,15 @@ def get_writer(
|
|||
raise IOError(constants.MESSAGE_ERROR_02)
|
||||
|
||||
file_type_given = True
|
||||
|
||||
if file_type is None and file_name:
|
||||
try:
|
||||
file_type = file_name.split(".")[-1]
|
||||
except AttributeError:
|
||||
raise Exception("file_name should be a string type")
|
||||
if force_file_type:
|
||||
file_type = force_file_type
|
||||
else:
|
||||
try:
|
||||
file_type = file_name.split(".")[-1]
|
||||
except AttributeError:
|
||||
raise Exception("file_name should be a string type")
|
||||
|
||||
file_type_given = False
|
||||
|
||||
|
|
120
setup.py
120
setup.py
|
@ -1,14 +1,14 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Template by pypi-mobans
|
||||
import os
|
||||
import sys
|
||||
import codecs
|
||||
import locale
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
from shutil import rmtree
|
||||
|
||||
from setuptools import Command, setup, find_packages
|
||||
from setuptools import Command, find_packages, setup
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
PY26 = PY2 and sys.version_info[1] < 7
|
||||
|
@ -22,69 +22,73 @@ PY33 = sys.version_info < (3, 4)
|
|||
try:
|
||||
lc = locale.getlocale()
|
||||
pf = platform.system()
|
||||
if pf != 'Windows' and lc == (None, None):
|
||||
locale.setlocale(locale.LC_ALL, 'C.UTF-8')
|
||||
if pf != "Windows" and lc == (None, None):
|
||||
locale.setlocale(locale.LC_ALL, "C.UTF-8")
|
||||
except (ValueError, UnicodeError, locale.Error):
|
||||
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
|
||||
locale.setlocale(locale.LC_ALL, "en_US.UTF-8")
|
||||
|
||||
NAME = 'pyexcel-io'
|
||||
AUTHOR = 'C.W.'
|
||||
VERSION = '0.6.0'
|
||||
EMAIL = 'info@pyexcel.org'
|
||||
LICENSE = 'New BSD'
|
||||
NAME = "pyexcel-io"
|
||||
AUTHOR = "C.W."
|
||||
VERSION = "0.6.0"
|
||||
EMAIL = "info@pyexcel.org"
|
||||
LICENSE = "New BSD"
|
||||
DESCRIPTION = (
|
||||
'A python library to read and write structured data in csv, zipped csv' +
|
||||
'format and to/from databases'
|
||||
"A python library to read and write structured data in csv, zipped csv" +
|
||||
"format and to/from databases"
|
||||
)
|
||||
URL = 'https://github.com/pyexcel/pyexcel-io'
|
||||
DOWNLOAD_URL = '%s/archive/0.5.17.tar.gz' % URL
|
||||
FILES = ['README.rst', 'CHANGELOG.rst']
|
||||
URL = "https://github.com/pyexcel/pyexcel-io"
|
||||
DOWNLOAD_URL = "%s/archive/0.5.19.tar.gz" % URL
|
||||
FILES = ["README.rst", "CHANGELOG.rst"]
|
||||
KEYWORDS = [
|
||||
'python',
|
||||
'API',
|
||||
'tsv',
|
||||
'tsvz',
|
||||
'csv',
|
||||
'csvz',
|
||||
'django',
|
||||
'sqlalchemy',
|
||||
"python",
|
||||
"API",
|
||||
"tsv",
|
||||
"tsvz",
|
||||
"csv",
|
||||
"csvz",
|
||||
"django",
|
||||
"sqlalchemy",
|
||||
]
|
||||
|
||||
CLASSIFIERS = [
|
||||
'Topic :: Software Development :: Libraries',
|
||||
'Programming Language :: Python',
|
||||
'Intended Audience :: Developers',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
"Topic :: Software Development :: Libraries",
|
||||
"Programming Language :: Python",
|
||||
"Intended Audience :: Developers",
|
||||
"Programming Language :: Python :: 2.6",
|
||||
"Programming Language :: Python :: 2.7",
|
||||
"Programming Language :: Python :: 3.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",
|
||||
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Programming Language :: Python :: Implementation :: PyPy'
|
||||
]
|
||||
|
||||
INSTALL_REQUIRES = [
|
||||
'lml>=0.0.4',
|
||||
"lml>=0.0.4",
|
||||
]
|
||||
SETUP_COMMANDS = {}
|
||||
|
||||
if PY26:
|
||||
INSTALL_REQUIRES.append('ordereddict')
|
||||
|
||||
PACKAGES = find_packages(exclude=['ez_setup', 'examples', 'tests'])
|
||||
PACKAGES = find_packages(exclude=["ez_setup", "examples", "tests"])
|
||||
EXTRAS_REQUIRE = {
|
||||
'xls': ['pyexcel-xls>=0.5.0'],
|
||||
'xlsx': ['pyexcel-xlsx>=0.5.0'],
|
||||
'ods': ['pyexcel-ods3>=0.5.0'],
|
||||
"xls": ['pyexcel-xls>=0.5.0'],
|
||||
"xlsx": ['pyexcel-xlsx>=0.5.0'],
|
||||
"ods": ['pyexcel-ods3>=0.5.0'],
|
||||
}
|
||||
# You do not need to read beyond this line
|
||||
PUBLISH_COMMAND = '{0} setup.py sdist bdist_wheel upload -r pypi'.format(
|
||||
sys.executable)
|
||||
GS_COMMAND = ('gs pyexcel-io v0.5.17 ' +
|
||||
"Find 0.5.17 in changelog for more details")
|
||||
NO_GS_MESSAGE = ('Automatic github release is disabled. ' +
|
||||
'Please install gease to enable it.')
|
||||
PUBLISH_COMMAND = "{0} setup.py sdist bdist_wheel upload -r pypi".format(sys.executable)
|
||||
GS_COMMAND = ("gs pyexcel-io v0.5.19 " +
|
||||
"Find 0.5.19 in changelog for more details")
|
||||
NO_GS_MESSAGE = ("Automatic github release is disabled. " +
|
||||
"Please install gease to enable it.")
|
||||
UPLOAD_FAILED_MSG = (
|
||||
'Upload failed. please run "%s" yourself.' % PUBLISH_COMMAND)
|
||||
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||
|
@ -93,13 +97,13 @@ HERE = os.path.abspath(os.path.dirname(__file__))
|
|||
class PublishCommand(Command):
|
||||
"""Support setup.py upload."""
|
||||
|
||||
description = 'Build and publish the package on github and pypi'
|
||||
description = "Build and publish the package on github and pypi"
|
||||
user_options = []
|
||||
|
||||
@staticmethod
|
||||
def status(s):
|
||||
"""Prints things in bold."""
|
||||
print('\033[1m{0}\033[0m'.format(s))
|
||||
print("\033[1m{0}\033[0m".format(s))
|
||||
|
||||
def initialize_options(self):
|
||||
pass
|
||||
|
@ -109,14 +113,14 @@ class PublishCommand(Command):
|
|||
|
||||
def run(self):
|
||||
try:
|
||||
self.status('Removing previous builds...')
|
||||
rmtree(os.path.join(HERE, 'dist'))
|
||||
rmtree(os.path.join(HERE, 'build'))
|
||||
rmtree(os.path.join(HERE, 'pyexcel_io.egg-info'))
|
||||
self.status("Removing previous builds...")
|
||||
rmtree(os.path.join(HERE, "dist"))
|
||||
rmtree(os.path.join(HERE, "build"))
|
||||
rmtree(os.path.join(HERE, "pyexcel_io.egg-info"))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
self.status('Building Source and Wheel (universal) distribution...')
|
||||
self.status("Building Source and Wheel (universal) distribution...")
|
||||
run_status = True
|
||||
if has_gease():
|
||||
run_status = os.system(GS_COMMAND) == 0
|
||||
|
@ -130,7 +134,7 @@ class PublishCommand(Command):
|
|||
|
||||
|
||||
SETUP_COMMANDS.update({
|
||||
'publish': PublishCommand
|
||||
"publish": PublishCommand
|
||||
})
|
||||
|
||||
|
||||
|
@ -159,7 +163,7 @@ def read_files(*files):
|
|||
def read(afile):
|
||||
"""Read a file into setup"""
|
||||
the_relative_file = os.path.join(HERE, afile)
|
||||
with codecs.open(the_relative_file, 'r', 'utf-8') as opened_file:
|
||||
with codecs.open(the_relative_file, "r", "utf-8") as opened_file:
|
||||
content = filter_out_test_code(opened_file)
|
||||
content = "".join(list(content))
|
||||
return content
|
||||
|
@ -168,11 +172,11 @@ def read(afile):
|
|||
def filter_out_test_code(file_handle):
|
||||
found_test_code = False
|
||||
for line in file_handle.readlines():
|
||||
if line.startswith('.. testcode:'):
|
||||
if line.startswith(".. testcode:"):
|
||||
found_test_code = True
|
||||
continue
|
||||
if found_test_code is True:
|
||||
if line.startswith(' '):
|
||||
if line.startswith(" "):
|
||||
continue
|
||||
else:
|
||||
empty_line = line.strip()
|
||||
|
@ -182,14 +186,14 @@ def filter_out_test_code(file_handle):
|
|||
found_test_code = False
|
||||
yield line
|
||||
else:
|
||||
for keyword in ['|version|', '|today|']:
|
||||
for keyword in ["|version|", "|today|"]:
|
||||
if keyword in line:
|
||||
break
|
||||
else:
|
||||
yield line
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
setup(
|
||||
test_suite="tests",
|
||||
name=NAME,
|
||||
|
@ -203,7 +207,7 @@ if __name__ == '__main__':
|
|||
license=LICENSE,
|
||||
keywords=KEYWORDS,
|
||||
extras_require=EXTRAS_REQUIRE,
|
||||
tests_require=['nose'],
|
||||
tests_require=["nose"],
|
||||
install_requires=INSTALL_REQUIRES,
|
||||
packages=PACKAGES,
|
||||
include_package_data=True,
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
from pyexcel_io.book import BookReader, BookWriter, RWInterface
|
||||
|
||||
from nose.tools import raises
|
||||
from pyexcel_io.book import _convert_content_to_stream
|
||||
from pyexcel_io._compact import PY2, StringIO, BytesIO
|
||||
from nose import SkipTest
|
||||
|
||||
|
||||
@raises(NotImplementedError)
|
||||
|
@ -31,3 +34,21 @@ def test_book_reader_open_stream():
|
|||
def test_book_writer():
|
||||
writer = BookWriter()
|
||||
writer.open_stream("a string")
|
||||
|
||||
|
||||
def test_convert_to_bytes_stream():
|
||||
if PY2:
|
||||
raise SkipTest('No need test in python 2')
|
||||
else:
|
||||
file_content = b'test'
|
||||
stream = _convert_content_to_stream(file_content, 'csv')
|
||||
assert isinstance(stream, StringIO)
|
||||
|
||||
|
||||
def test_convert_to_string_stream():
|
||||
if PY2:
|
||||
raise SkipTest('No need test in python 2')
|
||||
else:
|
||||
file_content = 'test'
|
||||
stream = _convert_content_to_stream(file_content, 'csvz')
|
||||
assert isinstance(stream, BytesIO)
|
||||
|
|
|
@ -24,6 +24,21 @@ def test_force_file_type():
|
|||
eq_(expected, data[test_file])
|
||||
|
||||
|
||||
def test_force_file_type_on_write():
|
||||
test_file = "force_file_type_on_write.txt"
|
||||
save_data(
|
||||
test_file,
|
||||
{"sheet 1": [[1, 2]]},
|
||||
force_file_type="csv"
|
||||
)
|
||||
data = get_data(
|
||||
test_file, force_file_type="csv"
|
||||
)
|
||||
expected = [[1, 2]]
|
||||
eq_(expected, data[test_file])
|
||||
os.unlink(test_file)
|
||||
|
||||
|
||||
@raises(IOError)
|
||||
def test_invalid_file():
|
||||
load_data("/something/does/not/exist")
|
||||
|
|
Loading…
Reference in New Issue