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

zopefoundation / z3c.recipe.tag / 13883129984

18 Sep 2024 07:14AM UTC coverage: 42.529% (+1.6%) from 40.909%
13883129984

push

github

web-flow
- Add support for Python 3.12, 3.13.  - Drop support for Python 3.7. (#20)

* Bumped version for feature release.
* Drop support for Python 3.7.
* Add support for Python 3.12.
* Add support for Python 3.13.
* Format code.

6 of 38 branches covered (15.79%)

Branch coverage included in aggregate %.

4 of 14 new or added lines in 1 file covered. (28.57%)

2 existing lines in 1 file now uncovered.

68 of 136 relevant lines covered (50.0%)

0.5 hits per line

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

36.71
/src/z3c/recipe/tag/__init__.py
1
##############################################################################
2
#
3
# Copyright (c) 2007 Zope Foundation and Contributors.
4
# All Rights Reserved.
5
#
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
# FOR A PARTICULAR PURPOSE.
12
#
13
##############################################################################
14
import optparse
1✔
15
import os
1✔
16
import subprocess
1✔
17
import sys
1✔
18

19
import pkg_resources
1✔
20

21
import zc.buildout.easy_install
1✔
22
import zc.recipe.egg
1✔
23

24

25
class TagsMaker:
1✔
26

27
    def __init__(self, buildout, name, options):
1✔
28
        self.buildout = buildout
1✔
29
        self.name = name
1✔
30
        self.options = options
1✔
31
        # We do this early so the "extends" functionality works before we get
32
        # to the other options below.
33
        self._delegated = zc.recipe.egg.Egg(buildout, name, options)
1✔
34
        options['script'] = os.path.join(
1✔
35
            buildout['buildout']['bin-directory'],
36
            options.get('script', self.name),
37
        )
38
        if not options.get('working-directory', ''):
1!
39
            options['location'] = os.path.join(
1✔
40
                buildout['buildout']['parts-directory'], name)
41

42
    def install(self):
1✔
43
        options = self.options
1✔
44
        generated = []
1✔
45
        eggs, ws = self._delegated.working_set(('z3c.recipe.tag', ))
1✔
46

47
        wd = options.get('working-directory', '')
1✔
48
        if not wd:
1!
49
            wd = options['location']
1✔
50
            if os.path.exists(wd):
1!
51
                assert os.path.isdir(wd)
×
52
            else:
53
                os.mkdir(wd)
1✔
54
            generated.append(wd)
1✔
55

56
        initialization = initialization_template % (
1✔
57
            self.buildout['buildout']['directory'])
58

59
        env_section = options.get('environment', '').strip()
1✔
60
        if env_section:
1!
61
            env = self.buildout[env_section]
×
62
            for key, value in env.items():
×
63
                initialization += env_template % (key, value)
×
64

65
        initialization_section = options.get('initialization', '').strip()
1✔
66
        if initialization_section:
1!
67
            initialization += initialization_section
×
68

69
        arguments = options.get('defaults', '')
1✔
70
        if arguments:
1!
71
            arguments = arguments + ' + sys.argv[1:]'
×
72

73
        generated.extend(
1✔
74
            zc.buildout.easy_install.scripts(
75
                [(options['script'], 'z3c.recipe.tag', 'build_tags')],
76
                ws,
77
                options['executable'],
78
                self.buildout['buildout']['bin-directory'],
79
                extra_paths=self._delegated.extra_paths,
80
                initialization=initialization,
81
            ))
82

83
        return generated
1✔
84

85
    update = install
1✔
86

87

88
initialization_template = """import os
1✔
89
sys.argv[0] = os.path.abspath(sys.argv[0])
90
os.chdir(%r)
91
"""
92

93
env_template = """os.environ['%s'] = %r
1✔
94
"""
95

96

97
def getpath(candidates):
1✔
98
    paths = os.environ['PATH'].split(os.pathsep)
×
99
    for c in candidates:
×
100
        for p in paths:
×
101
            full = os.path.join(p, c)
×
102
            if os.path.exists(full):
×
103
                return full
×
NEW
104
    raise RuntimeError('Can\'t find executable for any of: %s' % candidates)
×
105

106

107
class Builder:
1✔
108

109
    def get_relpaths(self, paths):
1✔
110
        working_dir = os.getcwd()
×
111
        return [os.path.relpath(path, working_dir) for path in paths]
×
112

113
    def __call__(self, targets=None, languages=None, tag_relative=False):
1✔
114
        if not targets:
×
115
            targets = ('idutils', 'ctags_vi', 'ctags_emacs')  # legacy behavior
×
116
        self.languages = languages or ''
×
117
        self.tag_relative = tag_relative
×
NEW
118
        paths = [path for path in sys.path if os.path.isdir(path)]
×
UNCOV
119
        if self.tag_relative:
×
120
            # ctags will ignore --tag-relative=yes for absolute paths so we
121
            # must pass relative paths to it.
122
            paths = self.get_relpaths(paths)
×
123
        self.paths = paths
×
124
        results = {}
×
125
        for target in targets:
×
126
            tool_candidates, arguments, source, destination = getattr(
×
127
                self, f'_build_{target}')()
128
            arguments[0:0] = [getpath(tool_candidates)]
×
129
            res = subprocess.call(arguments)
×
130
            if res == 0:
×
131
                res = subprocess.call(['mv', source, destination])
×
132
            results[target] = res
×
133
        return results
×
134

135
    def _build_idutils(self):
1✔
NEW
136
        return [['mkid'],
×
137
                [
138
                    '-m',
139
                    pkg_resources.resource_filename(
140
                        "z3c.recipe.tag", "id-lang.map.txt"), '-o', 'ID.new'
141
        ] + self.paths, 'ID.new', 'ID']
142

143
    def _build_ctags_vi(self):
1✔
144
        res = [['ctags-exuberant', 'ctags'],
×
145
               ['-R', '--python-kinds=-i', '-f', 'tags.new'] + self.paths,
146
               'tags.new', 'tags']
147
        if self.languages:
×
148
            res[1][0:0] = ['--languages=%s' % self.languages]
×
149
        if self.tag_relative:
×
150
            res[1][0:0] = ['--tag-relative=yes']
×
151
        return res
×
152

153
    def _build_ctags_emacs(self):
1✔
154
        res = self._build_ctags_vi()
×
155
        res[1][0:0] = ['-e']
×
156
        res[3] = 'TAGS'
×
157
        return res
×
158

159
    def _build_ctags_bbedit(self):
1✔
160
        res = self._build_ctags_vi()
×
161
        try:
×
162
            res[1].remove('--tag-relative=yes')
×
163
        except ValueError:
×
164
            pass
×
165
        res[1][0:0] = [
×
166
            '--excmd=number', '--tag-relative=no', '--fields=+a+m+n+S'
167
        ]
UNCOV
168
        return res
×
169

170

171
def append_const(option, opt_str, value, parser, const):
1✔
172
    # 'append_const' action added in Py 2.5, and we're in 2.4 :-(
173
    if getattr(parser.values, 'targets', None) is None:
×
174
        parser.values.targets = []
×
175
    parser.values.targets.append(const)
×
176

177

178
def build_tags(args=None):
1✔
179
    parser = optparse.OptionParser()
×
NEW
180
    parser.add_option('-l',
×
181
                      '--languages',
182
                      dest='languages',
183
                      default='-JavaScript',
184
                      help='ctags comma-separated list of languages. '
185
                      'defaults to ``-JavaScript``')
NEW
186
    parser.add_option('-e',
×
187
                      '--ctags-emacs',
188
                      action='callback',
189
                      callback=append_const,
190
                      callback_args=('ctags_emacs', ),
191
                      help='flag to build emacs ctags ``TAGS`` file')
NEW
192
    parser.add_option('-v',
×
193
                      '--ctags-vi',
194
                      action='callback',
195
                      callback=append_const,
196
                      callback_args=('ctags_vi', ),
197
                      help='flag to build vi ctags ``tags`` file')
NEW
198
    parser.add_option('-b',
×
199
                      '--ctags-bbedit',
200
                      action='callback',
201
                      callback=append_const,
202
                      callback_args=('ctags_bbedit', ),
203
                      help='flag to build bbedit ctags ``tags`` file')
NEW
204
    parser.add_option('-i',
×
205
                      '--idutils',
206
                      action='callback',
207
                      callback=append_const,
208
                      callback_args=('idutils', ),
209
                      help='flag to build idutils ``ID`` file')
NEW
210
    parser.add_option('-r',
×
211
                      '--tag-relative',
212
                      action='store_true',
213
                      dest='tag_relative',
214
                      default=False,
215
                      help=('generate tags with paths relative to'
216
                            ' tags file instead of absolute paths'
217
                            ' (works with vim tags only)'))
218
    options, args = parser.parse_args(args)
×
219
    if args:
×
220
        parser.error('no arguments accepted')
×
221
    targets = getattr(options, 'targets', None)
×
222
    if (targets and 'ctags_bbedit' in targets and 'ctags_vi' in targets):
×
223
        parser.error('cannot build both vi and bbedit ctags files (same name)')
×
224
    builder = Builder()
×
NEW
225
    builder(targets,
×
226
            languages=options.languages,
227
            tag_relative=options.tag_relative)
228

229

230
try:
1✔
231
    import paver.easy
1✔
232
except ModuleNotFoundError:
1✔
233
    HAS_PAVER = False
1✔
234
else:  # pragma: nocover
235
    HAS_PAVER = True
236

237
if HAS_PAVER:  # pragma: nocover
238

239
    @paver.easy.task
240
    @paver.easy.consume_args
241
    def tags(args):
242
        """Build tags database file for emacs, vim, or bbedit"""
243
        build_tags(args)
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

© 2025 Coveralls, Inc