From 001766f50057422473ed1eb4f46b1b663ec1194d Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Sat, 12 Oct 2019 15:00:46 +0200 Subject: [PATCH 1/7] Fix typo in .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 076bb8c..5df85d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,6 @@ python: dist: xenial install: - - python3 -m pip install -U pip -r dev-requirements.txt + - python3 -m pip install -U pip -r dev_requirements.txt script: - python3 -m pytest tests/ From 2cd9987e4cee2e9d1c1287f67fe439ea19b459a4 Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Sat, 12 Oct 2019 15:01:46 +0200 Subject: [PATCH 2/7] Update .travis.yml --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5df85d0..de9b45a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ cache: pip python: - 3.6 - 3.7 - - 3.8 dist: xenial install: From 8df7afcab4ccb76a03d5387a14097b539b8aa3ad Mon Sep 17 00:00:00 2001 From: Stephen Bosch Date: Sun, 13 Oct 2019 13:08:47 +0200 Subject: [PATCH 3/7] Add _get_all_shapes internal method Add _get_all_shapes internal method. The test simply checks to see if the attributes we expect to use the shape for are present and whether they can be coerced to strings. --- pptx_blueprint/__init__.py | 4 ++++ tests/test_template.py | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/pptx_blueprint/__init__.py b/pptx_blueprint/__init__.py index 955988c..9917b26 100644 --- a/pptx_blueprint/__init__.py +++ b/pptx_blueprint/__init__.py @@ -82,6 +82,10 @@ def _find_shapes_in_slide(slide): return matched_shapes + def _get_all_shapes(self) -> Iterable[BaseShape]: + all_shapes = [shape for slide in self._presentation.slides for shape in slide.shapes] + return all_shapes + def save(self, filename: _Pathlike) -> None: """Saves the updated pptx to the specified filepath. diff --git a/tests/test_template.py b/tests/test_template.py index a1ba1bd..6c2c97c 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -38,3 +38,8 @@ def test_find_shapes_from_one_slide(template): def test_find_shapes_index_out_of_range(template): with pytest.raises(IndexError): shapes = template._find_shapes(0, 'logo') + +def test_get_all_shapes(template): + shapes = template._get_all_shapes() + for shape in shapes: + assert str(shape.text) and str(shape.name) \ No newline at end of file From 853eee73ecd4f7082ad21609f94e99445e12c4ba Mon Sep 17 00:00:00 2001 From: Stephen Bosch Date: Sun, 13 Oct 2019 15:22:01 +0200 Subject: [PATCH 4/7] Copy tags to shape.name attribute for persistence Copy tags at template instantiation from shape.text to shape.name to make them resistant to user clobbering. --- pptx_blueprint/__init__.py | 14 +++++++++++++- tests/test_template.py | 11 ++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/pptx_blueprint/__init__.py b/pptx_blueprint/__init__.py index 9917b26..1d2a74c 100644 --- a/pptx_blueprint/__init__.py +++ b/pptx_blueprint/__init__.py @@ -1,5 +1,6 @@ import pathlib import pptx +import re from typing import Union, Iterable, Tuple from pptx.shapes.base import BaseShape @@ -18,6 +19,7 @@ def __init__(self, filename: _Pathlike) -> None: """ self._template_path = filename self._presentation = pptx.Presentation(filename) + self._copy_tags_to_name() pass def replace_text(self, label: str, new_text: str) -> None: @@ -66,7 +68,7 @@ def _find_shapes(self, matched_shapes = [] def _find_shapes_in_slide(slide): - return filter(lambda shape: shape.text == f'{{{tag_name}}}', slide.shapes) + return filter(lambda shape: shape.name == f'{{{tag_name}}}', slide.shapes) if slide_number == '*': slides = self._presentation.slides @@ -83,9 +85,19 @@ def _find_shapes_in_slide(slide): return matched_shapes def _get_all_shapes(self) -> Iterable[BaseShape]: + # Do we need all the shapes? Perhaps we should filter on tags here. all_shapes = [shape for slide in self._presentation.slides for shape in slide.shapes] return all_shapes + def _copy_tags_to_name(self) -> None: + all_shapes = self._get_all_shapes() + # This regex matches on tags + regex_tag = re.compile(r'\{[\s\w]*\}') + for shape in all_shapes: + # We only copy contents we recognize as tags + if regex_tag.match(shape.text): + shape.name = shape.text + def save(self, filename: _Pathlike) -> None: """Saves the updated pptx to the specified filepath. diff --git a/tests/test_template.py b/tests/test_template.py index 6c2c97c..d00a923 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -2,6 +2,7 @@ from pptx_blueprint import Template from pathlib import Path import pytest +import re @pytest.fixture @@ -42,4 +43,12 @@ def test_find_shapes_index_out_of_range(template): def test_get_all_shapes(template): shapes = template._get_all_shapes() for shape in shapes: - assert str(shape.text) and str(shape.name) \ No newline at end of file + assert str(shape.text) and str(shape.name) + +def test_copy_tags_to_name(template): + template._copy_tags_to_name() + all_shapes = template._get_all_shapes() + regex_tag = re.compile(r'\{[\s\w]*\}') + for shape in all_shapes: + if regex_tag.match(shape.text): + assert shape.text == shape.name \ No newline at end of file From 03465f9c805ddf16df05f58820f505fcacd55251 Mon Sep 17 00:00:00 2001 From: Stephen Bosch Date: Mon, 14 Oct 2019 21:06:08 +0200 Subject: [PATCH 5/7] Update pptx_blueprint/__init__.py Co-Authored-By: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- pptx_blueprint/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pptx_blueprint/__init__.py b/pptx_blueprint/__init__.py index 1d2a74c..f31101b 100644 --- a/pptx_blueprint/__init__.py +++ b/pptx_blueprint/__init__.py @@ -92,7 +92,7 @@ def _get_all_shapes(self) -> Iterable[BaseShape]: def _copy_tags_to_name(self) -> None: all_shapes = self._get_all_shapes() # This regex matches on tags - regex_tag = re.compile(r'\{[\s\w]*\}') + regex_tag = re.compile(r'^\s*(\{\w+\})\s*$') for shape in all_shapes: # We only copy contents we recognize as tags if regex_tag.match(shape.text): From f3a53921f69f559ab4ebde79cf0102e2b1b8be64 Mon Sep 17 00:00:00 2001 From: Stephen Bosch Date: Mon, 14 Oct 2019 21:06:58 +0200 Subject: [PATCH 6/7] Update pptx_blueprint/__init__.py Co-Authored-By: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- pptx_blueprint/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pptx_blueprint/__init__.py b/pptx_blueprint/__init__.py index f31101b..a838342 100644 --- a/pptx_blueprint/__init__.py +++ b/pptx_blueprint/__init__.py @@ -96,7 +96,7 @@ def _copy_tags_to_name(self) -> None: for shape in all_shapes: # We only copy contents we recognize as tags if regex_tag.match(shape.text): - shape.name = shape.text + shape.name = regex_tag.group(1) def save(self, filename: _Pathlike) -> None: """Saves the updated pptx to the specified filepath. From b7ede7aff2f655e677ca74a4a1f29c2a75e0bd7c Mon Sep 17 00:00:00 2001 From: Stephen Bosch Date: Tue, 15 Oct 2019 11:20:48 +0200 Subject: [PATCH 7/7] Use the regex match group for shape.name Use the regex match group for shape.name. This way we also include the curly braces and ignore non-matching text in shape.text. --- pptx_blueprint/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pptx_blueprint/__init__.py b/pptx_blueprint/__init__.py index 268acea..40226f6 100644 --- a/pptx_blueprint/__init__.py +++ b/pptx_blueprint/__init__.py @@ -100,8 +100,9 @@ def _copy_tags_to_name(self) -> None: regex_tag = re.compile(r'^\s*(\{\w+\})\s*$') for shape in all_shapes: # We only copy contents we recognize as tags - if regex_tag.match(shape.text): - shape.name = regex_tag.group(1) + match = regex_tag.match(shape.text) + if match: + shape.name = match.group(1) def save(self, filename: _Pathlike) -> None: """Saves the updated pptx to the specified filepath.