GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

qtsass.api.compile()   B
last analyzed

Complexity

Conditions 7

Size

Total Lines 64
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 36
dl 0
loc 64
rs 7.616
c 0
b 0
f 0
cc 7
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
# -*- coding: utf-8 -*-
2
# -----------------------------------------------------------------------------
3
# Copyright (c) 2015 Yann Lanthony
4
# Copyright (c) 2017-2018 Spyder Project Contributors
5
#
6
# Licensed under the terms of the MIT License
7
# (See LICENSE.txt for details)
8
# -----------------------------------------------------------------------------
9
"""qtsass - Compile SCSS files to valid Qt stylesheets."""
10
11
# yapf: disable
12
13
from __future__ import absolute_import, print_function
14
15
# Standard library imports
16
import logging
17
import os
18
import sys
19
20
# Third party imports
21
import sass
22
23
# Local imports
24
from qtsass.conformers import qt_conform, scss_conform
25
from qtsass.functions import qlineargradient, rgba
26
from qtsass.importers import qss_importer
27
28
29
if sys.version_info[0] == 3:
30
    from collections.abc import Mapping, Sequence
31
else:
32
    from collections import Mapping, Sequence
33
34
35
# yapf: enable
36
37
# Constants
38
DEFAULT_CUSTOM_FUNCTIONS = {'qlineargradient': qlineargradient, 'rgba': rgba}
39
DEFAULT_SOURCE_COMMENTS = False
40
41
# Logger setup
42
_log = logging.getLogger(__name__)
43
44
45
def compile(string, **kwargs):
46
    """
47
    Conform and Compile QtSASS source code to CSS.
48
49
    This function conforms QtSASS to valid SCSS before passing it to
50
    sass.compile. Any keyword arguments you provide will be combined with
51
    qtsass's default keyword arguments and passed to sass.compile.
52
53
    .. code-block:: python
54
55
        >>> import qtsass
56
        >>> qtsass.compile("QWidget {background: rgb(0, 0, 0);}")
57
        QWidget {background:black;}
58
59
    :param string: QtSASS source code to conform and compile.
60
    :param kwargs: Keyword arguments to pass to sass.compile
61
    :returns: CSS string
62
    """
63
    kwargs.setdefault('source_comments', DEFAULT_SOURCE_COMMENTS)
64
    kwargs.setdefault('custom_functions', [])
65
    kwargs.setdefault('importers', [])
66
    kwargs.setdefault('include_paths', [])
67
68
    # Add QtSass importers
69
    if isinstance(kwargs['importers'], Sequence):
70
        kwargs['importers'] = (list(kwargs['importers']) +
71
                               [(0, qss_importer(*kwargs['include_paths']))])
72
    else:
73
        raise ValueError('Expected Sequence for importers '
74
                         'got {}'.format(type(kwargs['importers'])))
75
76
    # Add QtSass custom_functions
77
    if isinstance(kwargs['custom_functions'], Sequence):
78
        kwargs['custom_functions'] = dict(
79
            DEFAULT_CUSTOM_FUNCTIONS,
80
            **{fn.__name__: fn
81
               for fn in kwargs['custom_functions']})
82
    elif isinstance(kwargs['custom_functions'], Mapping):
83
        kwargs['custom_functions'].update(DEFAULT_CUSTOM_FUNCTIONS)
84
    else:
85
        raise ValueError('Expected Sequence or Mapping for custom_functions '
86
                         'got {}'.format(type(kwargs['custom_functions'])))
87
88
    # Conform QtSass source code
89
    try:
90
        kwargs['string'] = scss_conform(string)
91
    except Exception:
92
        _log.error('Failed to conform source code')
93
        raise
94
95
    if _log.isEnabledFor(logging.DEBUG):
96
        from pprint import pformat
97
        log_kwargs = dict(kwargs)
98
        log_kwargs['string'] = 'Conformed SCSS<...>'
99
        _log.debug('Calling sass.compile with:')
100
        _log.debug(pformat(log_kwargs))
101
        _log.debug('Conformed scss:\n{}'.format(kwargs['string']))
102
103
    # Compile QtSass source code
104
    try:
105
        return qt_conform(sass.compile(**kwargs))
106
    except sass.CompileError:
107
        _log.error('Failed to compile source code')
108
        raise
109
110
111
def compile_filename(input_file, output_file, **kwargs):
112
    """Compile and save QtSASS file as CSS.
113
114
    .. code-block:: python
115
116
        >>> import qtsass
117
        >>> qtsass.compile_filename("dummy.scss", "dummy.css")
118
119
    :param input_file: Path to QtSass file.
120
    :param output_file: Path to write Qt compliant CSS.
121
    :param kwargs: Keyword arguments to pass to sass.compile
122
    :returns: CSS string
123
    """
