Coveralls logob
Coveralls logo
  • Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sergei-maertens / django-systemjs / 131

29 Aug 2016 - 13:38 coverage: 96.739% (+1.3%) from 95.443%
131

Pull #18

travis-ci

9181eb84f9c35729a3bad740fb7f9d93?size=18&default=identiconweb-flow
Catch error output from jspm api & raise error
Pull Request #18: Feature/more efficient bundling

291 of 297 new or added lines in 9 files covered. (97.98%)

534 of 552 relevant lines covered (96.74%)

11.56 hits per line

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

97.5
/systemjs/management/commands/_mixins.py
1
"""
2
Mixin for various command to retreive locations of systemjs_import calls.
3
"""
4
from __future__ import unicode_literals
12×
5

6
import io
12×
7
import os
12×
8
import re
12×
9
from collections import OrderedDict
12×
10

11
from django.conf import settings
12×
12
from django.core.management.base import CommandError
12×
13
from django.core.management.utils import handle_extensions
12×
14
from django.template import loader, TemplateDoesNotExist
12×
15
from django.template.base import TOKEN_BLOCK
12×
16
from django.template.loaders.app_directories import get_app_template_dirs
12×
17

18
from systemjs.compat import Lexer
12×
19
from systemjs.templatetags.system_tags import SystemImportNode
12×
20

21

22
SYSTEMJS_TAG_RE = re.compile(r"""systemjs_import\s+(['\"])(?P<app>.*)\1""")
12×
23

24
RESOLVE_CONTEXT = {}
12×
25

26

27
class TemplateDiscoveryMixin(object):
12×
28

29
    def add_arguments(self, parser):
12×
30
        tpl_group = parser.add_mutually_exclusive_group()
12×
31
        tpl_group.add_argument(
12×
32
            '--extension', '-e', dest='extensions',
33
            help='The file extension(s) to examine (default: "html"). Separate '
34
                 'multiple extensions with commas, or use -e multiple times.',
35
            action='append')
36
        tpl_group.add_argument(
12×
37
            '--template', '-t', dest='templates',
38
            help='The templates to examine. Separate multiple template names with'
39
                 'commas, or use -t multiple times',
40
            action='append')
41

42
        parser.add_argument(
12×
43
            '--symlinks', '-s', action='store_true', dest='symlinks',
44
            default=False, help='Follows symlinks to directories when examining '
45
                                'source code and templates for SystemJS imports.')
46

47
        super(TemplateDiscoveryMixin, self).add_arguments(parser)
12×
48

49
    def handle(self, **options):
12×
50
        self.symlinks = options.get('symlinks')
12×
51
        extensions = options.get('extensions') or ['html']
12×
52
        self.extensions = handle_extensions(extensions)
12×
53

54
    def discover_templates(self):
12×
55
        template_dirs = list(get_app_template_dirs('templates'))
12×
56
        for config in settings.TEMPLATES:
12×
57
            # only support vanilla Django templates
58
            if config['BACKEND'] != 'django.template.backends.django.DjangoTemplates':
12×
59
                continue
12×
60
            template_dirs += list(config['DIRS'])
12×
61

62
        all_files = []
12×
63
        for template_dir in template_dirs:
12×
64
            for dirpath, dirnames, filenames in os.walk(template_dir, topdown=True, followlinks=self.symlinks):
12×
65
                for filename in filenames:
12×
66
                    filepath = os.path.join(dirpath, filename)
12×
67
                    file_ext = os.path.splitext(filename)[1]
12×
68
                    if file_ext not in self.extensions:
12×
69
                        continue
12×
70
                    template_name = os.path.relpath(filepath, template_dir)
12×
71
                    all_files.append((template_name, filepath))
12×
72

73
        return all_files
12×
74

75
    def find_apps(self, templates=None):
12×
76
        """
77
        Crawls the (specified) template files and extracts the apps.
78

79
        If `templates` is specified, the template loader is used and the template
80
        is tokenized to extract the SystemImportNode. An empty context is used
81
        to resolve the node variables.
82
        """
83

84
        all_apps = OrderedDict()
12×
85

86
        if not templates:
12×
87
            all_files = self.discover_templates()
12×
88
            for tpl_name, fp in all_files:
12×
89
                # this is the most performant - a testcase that used the loader with tpl_name
90
                # was about 8x slower for a project with ~5 apps in different templates :(
91
                with io.open(fp, 'r', encoding=settings.FILE_CHARSET) as template_file:
12×
92
                    src_data = template_file.read()
12×
93

94
                for t in Lexer(src_data).tokenize():
12×
95
                    if t.token_type == TOKEN_BLOCK:
12×
96
                        imatch = SYSTEMJS_TAG_RE.match(t.contents)
12×
97
                        if imatch:
12×
98
                            all_apps.setdefault(tpl_name, [])
12×
99
                            all_apps[tpl_name].append(imatch.group('app'))
12×
100
        else:
101
            for tpl_name in templates:
12×
102
                try:
12×
103
                    template = loader.get_template(tpl_name)
12×
104
                except TemplateDoesNotExist:
12×
105
                    raise CommandError('Template \'%s\' does not exist' % tpl_name)
12×
106
                import_nodes = template.template.nodelist.get_nodes_by_type(SystemImportNode)
12×
107
                for node in import_nodes:
12×
108
                    app = node.path.resolve(RESOLVE_CONTEXT)
12×
109
                    if not app:
12×
NEW
110
                        self.stdout.write(self.style.WARNING(
!
111
                            '{tpl}: Could not resolve path with context {ctx}, skipping.'.format(
112
                                tpl=tpl_name, ctx=RESOLVE_CONTEXT)
113
                        ))
NEW
114
                        continue
!
115
                    all_apps.setdefault(tpl_name, [])
12×
116
                    all_apps[tpl_name].append(app)
12×
117

118
        return all_apps
12×
119

120

121
class BundleOptionsMixin(object):
12×
122

123
    def add_arguments(self, parser):
12×
124
        super(BundleOptionsMixin, self).add_arguments(parser)
12×
125

126
        parser.add_argument(
12×
127
            '--sfx',
128
            action='store_true', dest='sfx',
129
            help="Generate self-executing bundles.")
130

131
        parser.add_argument(
12×
132
            '--node-path', default='./node_modules',
133
            help='Path to the project `node_modules` directory')
134
        parser.add_argument('--minify', action='store_true', help='Let jspm minify the bundle')
12×
135
        parser.add_argument('--minimal', action='store_true', help='Only (re)bundle if changes detected')
12×
136

137
    def get_system_opts(self, options):
12×
138
        system_options = ['minimal', 'minify', 'sfx']
12×
139
        return {opt: options.get(opt) for opt in system_options}
12×
Troubleshooting · Open an Issue · Sales · Support · ENTERPRISE · CAREERS · STATUS
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2023 Coveralls, Inc