• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

collective / collective.documentgenerator / 9284190221

29 May 2024 10:06AM UTC coverage: 91.912% (+0.5%) from 91.42%
9284190221

Pull #60

github

duchenean
fix broken tests en P4
Pull Request #60: Plone 6 compatibility

70 of 91 new or added lines in 15 files covered. (76.92%)

1 existing line in 1 file now uncovered.

2182 of 2374 relevant lines covered (91.91%)

0.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.0
/src/collective/documentgenerator/search_replace/pod_template.py
1
from collective.documentgenerator.browser.generation_view import HAS_FINGERPOINTING
1✔
2
from collective.documentgenerator.utils import get_site_root_relative_path
1✔
3
from collective.documentgenerator.utils import temporary_file_name
1✔
4
from plone.namedfile import NamedBlobFile
1✔
5
from Products.CMFPlone.utils import safe_unicode
1✔
6

7
import collections
1✔
8
import mimetypes
1✔
9
import os
1✔
10
import shutil
1✔
11
import six
1✔
12

13

14
if six.PY2:
1✔
NEW
15
    from appy.bin.odfgrep import Grep
×
16
else:
17
    from appy.bin.ogrep import Grep
1✔
18

19
SearchReplaceResult = collections.namedtuple(
1✔
20
    "SearchReplaceResult",
21
    ["pod_expr", "match_start", "match_end", "match", "node_type", "new_pod_expr"],
22
)
23

24

25
class SearchAndReplacePODTemplates:
1✔
26
    """
27
    Search and replace POD expression among PODTemplates.
28
    Use it like this:
29
        with SearchAndReplacePODTemplates(podtemplate_obj) as search_replace:
30
            search_results = search_replace.search('WhatISearch')
31
            replace_results = search_replace.replace('^WillBeReplaced$', 'ByThis', is_regex=True)
32
    """
33

34
    def __init__(self, podtemplates):
1✔
35
        """
36
        :param podtemplates: List of PODTemplate objects
37
        """
38
        self.podtemplates = podtemplates
1✔
39
        self.templates_by_filename = {}
1✔
40
        self.tmp_dir = temporary_file_name(suffix='search_replace')
1✔
41
        self.changed_files = set()
1✔
42

43
        # compute the (future) file system path of the plone pod templates
44
        for podtemplate in podtemplates:
1✔
45
            if not podtemplate.odt_file:
1✔
46
                continue  # ignore templates referring another pod template.
×
47
            file_extension = podtemplate.odt_file.filename.split(".")[-1].lower()
1✔
48
            template_path = get_site_root_relative_path(podtemplate)
1✔
49
            fs_filename = "{}/{}.{}".format(
1✔
50
                self.tmp_dir, template_path.replace("/", "_"), file_extension
51
            )
52
            self.templates_by_filename[fs_filename] = {"obj": podtemplate, "path": template_path}
1✔
53

54
    def __enter__(self):
1✔
55
        """
56
        copy the plone pod template content on the file system
57
        """
58
        os.mkdir(self.tmp_dir)
1✔
59
        for filename in self.templates_by_filename.keys():
1✔
60
            # clean old files
61
            if os.path.isfile(filename):
1✔
62
                os.remove(filename)
×
63
            # copy the pod templates on the file system.
64
            if six.PY2:
1✔
NEW
65
                with open(filename, "w") as template_file:
×
NEW
66
                    plone_template = self.templates_by_filename[filename]["obj"]
×
NEW
67
                    template_file.write(plone_template.odt_file.data)
×
68
            else:
69
                with open(filename, "wb") as template_file:
1✔
70
                    plone_template = self.templates_by_filename[filename]["obj"]
1✔
71
                    template_file.write(plone_template.odt_file.data)
1✔
72
        return self
1✔
73

74
    def __exit__(self, exc_type, exc_value, traceback):
1✔
75
        # push the result back into the site pod templates
76
        for filename in self.changed_files:
1✔
77
            with open(filename, "rb") as replaced_file:
1✔
78
                podtemplate = self.templates_by_filename[filename]["obj"]
1✔
79
                result = NamedBlobFile(
1✔
80
                    data=replaced_file.read(),
81
                    contentType=podtemplate.odt_file.contentType
82
                    or mimetypes.guess_type(filename)[0],
83
                    filename=podtemplate.odt_file.filename,
84
                )
