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

python-formate / snippet-fmt / 6956687811

22 Nov 2023 11:31AM UTC coverage: 95.575%. First build
6956687811

push

github

domdfcoding
Bump version v0.1.4 -> v0.1.5

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

216 of 226 relevant lines covered (95.58%)

0.96 hits per line

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

100.0
/snippet_fmt/formatters.py
1
#!/usr/bin/env python3
2
#
3
#  formatters.py
4
"""
1✔
5
Formatters and syntax checkers.
6
"""
7
#
8
#  Copyright © 2021 Dominic Davis-Foster <dominic@davis-foster.co.uk>
9
#
10
#  Permission is hereby granted, free of charge, to any person obtaining a copy
11
#  of this software and associated documentation files (the "Software"), to deal
12
#  in the Software without restriction, including without limitation the rights
13
#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
#  copies of the Software, and to permit persons to whom the Software is
15
#  furnished to do so, subject to the following conditions:
16
#
17
#  The above copyright notice and this permission notice shall be included in all
18
#  copies or substantial portions of the Software.
19
#
20
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23
#  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
24
#  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
25
#  OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
26
#  OR OTHER DEALINGS IN THE SOFTWARE.
27
#
28

29
# stdlib
30
import ast
1✔
31
import json
1✔
32
import os
1✔
33
from configparser import ConfigParser
1✔
34
from io import StringIO
1✔
35
from typing import Any, Optional
1✔
36

37
# 3rd party
38
import dom_toml
1✔
39
import dom_toml.decoder
1✔
40
import formate
1✔
41
from domdf_python_tools.paths import PathPlus
1✔
42

43
__all__ = (
1✔
44
                "Formatter",
45
                "format_toml",
46
                "format_ini",
47
                "format_json",
48
                "format_python",
49
                "noformat",
50
                )
51

52
# 3rd party
53
from typing_extensions import Protocol
1✔
54

55

56
class Formatter(Protocol):
1✔
57
        """
58
        :class:`typing.Protocol` for formatter functions.
59
        """
60

61
        def __call__(self, code: str, **config: Any) -> str: ...  # noqa: D102
1✔
62

63

64
def noformat(code: str, **config) -> str:
1✔
65
        r"""
66
        A no-op formatter.
67

68
        :param code: The code to check and reformat.
69
        :param \*\*config: The language-specific configuration.
70

71
        :returns: The original code unchanged.
72
        """
73

74
        return code
1✔
75

76

77
class StringReformatter(formate.Reformatter):
1✔
78

79
        def __init__(self, code: str, config: formate.FormateConfigDict):
1✔
80
                self.file_to_format = PathPlus(os.devnull)  # in case someone tries to write to the file
1✔
81
                self.filename = "snippet.py"
1✔
82
                self.config = config
1✔
83
                self._unformatted_source = code
1✔
84
                self._reformatted_source: Optional[str] = None
1✔
85

86
        def to_file(self) -> None:  # pragma: no cover
87
                """
88
                Write the reformatted source to the original file.
89
                """
90

91
                raise NotImplementedError(f"Unsupported by {self.__class__!r}")
92

93

94
def format_python(code: str, **config) -> str:
1✔
95
        r"""
96
        Check the syntax of, and reformat, the given Python code.
97

98
        :param code: The code to check and reformat.
99
        :param \*\*config: The language-specific configuration.
100

101
        :returns: The reformatted code.
102
        """
103

104
        if config.get("reformat", False):
1✔
105
                formate_config = formate.config.load_toml(config.get("config-file", "formate.toml"))
1✔
106
                r = StringReformatter(code, formate_config)
1✔
107
                r.run()
1✔
108
                return r.to_string()
1✔
109
        else:
110
                ast.parse(code)
1✔
111
                return code
1✔
112

113

114
def format_toml(code: str, **config) -> str:
1✔
115
        r"""
116
        Check the syntax of, and reformat, the given TOML configuration.
117

118
        :param code: The code to check.
119
        :param \*\*config: The language-specific configuration.
120

121
        :returns: The original code unchanged.
122
        """
123

124
        toml_content = dom_toml.loads(code)
1✔
125

126
        if config.get("reformat", False):
1✔
127
                return dom_toml.dumps(toml_content)
1✔
128
        else:
129
                return code
1✔
130

131

132
def format_ini(code: str, **config) -> str:
1✔
133
        r"""
134
        Check the syntax of, and reformat, the given INI configuration.
135

136
        :param code: The code to check.
137
        :param \*\*config: The language-specific configuration.
138

139
        :returns: The original code unchanged.
140

141
        .. latex:clearpage::
142
        """
143

144
        parser = ConfigParser()
1✔
145
        parser.read_string(code)
1✔
146

147
        if config.get("reformat", False):
1✔
148
                output = StringIO()
1✔
149
                parser.write(output)
1✔
150
                return output.getvalue()
1✔
151
        else:
152
                return code
1✔
153

154

155
def format_json(code: str, **config) -> str:
1✔
156
        r"""
157
        Check the syntax of, and reformat, the given JSON source.
158

159
        :param code: The code to check.
160
        :param \*\*config: The language-specific configuration.
161

162
        :returns: The original code unchanged.
163
        """
164

165
        json_content = json.loads(code)
1✔
166
        config = config.copy()
1✔
167

168
        if config.pop("reformat", False):
1✔
169
                config.setdefault("ensure_ascii", False)
1✔
170
                return json.dumps(json_content, **config)
1✔
171
        else:
172
                return code
1✔
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