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

idlesign / makeapp / 23706637022

29 Mar 2026 10:03AM UTC coverage: 89.106%. Remained the same
23706637022

push

github

idlesign
Release v2.2.0

1 of 1 new or added line in 1 file covered. (100.0%)

4 existing lines in 2 files now uncovered.

957 of 1074 relevant lines covered (89.11%)

3.56 hits per line

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

75.53
/src/makeapp/utils.py
1
import configparser
4✔
2
import fileinput
4✔
3
import logging
4✔
4
import os
4✔
5
import shutil
4✔
6
import sys
4✔
7
import tempfile
4✔
8
from collections.abc import Generator
4✔
9
from configparser import ConfigParser
4✔
10
from contextlib import contextmanager
4✔
11
from pathlib import Path
4✔
12
from subprocess import PIPE, STDOUT, Popen
4✔
13
from textwrap import indent
4✔
14

15
from .exceptions import CommandError
4✔
16

17
LOG = logging.getLogger(__name__)
4✔
18
PYTHON_VERSION = sys.version_info
4✔
19

20

21
def configure_logging(
4✔
22
        level: int | None = None,
23
        logger: logging.Logger | None = None,
24
        format: str = '%(message)s'
25
):
26
    """Switches on logging at a given level. For a given logger or globally.
27

28
    :param level:
29
    :param logger:
30
    :param format:
31

32
    """
33
    logging.basicConfig(format=format, level=level if level else None)
4✔
34
    logger and logger.setLevel(level or logging.INFO)
4✔
35

36

37
def get_user_dir() -> Path:
4✔
38
    """Returns the user's home directory."""
39
    return Path(os.path.expanduser('~'))
4✔
40

41

42
def read_ini(fpath: Path) -> ConfigParser:
4✔
43
    """Read a .ini file.
44

45
    :param fpath:
46
    """
47
    cfg = configparser.ConfigParser()
×
48
    cfg.read(f'{fpath}')
×
49
    return cfg
×
50

51

52
@contextmanager
4✔
53
def temp_dir() -> Generator[str, None, None]:
4✔
54
    """Context manager to temporarily create a directory."""
55

56
    dir_tmp = tempfile.mkdtemp(prefix='makeapp_')
×
57

58
    try:
×
59
        yield dir_tmp
×
60

61
    finally:
62
        shutil.rmtree(dir_tmp, ignore_errors=True)
×
63

64

65
def replace_infile(filepath: str, pairs: dict[str, str]):
4✔
66
    """Replaces some term by another in file contents.
67

68
    :param filepath:
69
    :param pairs: search -> replace.
70

71
    """
72
    with fileinput.input(files=filepath, inplace=True) as f:
×
73

74
        for line in f:
×
75

76
            for search, replace in pairs.items():
×
77
                line = line.replace(search, replace)
×
78

79
            sys.stdout.write(line)
×
80

81

82
def check_command(command: str, *, hint: str):
4✔
83
    """Checks whether a command is available.
84
    If not - raises an exception.
85

86
    :param command:
87
    :param hint:
88

89
    """
90
    try:
4✔
91
        run_command(f'type {command}')
4✔
92

93
    except CommandError as e:
×
94
        raise CommandError(
×
95
            f"Failed to execute '{command}' command. "
96
            f"Check {hint} is installed and available.") from e
97

98

99
def run_command(command: str, *, err_msg: str = '', env: dict | None = None, capture: bool = True) -> list[str]:
4✔
100
    """Runs a command in a shell process.
101

102
    Returns a list of strings gathered from a command.
103

104
    :param command:
105
    :param err_msg: Message to show on error.
106
    :param env: Environment variables to use.
107
    :param capture: Capture stdout and stderr and return as lines.
108

109
    :raises: CommandError
110

111
    """
112
    if env:
4✔
113
        env = {**os.environ, **env}
4✔
114

115
    LOG.debug(f'Run command: {command} ...')
4✔
116
    kwargs = {}
4✔
117

118
    if capture:
4✔
119
        kwargs = {'stdout': PIPE, 'stderr': STDOUT}
4✔
120

121
    prc = Popen(command, shell=True, universal_newlines=True, env=env, **kwargs)
4✔
122
    out, _ = prc.communicate()
4✔
123

124
    if out:
4✔
125
        LOG.debug(indent(out, prefix="    "))
4✔
126
        data = [stripped for item in out.splitlines() if (stripped := item.strip())]
4✔
127

128
    else:
129
        data = []
4✔
130

131
    if prc.returncode:
4✔
UNCOV
132
        raise CommandError(err_msg or f"Command `{command}` failed: %s" % '\n'.join(data))
3✔
133

134
    return data
4✔
135

136

137
class Ruff:
4✔
138
    """Ruff wrapper."""
139

140
    @classmethod
4✔
141
    def _run(cls, cmd: str) -> list[str]:
4✔
142
        return run_command(f'ruff {cmd}', capture=False)
×
143

144
    @classmethod
4✔
145
    def check(cls, *, fix: bool = True) -> list[str]:
4✔
146
        return cls._run(f'check{" --fix" if fix else ""}')
×
147

148

149
class MkDocs:
4✔
150
    """MkDocs wrapper."""
151

152
    @classmethod
4✔
153
    def _run(cls, cmd: str) -> list[str]:
4✔
154
        return run_command(f'mkdocs {cmd}', capture=False)
×
155

156
    @classmethod
4✔
157
    def serve(cls) -> list[str]:
4✔
158
        return cls._run('serve -o')
×
159

160
    @classmethod
4✔
161
    def build(cls) -> list[str]:
4✔
162
        return cls._run('build')
×
163

164

165
class Uv:
4✔
166
    """Uv wrapper."""
167

168
    @classmethod
4✔
169
    def exec(cls, cmd: str, env: dict | None = None) -> list[str]:
4✔
170
        return run_command(f'uv {cmd}', env=env, capture=False)
4✔
171

172
    @classmethod
4✔
173
    def upgrade(cls) -> list[str]:
4✔
174
        return cls.exec('self update')
×
175

176
    @classmethod
4✔
177
    def tool_install(cls, name: str) -> list[str]:
4✔
178
        return cls.exec(f'tool install {name}')
×
179

180
    @classmethod
4✔
181
    def tool_upgrade(cls, name: str) -> list[str]:
4✔
182
        return cls.exec(f'tool upgrade {name} --reinstall')
×
183

184
    @classmethod
4✔
185
    def sync(cls) -> list[str]:
4✔
186
        return cls.exec('sync')
4✔
187

188
    @classmethod
4✔
189
    def install(cls):
4✔
190
        return run_command('curl -LsSf https://astral.sh/uv/install.sh | sh', capture=False)
×
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