124
    input_root = os.path.abspath(os.path.dirname(input_file))
125
    kwargs.setdefault('include_paths', [input_root])
126
127
    with open(input_file, 'r') as f:
128
        string = f.read()
129
130
    _log.info('Compiling {}...'.format(os.path.normpath(input_file)))
131
    css = compile(string, **kwargs)
132
133
    output_root = os.path.abspath(os.path.dirname(output_file))
134
    if not os.path.isdir(output_root):
135
        os.makedirs(output_root)
136
137
    with open(output_file, 'w') as css_file:
138
        css_file.write(css)
139
        _log.info('Created CSS file {}'.format(os.path.normpath(output_file)))
140
141
    return css
142
143
144
def compile_dirname(input_dir, output_dir, **kwargs):
145
    """Compiles QtSASS files in a directory including subdirectories.
146
147
    .. code-block:: python
148
149
        >>> import qtsass
150
        >>> qtsass.compile_dirname("./scss", "./css")
151
152
    :param input_dir: Directory containing QtSass files.
153
    :param output_dir: Directory to write compiled Qt compliant CSS files to.
154
    :param kwargs: Keyword arguments to pass to sass.compile
155
    """
156
    kwargs.setdefault('include_paths', [input_dir])
157
158
    def is_valid(file_name):
159
        return not file_name.startswith('_') and file_name.endswith('.scss')
160
161
    for root, _, files in os.walk(input_dir):
162
        relative_root = os.path.relpath(root, input_dir)
163
        output_root = os.path.join(output_dir, relative_root)
164
        fkwargs = dict(kwargs)
165
        fkwargs['include_paths'] = fkwargs['include_paths'] + [root]
166
167
        for file_name in [f for f in files if is_valid(f)]:
168
            scss_path = os.path.join(root, file_name)
169
            css_file = os.path.splitext(file_name)[0] + '.css'
170
            css_path = os.path.join(output_root, css_file)
171
172
            if not os.path.isdir(output_root):
173
                os.makedirs(output_root)
174
175
            compile_filename(scss_path, css_path, **fkwargs)
176
177
178
def enable_logging(level=None, handler=None):
179
    """Enable logging for qtsass.
180
181
    Sets the qtsass logger's level to:
182
        1. the provided logging level
183
        2. logging.DEBUG if the QTSASS_DEBUG envvar is a True value
184
        3. logging.WARNING
185
186
    .. code-block:: python
187
        >>> import logging
188
        >>> import qtsass
189
        >>> handler = logging.StreamHandler()
190
        >>> formatter = logging.Formatter('%(level)-8s: %(name)s> %(message)s')
191
        >>> handler.setFormatter(formatter)
192
        >>> qtsass.enable_logging(level=logging.DEBUG, handler=handler)
193
194
    :param level: Optional logging level
195
    :param handler: Optional handler to add
196
    """
197
    if level is None:
198
        debug = os.environ.get('QTSASS_DEBUG', False)
199
        if debug in ('1', 'true', 'True', 'TRUE', 'on', 'On', 'ON'):
200
            level = logging.DEBUG
201
        else:
202
            level = logging.WARNING
203
204
    logger = logging.getLogger('qtsass')
205
    logger.setLevel(level)
206
    if handler:
207
        logger.addHandler(handler)
208
    _log.debug('logging level set to {}.'.format(level))
209
210
211
def watch(source, destination, compiler=None, Watcher=None):
212
    """
213
    Watches a source file or directory, compiling QtSass files when modified.
214
215
    The compiler function defaults to compile_filename when source is a file
216
    and compile_dirname when source is a directory.
217
218
    :param source: Path to source QtSass file or directory.
219
    :param destination: Path to output css file or directory.
220
    :param compiler: Compile function (optional)
221
    :param Watcher: Defaults to qtsass.watchers.Watcher (optional)
222
    :returns: qtsass.watchers.Watcher instance
223
    """
224
    if os.path.isfile(source):
225
        watch_dir = os.path.dirname(source)
226
        compiler = compiler or compile_filename
227
    elif os.path.isdir(source):
228
        watch_dir = source
229
        compiler = compiler or compile_dirname
230
    else:
231
        raise ValueError('source arg must be a dirname or filename...')
232
233
    if Watcher is None:
234
        from qtsass.watchers import Watcher
235
236
    watcher = Watcher(watch_dir, compiler, (source, destination))
237
    return watcher
238