Skip to content

Commit

Permalink
merge release/0.5.2
Browse files Browse the repository at this point in the history
  • Loading branch information
CI committed Mar 26, 2019
2 parents 130df67 + fbf3d10 commit 3485abb
Show file tree
Hide file tree
Showing 12 changed files with 238 additions and 135 deletions.
5 changes: 5 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
Release 0.5.2
-------------
* Add docx table renderer option
* Update django and pyyaml requirements for security patches

Release 0.5.1
-------------
* Update retrieve method to handle export rendering
Expand Down
6 changes: 3 additions & 3 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ verify_ssl = true
name = "pypi"

[packages]
tablib = "*"
tablib = ">=0.13"
djangorestframework = "*"
django = "*"
django = ">=2.1.6"
"psycopg2-binary" = "*"
openpyxl = "<2.5" # https://github.com/kennethreitz/tablib/issues/331
openpyxl = "*"
reportlab = "*"
djangorestframework-csv = "*"
python-docx = "*"
Expand Down
270 changes: 142 additions & 128 deletions Pipfile.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
combine_as_imports = true
default_section = THIRDPARTY
include_trailing_comma = true
known_first_party = unicef_rest_export
known_first_party = unicef_rest_export,tests
multi_line_output = 0
line_length=120
balanced_wrapping = true
Expand Down
1 change: 1 addition & 0 deletions src/requirements/install.pip
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
backports.csv
defusedxml
django
djangorestframework-csv
Expand Down
1 change: 1 addition & 0 deletions src/requirements/testing.pip
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
atomicwrites
attrs
coverage
entrypoints
factory-boy
faker
filelock
Expand Down
2 changes: 1 addition & 1 deletion src/unicef_rest_export/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
NAME = 'unicef_rest_export'
VERSION = __version__ = "0.5.1"
VERSION = __version__ = "0.5.2"
__author__ = 'UNICEF'
41 changes: 39 additions & 2 deletions src/unicef_rest_export/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,9 +277,12 @@ def render_dataset(self, data, *args, **kwargs):
fp.write(self.export_set(formatted))


class ExportDocxRenderer(ExportFileRenderer):
"""Renders dataset as Doc (.docx)"""
class ExportDocxBaseRenderer(ExportFileRenderer):
media_type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"


class ExportDocxRenderer(ExportDocxBaseRenderer):
"""Renders dataset as Doc (.docx)"""
format = "docx"

def export_set(self, formatted):
Expand All @@ -303,6 +306,40 @@ def render_dataset(self, data, *args, **kwargs):
fp.write(self.export_set(formatted))


class ExportDocxTableRenderer(ExportDocxBaseRenderer):
"""Renders dataset as Doc (.docx) in table format"""
format = "docx_table"

def export_set(self, formatted, headers):
stream = BytesIO()
doc = Document()

if not headers:
doc.add_paragraph("No data provided.")
else:
table = doc.add_table(rows=1, cols=len(headers))

# set heading text
header_cells = table.rows[0].cells
for i, heading in enumerate(headers):
header_cells[i].text = heading

# set data
for record in formatted:
row = table.add_row().cells
for i, data in enumerate(record):
row[i].text = str(data)

doc.save(stream)
return stream.getvalue()

def render_dataset(self, data, *args, **kwargs):
formatted = data._package()
headers = data.headers
with open(self.filename, "wb") as fp:
fp.write(self.export_set(formatted, headers))


class FriendlyCSVRenderer(CSVRenderer):
def flatten_item(self, item):
if isinstance(item, bool):
Expand Down
1 change: 1 addition & 0 deletions src/unicef_rest_export/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"unicef_rest_export.renderers.ExportPDFRenderer",
"unicef_rest_export.renderers.ExportPDFTableRenderer",
"unicef_rest_export.renderers.ExportDocxRenderer",
"unicef_rest_export.renderers.ExportDocxTableRenderer",
)
if "unicef_rest_export" in settings.INSTALLED_APPS:
DEFAULT_TEMPLATE = True
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest
from rest_framework.test import APIClient

from tests import factories


Expand Down
1 change: 1 addition & 0 deletions tests/test_renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from django.urls import reverse
from rest_framework.test import APIClient
from tablib import Dataset

from tests.factories import BookFactory, UserFactory


Expand Down
42 changes: 42 additions & 0 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.urls import reverse
from rest_framework.test import APIClient
from tablib import Dataset

from tests.factories import BookFactory, UserFactory

pytestmark = pytest.mark.django_db
Expand Down Expand Up @@ -134,6 +135,12 @@ def test_export_view_list_docx_empty(api_client):
assert response.status_code == 200


def test_export_view_list_docx_table_empty(api_client):
url = "{}?format=docx_table".format(reverse("sample:author-view"))
response = api_client.get(url)
assert response.status_code == 200


def test_export_view_list_pdf(api_client, author):
url = "{}?format=pdf".format(reverse("sample:author-view"))
response = api_client.get(url)
Expand Down Expand Up @@ -168,6 +175,12 @@ def test_export_view_list_docx(api_client, author):
assert response.status_code == 200


def test_export_view_list_docx_table(api_client, author):
url = "{}?format=docx_table".format(reverse("sample:author-view"))
response = api_client.get(url)
assert response.status_code == 200


def test_export_view_retrieve_docx(api_client, book):
url = "{}?format=docx".format(
reverse("sample:book-detail", args=[book.pk])
Expand All @@ -176,6 +189,14 @@ def test_export_view_retrieve_docx(api_client, book):
assert response.status_code == 200


def test_export_view_retrieve_docx_table(api_client, book):
url = "{}?format=docx_table".format(
reverse("sample:book-detail", args=[book.pk])
)
response = api_client.get(url)
assert response.status_code == 200


def test_export_view_list_invalid_format(api_client, author):
url = "{}?format=wrong".format(reverse("sample:author-view"))
response = api_client.get(url)
Expand Down Expand Up @@ -241,6 +262,14 @@ def test_export_view_foreignkey_list_docx(api_client, book):
assert response.status_code == 200


def test_export_view_foreignkey_list_docx_table(api_client, book):
url = "{}?format=docx_table".format(reverse("sample:book-view"))
response = api_client.get(url)
with open("/tmp/file.docx", "wb") as fp:
fp.write(response.content)
assert response.status_code == 200


def test_export_view_list_pdf_text_blob(api_client):
BookFactory(description=factory.Faker("sentence", nb_words=800))
url = "{}?format=pdf".format(reverse("sample:book-view"))
Expand All @@ -262,6 +291,13 @@ def test_export_view_list_docx_text_blob(api_client):
assert response.status_code == 200


def test_export_view_list_docx_table_text_blob(api_client):
BookFactory(description=factory.Faker("sentence", nb_words=800))
url = "{}?format=docx_table".format(reverse("sample:book-view"))
response = api_client.get(url)
assert response.status_code == 200


def test_export_view_list_transform_json(api_client, book):
url = "{}?format=json".format(reverse("sample:author-transform"))
response = api_client.get(url)
Expand Down Expand Up @@ -310,6 +346,12 @@ def test_export_view_list_transform_docx(api_client, book):
assert response.status_code == 200


def test_export_view_list_transform_docx_table(api_client, book):
url = "{}?format=docx_table".format(reverse("sample:author-transform"))
response = api_client.get(url)
assert response.status_code == 200


def test_export_view_list_invalid(api_client, author):
"""If list serializer extends ListSerializer instead of ExportSerializer"""
url = "{}?format=json".format(reverse("sample:author-invalid"))
Expand Down

0 comments on commit 3485abb

Please sign in to comment.