Skip to content

Commit

Permalink
Merge pull request #266 from aktech/black-custom-formatting
Browse files Browse the repository at this point in the history
Allow custom formatting options with black
  • Loading branch information
Carreau authored Nov 21, 2023
2 parents 06cfd72 + 1e8dcdc commit a60a494
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 9 deletions.
5 changes: 3 additions & 2 deletions lib/python/pyflyby/_cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,14 @@ def callback(option, opt_str, value, parser):
help=hfmt('''
(Default) Don't align the 'from __future__ import
...' statement.'''))
group.add_option('--width', type='int', default=79, metavar='N',
group.add_option('--width', type='int', default=None, metavar='N',
help=hfmt('''
Maximum line length (default: 79).'''))
group.add_option('--black', action='store_true', default=False,
help=hfmt('''
Use black to format imports. If this option is
used, all other formatting options are ignored.'''))
used, all other formatting options are ignored,
except width'''))
group.add_option('--hanging-indent', type='choice', default='never',
choices=['never','auto','always'],
metavar='never|auto|always',
Expand Down
8 changes: 6 additions & 2 deletions lib/python/pyflyby/_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@


class FormatParams(object):
max_line_length = 79
max_line_length = None
_max_line_lenght_default = 79
wrap_paren = True
indent = 4
hanging_indent = 'never'
Expand Down Expand Up @@ -37,6 +38,9 @@ def __new__(cls, *args, **kwargs):
raise ValueError("bad kwarg %r" % (key,))
return self

def __repr__(self):
return f'<{self.__class__.__name__} {self.__dict__}>'


def fill(tokens, sep=(", ", ""), prefix="", suffix="", newline="\n",
max_line_length=80):
Expand Down Expand Up @@ -125,7 +129,7 @@ def pyfill(prefix, tokens, params=FormatParams()):
:rtype:
``str``
"""
N = params.max_line_length
N = params.max_line_length or params._max_line_lenght_default
if params.wrap_paren:
# Check how we will break up the tokens.
len_full = sum(len(tok) for tok in tokens) + 2 * (len(tokens)-1)
Expand Down
88 changes: 85 additions & 3 deletions lib/python/pyflyby/_importstmt.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,41 @@
from pyflyby._util import (Inf, cached_attribute, cmp,
longest_common_prefix)

from black import (find_pyproject_toml, format_str,
parse_pyproject_toml, TargetVersion,
FileMode as Mode)


def read_black_config():
"""Read the black configuration from ``pyproject.toml``
"""
value = find_pyproject_toml('.')

raw_config = parse_pyproject_toml(value)

config = {}
for key in [
"line_length",
"skip_magic_trailing_comma",
"skip_string_normalization",
]:
if key in raw_config:
config[key] = raw_config[key]
if "target_version" in raw_config:
target_version = raw_config["target_version"]
if isinstance(target_version, str):
config["target_version"] = target_version
elif isinstance(target_version, list):
# Convert TOML list to a Python set
config["target_version"] = set(target_version)
else:
raise ValueError(
f"Invalid config for black = {target_version!r} in {value}"
)
return config


class ImportFormatParams(FormatParams):
align_imports = True
Expand Down Expand Up @@ -486,11 +521,58 @@ def pretty_print(self, params=FormatParams(),
tokens.append(t)
res = s0 + pyfill(s, tokens, params=params)
if params.use_black:
import black
mode = black.FileMode()
return black.format_str(res, mode=mode)
return self.run_black(res, params)
return res

@staticmethod
def run_black(src_contents: str, params) -> str:
"""Run the black formatter for the Python source code given as a string
This is adapted from https://github.com/akaihola/darker
"""
black_config = read_black_config()
mode = dict()
if "line_length" in black_config:
mode["line_length"] = (
params.max_line_length
if params.max_line_length
else black_config["line_length"]
)
if "target_version" in black_config:
if isinstance(black_config["target_version"], set):
target_versions_in = black_config["target_version"]
else:
target_versions_in = {black_config["target_version"]}
all_target_versions = {
tgt_v.name.lower(): tgt_v for tgt_v in TargetVersion
}
bad_target_versions = target_versions_in - set(all_target_versions)
if bad_target_versions:
raise ValueError(
f"Invalid target version(s) {bad_target_versions}"
)
mode["target_versions"] = {
all_target_versions[n] for n in target_versions_in
}
if "skip_magic_trailing_comma" in black_config:
mode["magic_trailing_comma"] = not black_config[
"skip_magic_trailing_comma"
]
if "skip_string_normalization" in black_config:
# The ``black`` command line argument is
# ``--skip-string-normalization``, but the parameter for
# ``black.Mode`` needs to be the opposite boolean of
# ``skip-string-normalization``, hence the inverse boolean
mode["string_normalization"] = not black_config[
"skip_string_normalization"
]

# The custom handling of empty and all-whitespace files below will be unnecessary if
# https://github.com/psf/black/pull/2484 lands in Black.
contents_for_black = src_contents
return format_str(contents_for_black, mode=Mode(**mode))

@property
def _data(self):
return (self.fromname, self.aliases)
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,8 @@ def make_distribution(self):
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
],
install_requires=["six", "toml", "isort", "pathlib ; python_version<'3'"],
python_requires=">3.0, !=3.0.*, !=3.1.*, !=3.2.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, <4",
install_requires=["six", "toml", "isort", "black"],
python_requires=">3.6, <4",
tests_require=['pexpect>=3.3', 'pytest', 'epydoc', 'rlipython', 'requests'],
cmdclass = {
'test' : PyTest,
Expand Down

0 comments on commit a60a494

Please sign in to comment.