85
                podtemplate.odt_file = result
1✔
86
        # delete tmp directory
87
        shutil.rmtree(self.tmp_dir)
1✔
88

89
    def search(self, find_expr, is_regex=False):
1✔
90
        """
91
        Search find_expr in self.podtemplates
92
        :param find_expr: A regex str or simple string
93
        :param is_regex: use is_regex=False if find_expr is not a regex
94
        :return: a dict with podtemplate uid as key and list of SearchReplaceResult as value
95
        """
96

97
        if six.PY2:
1✔
NEW
98
            grepper = Grep(
×
99
                find_expr,
100
                self.tmp_dir,
101
                repl=None,
102
                asString=not is_regex,
103
                inContent=False,
104
                dryRun=False,
105
                verbose=0,
106
            )
107
        else:
108
            grepper = Grep(
1✔
109
                keyword=find_expr,
110
                repl=None,
111
                path=self.tmp_dir,
112
                asString=not is_regex,
113
                inContent=False,
114
                dryRun=False,
115
                verbose=0,
116
                vverbose=0,
117
                nice=0
118
            )
119
        grepper.run()
1✔
120
        results = self._prepare_results_output(grepper.matches, is_replacing=False)
1✔
121
        return results
1✔
122

123
    def replace(self, find_expr, replace_expr, is_regex=False, dry_run=False):
1✔
124
        """
125
        Replace find_expr match with replace_expr in self.podtemplates
126
        :param find_expr: A regex str or simple str
127
        :param replace_expr: A str that will replace find_expr match
128
        :param is_regex: Use is_regex=False if find_expr is not a regex
129
        :param dry_run: Perform a dry run and not the actual replacement(s).
130
        This will not modify the template(s) and can be used safely.
131
        :return: a dict with podtemplate uid as key and list of SearchReplaceResult as value
132
        """
133
        if six.PY2:
1✔
NEW
134
            grepper = Grep(
×
135
                find_expr,
136
                self.tmp_dir,
137
                repl=replace_expr,
138
                asString=not is_regex,
139
                inContent=False,
140
                dryRun=dry_run,
141
                verbose=0,
142
            )
143
        else:
144
            grepper = Grep(
1✔
145
                keyword=find_expr,
146
                path=self.tmp_dir,
147
                repl=replace_expr,
148
                asString=not is_regex,
149
                inContent=False,
150
                dryRun=dry_run,
151
                verbose=0,
152
                vverbose=0,
153
                nice=0
154
            )
155
        grepper.run()
1✔
156
        results = self._prepare_results_output(grepper.matches, is_replacing=False)
1✔
157

158
        for filename in grepper.matches.keys():
1✔
159
            self.changed_files.add(filename)
1✔
160

161
        return results
1✔
162

163
    def _prepare_results_output(self, matches, replace_expr="", is_replacing=True):
1✔
164
        """ Prepare results output so we have a nice feedback when searching and replacing """
165
        results = {}
1✔
166
        for file_path, file_results in matches.items():
1✔
167
            template = self.templates_by_filename[file_path]["obj"]
1✔
168
            template_uid = template.UID()
1✔
169
            results[template_uid] = file_results
1✔
170
        return results
1✔
171

172
    @staticmethod
1✔
173
    def _log_replace(template, match, replaced_by, old_pod_expr, new_pod_expr):
1✔
174
        """ Log replacements if fingerpointing installed """
175
        if HAS_FINGERPOINTING:
×
176
            from collective.fingerpointing.config import AUDIT_MESSAGE
×
177
            from collective.fingerpointing.logger import log_info
×
178
            from collective.fingerpointing.utils import get_request_information
×
179

180
            # add logging message to fingerpointing log
181
            user, ip = get_request_information()
×
182
            action = "replace_in_template"
×
183
            extras = u"podtemplate={0} match={1} replaced_by={2} old_pod_expr={3} new_pod_expr={4}".format(
×
184
                "/".join(template.getPhysicalPath()),
185
                match,
186
                replaced_by,
187
                old_pod_expr,
188
                new_pod_expr,
189
            )
NEW
190
            log_info(safe_unicode(AUDIT_MESSAGE).format(user, ip, action, extras))
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc