Skip to content

Commit 4bc78d6

Browse files
authored
New style writer (#76)
* 🔨 code up the new writer interface * 🐴 prototype * 🚜 new style csv writer for file, content and stream * This is an auto-commit, updating project meta data, such as changelog.rst, contributors.rst * 💚 add test dependency * This is an auto-commit, updating project meta data, such as changelog.rst, contributors.rst * 💚 update moban update yaml * 💄 update coding style with latest black, isort * ✨ tsv writers in new style * 🐴 new style csvz writer * 🐴 new style tsvz writer * 🔥 remove old style csvz and tsvz writers * 🔥 remove old style csv and tsv writer * 📚 update changelog * 🚜 code refactoring and update 📚 * This is an auto-commit, updating project meta data, such as changelog.rst, contributors.rst * 🚜 rename sheet writer files * 🔥 remove .moban.hashes * 🔥 remove useless set_type function call * 💄 update coding style Co-authored-by: chfw <chfw@users.noreply.github.com>
1 parent 7a3957c commit 4bc78d6

25 files changed

+331
-213
lines changed

.github/workflows/moban-update.yml

+22-20
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,25 @@ jobs:
55
runs-on: ubuntu-latest
66
name: synchronize templates via moban
77
steps:
8-
- uses: actions/checkout@v2
9-
with:
10-
ref: ${{ github.head_ref }}
11-
- name: Set up Python
12-
uses: actions/setup-python@v1
13-
with:
14-
python-version: '3.7'
15-
- name: check changes
16-
run: |
17-
pip install moban gitfs2 pypifs
18-
moban
19-
git status
20-
git diff --exit-code
21-
- name: Auto-commit
22-
if: failure()
23-
uses: docker://cdssnc/auto-commit-github-action
24-
env:
25-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26-
with:
27-
args: This is an auto-commit, updating project meta data, such as changelog.rst, contributors.rst
8+
- uses: actions/checkout@v2
9+
with:
10+
ref: ${{ github.head_ref }}
11+
- name: Set up Python
12+
uses: actions/setup-python@v1
13+
with:
14+
python-version: '3.7'
15+
- name: check changes
16+
run: |
17+
pip install moban gitfs2 pypifs moban-jinja2-github moban-ansible
18+
moban
19+
git status
20+
git diff --exit-code
21+
- name: Auto-commit
22+
if: failure()
23+
uses: docker://cdssnc/auto-commit-github-action
24+
env:
25+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26+
with:
27+
args: >-
28+
This is an auto-commit, updating project meta data,
29+
such as changelog.rst, contributors.rst

CHANGELOG.rst

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ Change log
1313

1414
#. python 3.6 lower versions are no longer supported
1515

16+
**updated**
17+
18+
#. pyexcel-io plugin interface has been rewritten. PyInstaller user will be
19+
impacted.
20+
1621
0.5.20 - 17.7.2019
1722
--------------------------------------------------------------------------------
1823

changelog.yml

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ releases:
88
- action: removed
99
details:
1010
- 'python 3.6 lower versions are no longer supported'
11+
- action: updated
12+
details:
13+
- 'pyexcel-io plugin interface has been rewritten. PyInstaller user will be impacted.'
1114
version: 0.6.0
1215
date: tbd
1316
- changes:

docs/source/pyinstaller.rst

+27-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,30 @@
11
Packaging with PyInstaller
22
================================================================================
33

4+
With pyexcel-io v0.6.0, the way to package it has been changed because
5+
plugin interface update.
6+
7+
Built-in plugins for pyexcel-io
8+
---------------------------------
9+
10+
In order to package every built-in plugins of pyexcel-io, you need to specify::
11+
12+
--hidden-import pyexcel_io.readers.csvr
13+
--hidden-import pyexcel_io.readers.csvz
14+
--hidden-import pyexcel_io.readers.tsv
15+
--hidden-import pyexcel_io.readers.tsvz
16+
--hidden-import pyexcel_io.writers.csv_file_writer
17+
--hidden-import pyexcel_io.writers.csv_memory_writer
18+
--hidden-import pyexcel_io.writers.tsv_file_writer
19+
--hidden-import pyexcel_io.writers.tsv_memory_writer
20+
--hidden-import pyexcel_io.writers.csvz_writer
21+
--hidden-import pyexcel_io.writers.tsvz_writer
22+
--hidden-import pyexcel_io.database.importers.django
23+
--hidden-import pyexcel_io.database.importers.sqlalchemy
24+
--hidden-import pyexcel_io.database.exporters.django
25+
--hidden-import pyexcel_io.database.exporters.sqlalchemy
26+
27+
428
With pyexcel-io v0.4.0, the way to package it has been changed because it
529
uses lml for all plugins.
630

@@ -14,9 +38,9 @@ In order to package every built-in plugins of pyexcel-io, you need to specify::
1438
--hidden-import pyexcel_io.readers.tsv
1539
--hidden-import pyexcel_io.readers.tsvz
1640
--hidden-import pyexcel_io.writers.csvw
17-
--hidden-import pyexcel_io.readers.csvz
18-
--hidden-import pyexcel_io.readers.tsv
19-
--hidden-import pyexcel_io.readers.tsvz
41+
--hidden-import pyexcel_io.writers.csvz
42+
--hidden-import pyexcel_io.writers.tsv
43+
--hidden-import pyexcel_io.writers.tsvz
2044
--hidden-import pyexcel_io.database.importers.django
2145
--hidden-import pyexcel_io.database.importers.sqlalchemy
2246
--hidden-import pyexcel_io.database.exporters.django

pyexcel-io.yml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ test_dependencies:
1515
- pyexcel
1616
- pyexcel-xls
1717
- SQLAlchemy
18+
- pyexcel-xlsxw
1819
extra_dependencies:
1920
- xls:
2021
- pyexcel-xls>=0.5.0

pyexcel_io/io.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from pyexcel_io import constants
1515
from pyexcel_io.reader import Reader
1616
from pyexcel_io.writer import Writer
17-
from pyexcel_io.plugins import OLD_READERS
17+
from pyexcel_io.plugins import OLD_READERS, OLD_WRITERS
1818
from pyexcel_io._compact import isstream
1919
from pyexcel_io.exceptions import (
2020
NoSupportingPluginFound,
@@ -244,7 +244,11 @@ def get_writer(
244244

245245
file_type_given = False
246246

247-
writer = Writer(file_type, library)
247+
try:
248+
writer = OLD_WRITERS.get_a_plugin(file_type, library)
249+
except (NoSupportingPluginFound, SupportingPluginAvailableButNotInstalled):
250+
writer = Writer(file_type, library)
251+
248252
if file_name:
249253
if file_type_given:
250254
writer.open_content(file_name, **keywords)

pyexcel_io/plugins.py

+43-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
READER_PLUGIN = "pyexcel-io reader"
2121
NEW_READER_PLUGIN = "pyexcel-io new reader"
2222
WRITER_PLUGIN = "pyexcel-io writer"
23+
NEW_WRITER_PLUGIN = "pyexcel-io new writer"
2324

2425

2526
class IOPluginInfo(PluginInfo):
@@ -83,6 +84,26 @@ def add_a_reader(
8384
)
8485
return self.add_a_plugin_instance(a_plugin_info)
8586

87+
def add_a_writer(
88+
self,
89+
relative_plugin_class_path=None,
90+
locations=(),
91+
file_types=(),
92+
stream_type=None,
93+
):
94+
""" add pyexcle-io writer plugin info """
95+
a_plugin_info = IOPluginInfo(
96+
NEW_WRITER_PLUGIN,
97+
self._get_abs_path(relative_plugin_class_path),
98+
file_types=[
99+
f"{location}-{file_type}"
100+
for file_type in file_types
101+
for location in locations
102+
],
103+
stream_type=stream_type,
104+
)
105+
return self.add_a_plugin_instance(a_plugin_info)
106+
86107

87108
class IOManager(PluginManager):
88109
"""Manage pyexcel-io plugins"""
@@ -143,20 +164,19 @@ def get_all_formats(self):
143164
class NewIOManager(IOManager):
144165
def load_me_later(self, plugin_info):
145166
PluginManager.load_me_later(self, plugin_info)
146-
_do_additional_registration(plugin_info)
167+
_do_additional_registration_for_new_plugins(plugin_info)
147168

148169
def register_a_plugin(self, cls, plugin_info):
149170
""" for dynamically loaded plugin """
150171
PluginManager.register_a_plugin(self, cls, plugin_info)
151-
_do_additional_registration(plugin_info)
172+
_do_additional_registration_for_new_plugins(plugin_info)
152173

153174
def get_a_plugin(
154175
self, file_type=None, location=None, library=None, **keywords
155176
):
156177
__file_type = file_type.lower()
157178
plugin = self.load_me_now(f"{location}-{__file_type}", library=library)
158179
handler = plugin()
159-
handler.set_type(__file_type)
160180
return handler
161181

162182
def raise_exception(self, file_type):
@@ -194,17 +214,36 @@ def _do_additional_registration(plugin_info):
194214
manager.register_a_file_type(file_type, plugin_info.stream_type, None)
195215

196216

217+
def _do_additional_registration_for_new_plugins(plugin_info):
218+
for file_type in plugin_info.tags():
219+
manager.register_stream_type(
220+
file_type.split("-")[1], plugin_info.stream_type
221+
)
222+
manager.register_a_file_type(
223+
file_type.split("-")[1], plugin_info.stream_type, None
224+
)
225+
226+
197227
class FakeReaders:
198228
def get_all_formats(self):
199229
return OLD_READERS.get_all_formats().union(
200230
NEW_READERS.get_all_formats()
201231
)
202232

203233

234+
class FakeWriters:
235+
def get_all_formats(self):
236+
return OLD_WRITERS.get_all_formats().union(
237+
NEW_WRITERS.get_all_formats()
238+
)
239+
240+
204241
OLD_READERS = IOManager(READER_PLUGIN, ioutils.AVAILABLE_READERS)
205-
WRITERS = IOManager(WRITER_PLUGIN, ioutils.AVAILABLE_WRITERS)
242+
OLD_WRITERS = IOManager(WRITER_PLUGIN, ioutils.AVAILABLE_WRITERS)
243+
NEW_WRITERS = NewIOManager(NEW_WRITER_PLUGIN, ioutils.AVAILABLE_WRITERS)
206244
NEW_READERS = NewIOManager(NEW_READER_PLUGIN, ioutils.AVAILABLE_READERS)
207245
READERS = FakeReaders()
246+
WRITERS = FakeWriters()
208247

209248

210249
def load_plugins(plugin_name_patterns, path, black_list, white_list):

pyexcel_io/readers/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
:copyright: (c) 2014-2020 by Onni Software Ltd.
88
:license: New BSD License, see LICENSE for more details
99
"""
10-
from pyexcel_io.plugins import IOPluginInfoChain, NewIOPluginInfoChain
10+
from pyexcel_io.plugins import NewIOPluginInfoChain
1111

1212
NewIOPluginInfoChain(__name__).add_a_reader(
1313
relative_plugin_class_path="csv_file_reader.FileReader",

pyexcel_io/writer.py

+30-11
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,43 @@
1-
from pyexcel_io.plugins import WRITERS
1+
from pyexcel_io.plugins import NEW_WRITERS
2+
from pyexcel_io._compact import isstream
3+
4+
from .constants import MESSAGE_ERROR_03
25

36

47
class Writer(object):
5-
def __init__(self, file_type, library):
6-
self.writer = WRITERS.get_a_plugin(file_type, library)
8+
def __init__(self, file_type, library=None):
9+
self.file_type = file_type
10+
self.library = library
11+
self.keyboards = None
712

813
def open(self, file_name, **keywords):
14+
self.writer = NEW_WRITERS.get_a_plugin(
15+
self.file_type, library=self.library, location="file"
16+
)
917
self.writer.open(file_name, **keywords)
1018

11-
def open_stream(self, file_stream, **keywords):
12-
self.writer.open_stream(file_stream, **keywords)
13-
1419
def open_content(self, file_stream, **keywords):
15-
self.writer.open_content(file_stream, **keywords)
20+
if not isstream(file_stream):
21+
raise IOError(MESSAGE_ERROR_03)
22+
self.writer = NEW_WRITERS.get_a_plugin(
23+
self.file_type, library=self.library, location="content"
24+
)
25+
self.writer.open(file_stream, **keywords)
1626

17-
def write(self, incoming_dict):
18-
self.writer.write(incoming_dict)
27+
def open_stream(self, file_stream, **keywords):
28+
self.writer = NEW_WRITERS.get_a_plugin(
29+
self.file_type, library=self.library, location="memory"
30+
)
31+
self.writer.open(file_stream, **keywords)
1932

20-
def create_sheet(self, sheet_name):
21-
return self.writer.create_sheet(sheet_name)
33+
def write(self, incoming_dict):
34+
for sheet_name in incoming_dict:
35+
sheet_writer = self.writer.create_sheet(sheet_name)
36+
if sheet_writer:
37+
sheet_writer.write_array(incoming_dict[sheet_name])
38+
sheet_writer.close()
39+
else:
40+
raise Exception("Cannot create a sheet writer!")
2241

2342
def close(self):
2443
self.writer.close()

pyexcel_io/writers/__init__.py

+20-6
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,36 @@
77
:copyright: (c) 2014-2020 by Onni Software Ltd.
88
:license: New BSD License, see LICENSE for more details
99
"""
10-
from pyexcel_io.plugins import IOPluginInfoChain
10+
from pyexcel_io.plugins import NewIOPluginInfoChain
1111

12-
IOPluginInfoChain(__name__).add_a_writer(
13-
relative_plugin_class_path="csvw.CSVBookWriter",
12+
NewIOPluginInfoChain(__name__).add_a_writer(
13+
relative_plugin_class_path="csv_in_file.CsvFileWriter",
14+
locations=["file", "content"],
1415
file_types=["csv"],
1516
stream_type="text",
1617
).add_a_writer(
17-
relative_plugin_class_path="tsv.TSVBookWriter",
18+
relative_plugin_class_path="csv_in_memory.CsvMemoryWriter",
19+
locations=["memory"],
20+
file_types=["csv"],
21+
stream_type="text",
22+
).add_a_writer(
23+
relative_plugin_class_path="tsv_in_file.TsvFileWriter",
24+
locations=["file", "content"],
25+
file_types=["tsv"],
26+
stream_type="text",
27+
).add_a_writer(
28+
relative_plugin_class_path="tsv_in_memory.TsvMemoryWriter",
29+
locations=["memory"],
1830
file_types=["tsv"],
1931
stream_type="text",
2032
).add_a_writer(
21-
relative_plugin_class_path="csvz.CSVZipBookWriter",
33+
relative_plugin_class_path="csvz_writer.CsvZipWriter",
34+
locations=["memory", "file", "content"],
2235
file_types=["csvz"],
2336
stream_type="binary",
2437
).add_a_writer(
25-
relative_plugin_class_path="tsvz.TSVZipBookWriter",
38+
relative_plugin_class_path="tsvz_writer.TsvZipWriter",
39+
locations=["memory", "file", "content"],
2640
file_types=["tsvz"],
2741
stream_type="binary",
2842
)

pyexcel_io/writers/csv_in_file.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from pyexcel_io.writers.csv_sheet import CSVFileWriter
2+
3+
4+
class CsvFileWriter:
5+
def __init__(self):
6+
self.__index = 0
7+
self.writer = None
8+
9+
def open(self, file_alike_object, **keywords):
10+
self._file_alike_object = file_alike_object
11+
self._keywords = keywords
12+
13+
def create_sheet(self, name):
14+
self.writer = CSVFileWriter(
15+
self._file_alike_object,
16+
name,
17+
sheet_index=self.__index,
18+
**self._keywords
19+
)
20+
self.__index = self.__index + 1
21+
return self.writer
22+
23+
def close(self):
24+
if self.writer:
25+
self.writer.close()

pyexcel_io/writers/csv_in_memory.py

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from pyexcel_io.writers.csv_sheet import CSVMemoryWriter
2+
3+
4+
class CsvMemoryWriter:
5+
def __init__(self):
6+
self.__index = 0
7+
8+
def open(self, file_alike_object, **keywords):
9+
self._file_alike_object = file_alike_object
10+
self._keywords = keywords
11+
12+
def create_sheet(self, name):
13+
writer_class = CSVMemoryWriter
14+
writer = writer_class(
15+
self._file_alike_object,
16+
name,
17+
sheet_index=self.__index,
18+
**self._keywords
19+
)
20+
self.__index = self.__index + 1
21+
return writer
22+
23+
def close(self):
24+
pass

0 commit comments

Comments
 (0)