mirror of
https://github.com/kennethreitz/tablib.git
synced 2026-06-05 15:00:19 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e8f54811c7 | |||
| e8774043ed | |||
| dc1729fc6f | |||
| 3dc62685f8 | |||
| 22c88de90d | |||
| 615e308559 | |||
| 8c5404591b | |||
| 5fa4496f9d | |||
| bc8438bda4 | |||
| ce79e44d14 |
@@ -2,23 +2,39 @@ name: Docs and lint
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.8]
|
||||
env:
|
||||
- TOXENV: docs
|
||||
- TOXENV: lint
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
python-version: 3.9
|
||||
|
||||
- name: Get pip cache dir
|
||||
id: pip-cache
|
||||
run: |
|
||||
echo "::set-output name=dir::$(pip cache dir)"
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.pip-cache.outputs.dir }}
|
||||
key:
|
||||
${{ matrix.os }}-${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.py') }}
|
||||
restore-keys: |
|
||||
${{ matrix.os }}-${{ matrix.python-version }}-v1-
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: github.repository == 'jazzband/tablib'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
- name: Get pip cache dir
|
||||
id: pip-cache
|
||||
run: |
|
||||
echo "::set-output name=dir::$(pip cache dir)"
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.pip-cache.outputs.dir }}
|
||||
key: release-${{ hashFiles('**/setup.py') }}
|
||||
restore-keys: |
|
||||
release-
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install -U pip
|
||||
python -m pip install -U setuptools twine wheel
|
||||
|
||||
- name: Build package
|
||||
run: |
|
||||
python setup.py --version
|
||||
python setup.py sdist --format=gztar bdist_wheel
|
||||
twine check dist/*
|
||||
|
||||
- name: Upload packages to Jazzband
|
||||
if: github.event.action == 'published'
|
||||
uses: pypa/gh-action-pypi-publish@master
|
||||
with:
|
||||
user: jazzband
|
||||
password: ${{ secrets.JAZZBAND_RELEASE_KEY }}
|
||||
repository_url: https://jazzband.co/projects/tablib/upload
|
||||
@@ -2,24 +2,40 @@ name: Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: [3.5, 3.6, 3.7, 3.8]
|
||||
python-version: [3.6, 3.7, 3.8, 3.9]
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v1
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Get pip cache dir
|
||||
id: pip-cache
|
||||
run: |
|
||||
echo "::set-output name=dir::$(pip cache dir)"
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.pip-cache.outputs.dir }}
|
||||
key:
|
||||
${{ matrix.os }}-${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.py') }}
|
||||
restore-keys: |
|
||||
${{ matrix.os }}-${{ matrix.python-version }}-v1-
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
@@ -30,3 +46,8 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
tox -e py
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
name: ${{ matrix.os }} Python ${{ matrix.python-version }}
|
||||
|
||||
@@ -38,3 +38,6 @@ htmlcov
|
||||
# setuptools noise
|
||||
.eggs
|
||||
*.egg-info
|
||||
|
||||
# generated by setuptools-scm
|
||||
/src/tablib/_version.py
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
repos:
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v1.26.2
|
||||
rev: v2.7.3
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: ["--py3-plus"]
|
||||
args: ["--py36-plus"]
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-isort
|
||||
rev: v4.3.21
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 5.6.4
|
||||
hooks:
|
||||
- id: isort
|
||||
additional_dependencies: [toml]
|
||||
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: v1.4.4
|
||||
rev: v1.7.0
|
||||
hooks:
|
||||
- id: python-check-blanket-noqa
|
||||
- id: rst-backticks
|
||||
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v2.4.0
|
||||
rev: v3.3.0
|
||||
hooks:
|
||||
- id: check-merge-conflict
|
||||
- id: check-toml
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
language: python
|
||||
cache:
|
||||
pip: true
|
||||
directories:
|
||||
- $HOME/.cache/pre-commit
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- python: 3.8
|
||||
env: TOXENV=docs
|
||||
- python: 3.8
|
||||
env: TOXENV=lint
|
||||
- python: 3.8
|
||||
- python: 3.7
|
||||
- python: 3.6
|
||||
|
||||
install: travis_retry pip install tox-travis
|
||||
|
||||
script: tox
|
||||
|
||||
after_success:
|
||||
- |
|
||||
if [[ "$TOXENV" != "docs" && "$TOXENV" != "lint" ]]; then
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
fi
|
||||
|
||||
deploy:
|
||||
provider: pypi
|
||||
user: jazzband
|
||||
server: https://jazzband.co/projects/tablib/upload
|
||||
distributions: sdist bdist_wheel
|
||||
password:
|
||||
secure: svV4fYtodwW+iTyFOm5ISEfhVwcA+6vTskD3x6peznc40TdMV9Ek8nT3Q/NB4lCbXoUw2qR4H6uhLCjesnv/VvVk/qbitCyD8ySlgwOV5n7NzJs8lC8EYaHSjGQjatTwJAokfGVYkPawkI7HXDqtDggLUQBK+Ag8HDW+XBSbQIU=
|
||||
on:
|
||||
tags: true
|
||||
repo: jazzband/tablib
|
||||
python: 3.7
|
||||
+15
@@ -1,5 +1,20 @@
|
||||
# History
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- Dropped Python 3.5 support
|
||||
|
||||
### Improvements
|
||||
|
||||
- Added Python 3.9 support
|
||||
- Added read_only option to xlsx file reader (#482).
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- Prevented crash in rst export with only-space strings (#469).
|
||||
|
||||
## 2.0.0 (2020-05-16)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[](https://pypi.org/project/tablib/)
|
||||
[](https://pypi.org/project/tablib/)
|
||||
[](https://pypistats.org/packages/tablib)
|
||||
[](https://travis-ci.org/jazzband/tablib)
|
||||
[](https://github.com/jazzband/tablib/actions)
|
||||
[](https://codecov.io/gh/jazzband/tablib)
|
||||
[](LICENSE)
|
||||
|
||||
+3
-3
@@ -3,9 +3,9 @@
|
||||
Jazzband guidelines: https://jazzband.co/about/releases
|
||||
|
||||
* [ ] Get master to the appropriate code release state.
|
||||
[Travis CI](https://travis-ci.org/jazzband/tablib)
|
||||
[GitHub Actions](https://github.com/jazzband/tablib/actions)
|
||||
should pass on master.
|
||||
[](https://travis-ci.org/jazzband/tablib)
|
||||
[](https://github.com/jazzband/tablib/actions)
|
||||
|
||||
* [ ] Check [HISTORY.md](https://github.com/jazzband/tablib/blob/master/HISTORY.md),
|
||||
update version number and release date
|
||||
@@ -16,7 +16,7 @@ git tag -a v0.14.0 -m v0.14.0
|
||||
git push --tags
|
||||
```
|
||||
|
||||
* [ ] Once Travis CI has built and uploaded distributions, check files at
|
||||
* [ ] Once GitHub Actions has built and uploaded distributions, check files at
|
||||
[Jazzband](https://jazzband.co/projects/tablib) and release to
|
||||
[PyPI](https://pypi.org/pypi/tablib)
|
||||
|
||||
|
||||
Vendored
+1
@@ -8,4 +8,5 @@
|
||||
<li><a href="https://pypi.org/project/tablib">Tablib @ PyPI</a></li>
|
||||
<li><a href="https://github.com/jazzband/tablib">Tablib @ GitHub</a></li>
|
||||
<li><a href="https://github.com/jazzband/tablib/issues">Issue Tracker</a></li>
|
||||
<li><a href="https://github.com/jazzband/tablib/blob/master/HISTORY.md">Changelog</a></li>
|
||||
</ul>
|
||||
|
||||
+3
-3
@@ -9,7 +9,7 @@
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
from pkg_resources import get_distribution
|
||||
import tablib
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
@@ -49,9 +49,9 @@ copyright = '2019 Jazzband'
|
||||
# built documents.
|
||||
#
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = get_distribution('tablib').version
|
||||
release = tablib.__version__
|
||||
# The short X.Y version.
|
||||
version = '.'.join(release.split('.')[:2])
|
||||
version = '.'.join(tablib.__version__.split('.')[:2])
|
||||
# for example take major/minor
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
|
||||
@@ -163,16 +163,16 @@ the easiest way to test your changes for potential issues is to simply run the t
|
||||
Continuous Integration
|
||||
----------------------
|
||||
|
||||
Every pull request is automatically tested and inspected upon receipt with `Travis CI`_.
|
||||
Every pull request is automatically tested and inspected upon receipt with `GitHub Actions`_.
|
||||
If you broke the build, you will receive an email accordingly.
|
||||
|
||||
Anyone may view the build status and history at any time.
|
||||
|
||||
https://travis-ci.org/jazzband/tablib
|
||||
https://github.com/jazzband/tablib/actions
|
||||
|
||||
Additional reports will also be included here in the future, including :pep:`8` checks and stress reports for extremely large datasets.
|
||||
|
||||
.. _`Travis CI`: https://travis-ci.org/
|
||||
.. _`GitHub Actions`: https://github.com/jazzband/tablib/actions
|
||||
|
||||
|
||||
.. _docs:
|
||||
|
||||
+16
-7
@@ -27,7 +27,7 @@ For example::
|
||||
dataset.export("cli", tablefmt="github")
|
||||
dataset.export("cli", tablefmt="grid")
|
||||
|
||||
This format is optional, install Tablib with ``pip install tablib[cli]`` to
|
||||
This format is optional, install Tablib with ``pip install "tablib[cli]"`` to
|
||||
make the format available.
|
||||
|
||||
csv
|
||||
@@ -83,7 +83,7 @@ df (DataFrame)
|
||||
==============
|
||||
|
||||
Import/export using the pandas_ DataFrame format. This format is optional,
|
||||
install Tablib with ``pip install tablib[pandas]`` to make the format available.
|
||||
install Tablib with ``pip install "tablib[pandas]"`` to make the format available.
|
||||
|
||||
.. _pandas: https://pandas.pydata.org/
|
||||
|
||||
@@ -94,7 +94,7 @@ The ``html`` format is currently export-only. The exports produce an HTML page
|
||||
with the data in a ``<table>``. If headers have been set, they will be used as
|
||||
table headers.
|
||||
|
||||
This format is optional, install Tablib with ``pip install tablib[html]`` to
|
||||
This format is optional, install Tablib with ``pip install "tablib[html]"`` to
|
||||
make the format available.
|
||||
|
||||
jira
|
||||
@@ -132,7 +132,7 @@ ods
|
||||
Export data in OpenDocument Spreadsheet format. The ``ods`` format is currently
|
||||
export-only.
|
||||
|
||||
This format is optional, install Tablib with ``pip install tablib[ods]`` to
|
||||
This format is optional, install Tablib with ``pip install "tablib[ods]"`` to
|
||||
make the format available.
|
||||
|
||||
.. admonition:: Binary Warning
|
||||
@@ -183,7 +183,7 @@ xls
|
||||
|
||||
Import/export data in Legacy Excel Spreadsheet representation.
|
||||
|
||||
This format is optional, install Tablib with ``pip install tablib[xls]`` to
|
||||
This format is optional, install Tablib with ``pip install "tablib[xls]"`` to
|
||||
make the format available.
|
||||
|
||||
.. note::
|
||||
@@ -203,9 +203,18 @@ xlsx
|
||||
|
||||
Import/export data in Excel 07+ Spreadsheet representation.
|
||||
|
||||
This format is optional, install Tablib with ``pip install tablib[xlsx]`` to
|
||||
This format is optional, install Tablib with ``pip install "tablib[xlsx]"`` to
|
||||
make the format available.
|
||||
|
||||
The ``import_set()`` and ``import_book()`` methods accept keyword
|
||||
argument ``read_only``. If its value is ``True`` (the default), the
|
||||
XLSX data source is read lazily. Lazy reading generally reduces time
|
||||
and memory consumption, especially for large spreadsheets. However,
|
||||
it relies on the XLSX data source declaring correct dimensions. Some
|
||||
programs generate XLSX files with incorrect dimensions. Such files
|
||||
may need to be loaded with this optimization turned off by passing
|
||||
``read_only=False``.
|
||||
|
||||
.. note::
|
||||
|
||||
When reading an ``xlsx`` file containing formulas in its cells, Tablib will
|
||||
@@ -232,7 +241,7 @@ returned instead.
|
||||
|
||||
Import assumes (for now) that headers exist.
|
||||
|
||||
This format is optional, install Tablib with ``pip install tablib[yaml]`` to
|
||||
This format is optional, install Tablib with ``pip install "tablib[yaml]"`` to
|
||||
make the format available.
|
||||
|
||||
.. _YAML: https://yaml.org
|
||||
|
||||
+3
-3
@@ -26,19 +26,19 @@ formats available:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install tablib[xlsx]
|
||||
$ pip install "tablib[xlsx]"
|
||||
|
||||
Or all possible formats:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install tablib[all]
|
||||
$ pip install "tablib[all]"
|
||||
|
||||
which is equivalent to:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install tablib[html, pandas, ods, xls, xlsx, yaml]
|
||||
$ pip install "tablib[html, pandas, ods, xls, xlsx, yaml]"
|
||||
|
||||
-------------------
|
||||
Download the Source
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ THE SOFTWARE.
|
||||
Pythons Supported
|
||||
-----------------
|
||||
|
||||
Python 3.5+ is officially supported.
|
||||
Python 3.6+ is officially supported.
|
||||
|
||||
Now, go :ref:`install Tablib <install>`.
|
||||
|
||||
|
||||
+1
-6
@@ -1,7 +1,2 @@
|
||||
[tool.isort]
|
||||
force_grid_wrap = 0
|
||||
include_trailing_comma = true
|
||||
known_third_party = ["MarkupPy", "odf", "openpyxl", "pkg_resources", "setuptools", "tablib", "xlrd", "xlwt", "yaml"]
|
||||
line_length = 88
|
||||
multi_line_output = 3
|
||||
use_parentheses = true
|
||||
profile = "black"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
[pytest]
|
||||
norecursedirs = .git .*
|
||||
addopts = -rsxX --showlocals --tb=native --cov=tablib --cov=tests --cov-report xml --cov-report term --cov-report html
|
||||
python_paths = .
|
||||
|
||||
@@ -4,7 +4,9 @@ from setuptools import find_packages, setup
|
||||
|
||||
setup(
|
||||
name='tablib',
|
||||
use_scm_version=True,
|
||||
use_scm_version={
|
||||
'write_to': 'src/tablib/_version.py',
|
||||
},
|
||||
setup_requires=['setuptools_scm'],
|
||||
description='Format agnostic tabular data library (XLS, JSON, YAML, CSV)',
|
||||
long_description=(
|
||||
@@ -31,12 +33,12 @@ setup(
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3 :: Only',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
],
|
||||
python_requires='>=3.5',
|
||||
python_requires='>=3.6',
|
||||
extras_require={
|
||||
'all': ['markuppy', 'odfpy', 'openpyxl>=2.6.0', 'pandas', 'pyyaml', 'tabulate', 'xlrd', 'xlwt'],
|
||||
'cli': ['tabulate'],
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
""" Tablib. """
|
||||
from pkg_resources import DistributionNotFound, get_distribution
|
||||
try:
|
||||
# Generated by setuptools-scm.
|
||||
from ._version import version as __version__
|
||||
except ImportError:
|
||||
# Some broken installation.
|
||||
__version__ = None
|
||||
|
||||
|
||||
from tablib.core import ( # noqa: F401
|
||||
Databook,
|
||||
Dataset,
|
||||
@@ -10,9 +17,3 @@ from tablib.core import ( # noqa: F401
|
||||
import_book,
|
||||
import_set,
|
||||
)
|
||||
|
||||
try:
|
||||
__version__ = get_distribution(__name__).version
|
||||
except DistributionNotFound:
|
||||
# package is not installed
|
||||
__version__ = None
|
||||
|
||||
+22
-30
@@ -57,18 +57,10 @@ class Row:
|
||||
del self._row[i]
|
||||
|
||||
def __getstate__(self):
|
||||
|
||||
slots = dict()
|
||||
|
||||
for slot in self.__slots__:
|
||||
attribute = getattr(self, slot)
|
||||
slots[slot] = attribute
|
||||
|
||||
return slots
|
||||
return self._row, self.tags
|
||||
|
||||
def __setstate__(self, state):
|
||||
for (k, v) in list(state.items()):
|
||||
setattr(self, k, v)
|
||||
self._row, self.tags = state
|
||||
|
||||
def rpush(self, value):
|
||||
self.insert(len(self._row), value)
|
||||
@@ -147,9 +139,9 @@ class Dataset:
|
||||
|
||||
.. admonition:: Format Attributes Definition
|
||||
|
||||
If you look at the code, the various output/import formats are not
|
||||
defined within the :class:`Dataset` object. To add support for a new format, see
|
||||
:ref:`Adding New Formats <newformats>`.
|
||||
If you look at the code, the various output/import formats are not
|
||||
defined within the :class:`Dataset` object. To add support for a new format, see
|
||||
:ref:`Adding New Formats <newformats>`.
|
||||
|
||||
"""
|
||||
|
||||
@@ -299,7 +291,7 @@ class Dataset:
|
||||
def _get_headers(self):
|
||||
"""An *optional* list of strings to be used for header rows and attribute names.
|
||||
|
||||
This must be set manually. The given list length must equal :class:`Dataset.width`.
|
||||
This must be set manually. The given list length must equal :attr:`Dataset.width`.
|
||||
|
||||
"""
|
||||
return self.__headers
|
||||
@@ -335,7 +327,7 @@ class Dataset:
|
||||
set, a list of Python dictionaries will be returned. If no headers have been
|
||||
set, a list of tuples (rows) will be returned instead.
|
||||
|
||||
A dataset object can also be imported by setting the :class:`Dataset.dict` attribute. ::
|
||||
A dataset object can also be imported by setting the :attr:`Dataset.dict` attribute. ::
|
||||
|
||||
data = tablib.Dataset()
|
||||
data.dict = [{'age': 90, 'first_name': 'Kenneth', 'last_name': 'Reitz'}]
|
||||
@@ -414,10 +406,10 @@ class Dataset:
|
||||
|
||||
fmt = registry.get_format(format)
|
||||
if not hasattr(fmt, 'import_set'):
|
||||
raise UnsupportedFormat('Format {} cannot be imported.'.format(format))
|
||||
raise UnsupportedFormat(f'Format {format} cannot be imported.')
|
||||
|
||||
if not import_set:
|
||||
raise UnsupportedFormat('Format {} cannot be imported.'.format(format))
|
||||
raise UnsupportedFormat(f'Format {format} cannot be imported.')
|
||||
|
||||
fmt.import_set(self, stream, **kwargs)
|
||||
return self
|
||||
@@ -430,7 +422,7 @@ class Dataset:
|
||||
"""
|
||||
fmt = registry.get_format(format)
|
||||
if not hasattr(fmt, 'export_set'):
|
||||
raise UnsupportedFormat('Format {} cannot be exported.'.format(format))
|
||||
raise UnsupportedFormat(f'Format {format} cannot be exported.')
|
||||
|
||||
return fmt.export_set(self, **kwargs)
|
||||
|
||||
@@ -452,28 +444,28 @@ class Dataset:
|
||||
|
||||
def rpush(self, row, tags=list()):
|
||||
"""Adds a row to the end of the :class:`Dataset`.
|
||||
See :class:`Dataset.insert` for additional documentation.
|
||||
See :method:`Dataset.insert` for additional documentation.
|
||||
"""
|
||||
|
||||
self.insert(self.height, row=row, tags=tags)
|
||||
|
||||
def lpush(self, row, tags=list()):
|
||||
"""Adds a row to the top of the :class:`Dataset`.
|
||||
See :class:`Dataset.insert` for additional documentation.
|
||||
See :method:`Dataset.insert` for additional documentation.
|
||||
"""
|
||||
|
||||
self.insert(0, row=row, tags=tags)
|
||||
|
||||
def append(self, row, tags=list()):
|
||||
"""Adds a row to the :class:`Dataset`.
|
||||
See :class:`Dataset.insert` for additional documentation.
|
||||
See :method:`Dataset.insert` for additional documentation.
|
||||
"""
|
||||
|
||||
self.rpush(row, tags)
|
||||
|
||||
def extend(self, rows, tags=list()):
|
||||
"""Adds a list of rows to the :class:`Dataset` using
|
||||
:class:`Dataset.append`
|
||||
:method:`Dataset.append`
|
||||
"""
|
||||
|
||||
for row in rows:
|
||||
@@ -515,20 +507,20 @@ class Dataset:
|
||||
|
||||
data.append_col(col=random.randint)
|
||||
|
||||
If inserting a column, and :class:`Dataset.headers` is set, the
|
||||
If inserting a column, and :attr:`Dataset.headers` is set, the
|
||||
header attribute must be set, and will be considered the header for
|
||||
that row.
|
||||
|
||||
See :ref:`dyncols` for an in-depth example.
|
||||
|
||||
.. versionchanged:: 0.9.0
|
||||
If inserting a column, and :class:`Dataset.headers` is set, the
|
||||
If inserting a column, and :attr:`Dataset.headers` is set, the
|
||||
header attribute must be set, and will be considered the header for
|
||||
that row.
|
||||
|
||||
.. versionadded:: 0.9.0
|
||||
If inserting a row, you can add :ref:`tags <tags>` to the row you are inserting.
|
||||
This gives you the ability to :class:`filter <Dataset.filter>` your
|
||||
This gives you the ability to :method:`filter <Dataset.filter>` your
|
||||
:class:`Dataset` later.
|
||||
|
||||
"""
|
||||
@@ -565,14 +557,14 @@ class Dataset:
|
||||
|
||||
def rpush_col(self, col, header=None):
|
||||
"""Adds a column to the end of the :class:`Dataset`.
|
||||
See :class:`Dataset.insert` for additional documentation.
|
||||
See :method:`Dataset.insert` for additional documentation.
|
||||
"""
|
||||
|
||||
self.insert_col(self.width, col, header=header)
|
||||
|
||||
def lpush_col(self, col, header=None):
|
||||
"""Adds a column to the top of the :class:`Dataset`.
|
||||
See :class:`Dataset.insert` for additional documentation.
|
||||
See :method:`Dataset.insert` for additional documentation.
|
||||
"""
|
||||
|
||||
self.insert_col(0, col, header=header)
|
||||
@@ -596,7 +588,7 @@ class Dataset:
|
||||
|
||||
def append_col(self, col, header=None):
|
||||
"""Adds a column to the :class:`Dataset`.
|
||||
See :class:`Dataset.insert_col` for additional documentation.
|
||||
See :method:`Dataset.insert_col` for additional documentation.
|
||||
"""
|
||||
|
||||
self.rpush_col(col, header)
|
||||
@@ -875,7 +867,7 @@ class Databook:
|
||||
|
||||
fmt = registry.get_format(format)
|
||||
if not hasattr(fmt, 'import_book'):
|
||||
raise UnsupportedFormat('Format {} cannot be loaded.'.format(format))
|
||||
raise UnsupportedFormat(f'Format {format} cannot be loaded.')
|
||||
|
||||
fmt.import_book(self, stream, **kwargs)
|
||||
return self
|
||||
@@ -888,7 +880,7 @@ class Databook:
|
||||
"""
|
||||
fmt = registry.get_format(format)
|
||||
if not hasattr(fmt, 'export_book'):
|
||||
raise UnsupportedFormat('Format {} cannot be exported.'.format(format))
|
||||
raise UnsupportedFormat(f'Format {format} cannot be exported.')
|
||||
|
||||
return fmt.export_book(self, **kwargs)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ def load_format_class(dotted_path):
|
||||
module_path, class_name = dotted_path.rsplit('.', 1)
|
||||
return getattr(import_module(module_path), class_name)
|
||||
except (ValueError, AttributeError) as err:
|
||||
raise ImportError("Unable to load format class '{}' ({})".format(dotted_path, err))
|
||||
raise ImportError(f"Unable to load format class '{dotted_path}' ({err})")
|
||||
|
||||
|
||||
class FormatDescriptorBase:
|
||||
@@ -122,7 +122,7 @@ class Registry:
|
||||
if key in uninstalled_format_messages:
|
||||
raise UnsupportedFormat(
|
||||
"The '{key}' format is not available. You may want to install the "
|
||||
"{package_name} (or `pip install tablib[{extras_name}]`).".format(
|
||||
"{package_name} (or `pip install \"tablib[{extras_name}]\"`).".format(
|
||||
**uninstalled_format_messages[key], key=key
|
||||
)
|
||||
)
|
||||
|
||||
@@ -30,7 +30,7 @@ class DataFrameFormat:
|
||||
if DataFrame is None:
|
||||
raise NotImplementedError(
|
||||
'DataFrame Format requires `pandas` to be installed.'
|
||||
' Try `pip install tablib[pandas]`.')
|
||||
' Try `pip install "tablib[pandas]"`.')
|
||||
dataframe = DataFrame(dset.dict, columns=dset.headers)
|
||||
return dataframe
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ class HTMLFormat:
|
||||
|
||||
for i, dset in enumerate(databook._datasets):
|
||||
title = (dset.title if dset.title else 'Set %s' % (i))
|
||||
wrapper.write('<{}>{}</{}>\n'.format(cls.BOOK_ENDINGS, title, cls.BOOK_ENDINGS))
|
||||
wrapper.write(f'<{cls.BOOK_ENDINGS}>{title}</{cls.BOOK_ENDINGS}>\n')
|
||||
wrapper.write(dset.html)
|
||||
wrapper.write('\n')
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ class JIRAFormat:
|
||||
|
||||
header = cls._get_header(dataset.headers) if dataset.headers else ''
|
||||
body = cls._get_body(dataset)
|
||||
return '{}\n{}'.format(header, body) if header else body
|
||||
return f'{header}\n{body}' if header else body
|
||||
|
||||
@classmethod
|
||||
def _get_body(cls, dataset):
|
||||
|
||||
@@ -24,7 +24,7 @@ def _max_word_len(text):
|
||||
>>> _max_word_len('Python Module for Tabular Datasets')
|
||||
8
|
||||
"""
|
||||
return max(len(word) for word in text.split()) if text else 0
|
||||
return max([len(word) for word in text.split()], default=0) if text else 0
|
||||
|
||||
|
||||
class ReSTFormat:
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
|
||||
from io import BytesIO
|
||||
|
||||
import tablib
|
||||
import xlrd
|
||||
import xlwt
|
||||
from xlrd.xldate import xldate_as_datetime
|
||||
|
||||
import tablib
|
||||
|
||||
# special styles
|
||||
wrap = xlwt.easyxf("alignment: wrap on")
|
||||
bold = xlwt.easyxf("font: bold on")
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
|
||||
from io import BytesIO
|
||||
|
||||
import tablib
|
||||
from openpyxl.reader.excel import ExcelReader, load_workbook
|
||||
from openpyxl.styles import Alignment, Font
|
||||
from openpyxl.utils import get_column_letter
|
||||
from openpyxl.workbook import Workbook
|
||||
from openpyxl.writer.excel import ExcelWriter
|
||||
|
||||
import tablib
|
||||
|
||||
|
||||
class XLSXFormat:
|
||||
title = 'xlsx'
|
||||
@@ -58,12 +59,12 @@ class XLSXFormat:
|
||||
return stream.getvalue()
|
||||
|
||||
@classmethod
|
||||
def import_set(cls, dset, in_stream, headers=True):
|
||||
def import_set(cls, dset, in_stream, headers=True, read_only=True):
|
||||
"""Returns databook from XLS stream."""
|
||||
|
||||
dset.wipe()
|
||||
|
||||
xls_book = load_workbook(in_stream, read_only=True, data_only=True)
|
||||
xls_book = load_workbook(in_stream, read_only=read_only, data_only=True)
|
||||
sheet = xls_book.active
|
||||
|
||||
dset.title = sheet.title
|
||||
@@ -76,12 +77,12 @@ class XLSXFormat:
|
||||
dset.append(row_vals)
|
||||
|
||||
@classmethod
|
||||
def import_book(cls, dbook, in_stream, headers=True):
|
||||
def import_book(cls, dbook, in_stream, headers=True, read_only=True):
|
||||
"""Returns databook from XLS stream."""
|
||||
|
||||
dbook.wipe()
|
||||
|
||||
xls_book = load_workbook(in_stream, read_only=True, data_only=True)
|
||||
xls_book = load_workbook(in_stream, read_only=read_only, data_only=True)
|
||||
|
||||
for sheet in xls_book.worksheets:
|
||||
data = tablib.Dataset()
|
||||
@@ -114,7 +115,7 @@ class XLSXFormat:
|
||||
row_number = i + 1
|
||||
for j, col in enumerate(row):
|
||||
col_idx = get_column_letter(j + 1)
|
||||
cell = ws['{}{}'.format(col_idx, row_number)]
|
||||
cell = ws[f'{col_idx}{row_number}']
|
||||
|
||||
# bold headers
|
||||
if (row_number == 1) and dataset.headers:
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
""" Tablib - YAML Support.
|
||||
"""
|
||||
|
||||
import tablib
|
||||
import yaml
|
||||
|
||||
import tablib
|
||||
|
||||
|
||||
class YAMLFormat:
|
||||
title = 'yaml'
|
||||
|
||||
@@ -315,7 +315,7 @@ class DbfLogicalFieldDef(DbfFieldDef):
|
||||
return False
|
||||
if value in "YyTt":
|
||||
return True
|
||||
raise ValueError("[{}] Invalid logical value {!r}".format(self.name, value))
|
||||
raise ValueError(f"[{self.name}] Invalid logical value {value!r}")
|
||||
|
||||
def encodeValue(self, value):
|
||||
"""Return a character from the "TF?" set.
|
||||
|
||||
Binary file not shown.
+12
-2
@@ -11,8 +11,9 @@ from io import BytesIO, StringIO
|
||||
from pathlib import Path
|
||||
from uuid import uuid4
|
||||
|
||||
import tablib
|
||||
from MarkupPy import markup
|
||||
|
||||
import tablib
|
||||
from tablib.core import Row, detect_format
|
||||
from tablib.exceptions import UnsupportedFormat
|
||||
from tablib.formats import registry
|
||||
@@ -57,7 +58,7 @@ class TablibTestCase(BaseTestCase):
|
||||
# A known format but uninstalled
|
||||
del registry._formats['ods']
|
||||
msg = (r"The 'ods' format is not available. You may want to install the "
|
||||
"odfpy package \\(or `pip install tablib\\[ods\\]`\\).")
|
||||
"odfpy package \\(or `pip install \"tablib\\[ods\\]\"`\\).")
|
||||
with self.assertRaisesRegex(UnsupportedFormat, msg):
|
||||
data.export('ods')
|
||||
|
||||
@@ -659,6 +660,7 @@ class RSTTests(BaseTestCase):
|
||||
data.headers = self.headers
|
||||
data.append(self.john)
|
||||
data.append(('Wendy', '', 43))
|
||||
data.append(('Esther', ' ', 31))
|
||||
self.assertEqual(
|
||||
data.export('rst'),
|
||||
'========== ========= ===\n'
|
||||
@@ -666,6 +668,7 @@ class RSTTests(BaseTestCase):
|
||||
'========== ========= ===\n'
|
||||
'John Adams 90 \n'
|
||||
'Wendy 43 \n'
|
||||
'Esther 31 \n'
|
||||
'========== ========= ==='
|
||||
)
|
||||
|
||||
@@ -1037,6 +1040,13 @@ class XLSXTests(BaseTestCase):
|
||||
data = tablib.Dataset().load(fh)
|
||||
self.assertEqual(data.headers[0], 'Hello World')
|
||||
|
||||
def test_xlsx_bad_dimensions(self):
|
||||
"""Test loading file with bad dimension. Must be done with
|
||||
read_only=False."""
|
||||
xls_source = Path(__file__).parent / 'files' / 'bad_dimensions.xlsx'
|
||||
with xls_source.open('rb') as fh:
|
||||
data = tablib.Dataset().load(fh, read_only=False)
|
||||
self.assertEqual(data.height, 3)
|
||||
|
||||
class JSONTests(BaseTestCase):
|
||||
def test_json_format_detect(self):
|
||||
|
||||
@@ -4,12 +4,14 @@ minversion = 2.4
|
||||
envlist =
|
||||
docs
|
||||
lint
|
||||
py{35,36,37,38}
|
||||
py{36,37,38,39}
|
||||
|
||||
[testenv]
|
||||
deps =
|
||||
-rtests/requirements.txt
|
||||
extras = pandas
|
||||
passenv =
|
||||
FORCE_COLOR
|
||||
commands =
|
||||
pytest {posargs:tests}
|
||||
|
||||
@@ -35,4 +37,3 @@ skip_install = true
|
||||
[flake8]
|
||||
exclude =
|
||||
.tox
|
||||
ignore=E501,E127,E128,E124
|
||||
|
||||
Reference in New Issue
Block a user