Skip to content

Commit

Permalink
Version 0.1.0b2
Browse files Browse the repository at this point in the history
  • Loading branch information
danie1k committed Nov 7, 2020
1 parent 0b5c8f3 commit 3b93fbd
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 85 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/publish-to-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Publish Python Package to PyPi

on:
release:
types: [created]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.6'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
93 changes: 90 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,95 @@
![MIT License](https://img.shields.io/github/license/danie1k/python-black-configparser)
[![Build Status](https://travis-ci.org/danie1k/python-black-configparser.svg?branch=master)](https://travis-ci.org/danie1k/python-black-configparser)
[![Code Coverage](https://codecov.io/gh/danie1k/python-black-configparser/branch/master/graph/badge.svg?token=A496BD37Qj)](https://codecov.io/gh/danie1k/python-black-configparser)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/black-configparser)](https://pypi.org/project/black-configparser/)
[![PyPI](https://img.shields.io/pypi/v/black-configparser)](https://pypi.org/project/black-configparser/)
[![MIT License](https://img.shields.io/github/license/danie1k/python-black-configparser)](https://github.com/danie1k/python-black-configparser/blob/master/LICENSE)

# black-configparser

Seamless proxy CLI for [black](https://pypi.org/project/black/) (The uncompromising code formatter)
with support for `setup.cfg` & `tox.ini` config files.
Seamless proxy CLI for [black](https://pypi.org/project/black/) *("The uncompromising code formatter")*
with support for non-`pyproject.toml` config files.


## Table of Contents

1. [About the Project](#about-the-project)
- [Why it is different?](#why-it-is-different)
1. [Installation](#installation)
1. [Usage](#usage)
- [Example configuration](#)
1. [Known issues](#known-issues)
1. [License](#license)


## About the Project

The `black-configparser` ia yet another tool (next to [brunette](https://pypi.org/project/brunette/),
[white](https://pypi.org/project/white/), and maybe a few more out there),
which tries to fill [the gap of missing `setup.cfg`](https://github.com/psf/black/issues/688)
(or just [any other non-`pyproject.toml`](https://github.com/psf/black/issues/683)) config file.


### Why it is different?

Unlike other tools, tries to stay **dumb simple** and add only minimum needed overhead to `black` usage.

1. It is **seamless** - it works on the same CLI command - `black` - just passing logic through some extra code!
1. There is no complex argument processing, if config file is present, the values set there are passed directly to `black`.
1. Code of this tool is independent from `black` insides and will work properly
as long as `black` won't make any braking changes in its command line options.


## Installation

```
pip install black-configparser
```


## Usage

- Supported configuration files: `setup.cfg`, `tox.ini`.
- Configuration file section: `[black]` or `[tools:black]`.

**Important!** :warning:
> When you `black-configparser` finds black configuration in file, most command line arguments won't be available anymore,
> except: `--check`, `--code`, `--diff`, `--help`, `--verbose` & `--version`.
### Example configuration

```ini
[black]
line-length = 120
target-version =
py27
py33
py34
py35
py36
py37
py38
pyi = True
skip-string-normalization = True
color = True
include = \.pyi?$
exclude = /(\.direnv|\.eggs|\.git|\.hg|\.mypy_cache|\.nox|\.tox|\.venv|\.svn|_build|buck-out|build|dist)/]
force-exclude = lorem ipsum
quiet = True
verbose = True
```

- Almost any option available for black (`black --help`) can be put onto config file.
- Values for multi-value arguments must be one per line (separated by `\n` char).
- Flags *(arguments without values)* must be set in config file as `= True`.


## Known issues

- Undefined behavior, when one of allowed CLI arguments will be also put inside config file.
- After `black-configparser` package is uninstalled, the `black` command does not work anymore
and [black](https://pypi.org/project/black/) package must be reinstalled.


## License

MIT
23 changes: 18 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
#!/usr/bin/env python
from setuptools import setup
import collections
import pathlib

from setuptools import setup

setup(
name="black-configparser",
version="0.0.5",
version="0.1.0b2",
author="Daniel Kuruc",
author_email="[email protected]",
license="MIT",
url="https://github.com/danie1k/black_configparser",
url="https://github.com/danie1k/python-black-configparser",
project_urls=collections.OrderedDict(
(
("Code", "https://github.com/danie1k/python-black-configparser"),
(
"Issue tracker",
"https://github.com/danie1k/python-black-configparser/issues",
),
)
),
description=(
"Seamless Proxy CLI for black (The uncompromising code formatter) "
"with support for setup.cfg & tox.ini config files"
"Seamless Proxy CLI for black (\"The uncompromising code formatter\") "
"with support for non-pyproject.toml config files"
),
long_description=(pathlib.Path(__file__).parent / "README.md").read_text("utf8"),
long_description_content_type="text/markdown",
Expand Down Expand Up @@ -43,4 +53,7 @@
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Quality Assurance",
],
entry_points={
"console_scripts": ["black=black_configparser.black_configparser:main"]
},
)
66 changes: 37 additions & 29 deletions src/black_configparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,12 @@
import click
import sh

__all__ = (
"CONFIG_FILES",
"CONFIG_SECTIONS",
"NO_CONFIG_FLAG",
"PWD",
"ParamValue",
"ParamsType",
"_get_options_from_config_files",
"_get_options_from_stream",
"_make_key",
"_make_value",
"_open_config_files",
"_prepare_argv",
"main",
)

PWD = os.getcwd()

CONFIG_FILES = ("setup.cfg", "tox.ini")
CONFIG_SECTIONS = ("black", "tools:black")
NO_CONFIG_FLAG = "no-config-file"
ALLOWED_ARGUMENTS = ("--check", "--diff", "--verbose")

ParamValue = Optional[Tuple[str, ...]]
ParamsType = Dict[str, ParamValue]
Expand All @@ -45,12 +30,12 @@ def _get_options_from_config_files() -> ParamsType:
options: ParamsType = {}

for file_stream, file_name in _open_config_files():
options.update(_get_options_from_stream(file_stream, file_name))
options.update(_get_options_from_file_stream(file_stream, file_name))

return options


def _get_options_from_stream( # noqa:C901
def _get_options_from_file_stream( # noqa:C901
file_stream: TextIO, file_name: str
) -> ParamsType:
result: ParamsType = {}
Expand All @@ -62,11 +47,16 @@ def _get_options_from_stream( # noqa:C901
if section_name not in config:
continue

items_in_section = dict(config[section_name])

if not items_in_section: # pragma:no cover
continue

click.secho(
f"Using [{section_name}] configuration from {file_name}.", fg="blue"
)

for key, value in dict(config[section_name]).items():
for key, value in items_in_section.items():
try:
value = config.getboolean(section_name, key) # type:ignore
except ValueError:
Expand All @@ -84,6 +74,20 @@ def _get_options_from_stream( # noqa:C901
return result


def _convert_options_to_argv(options: ParamsType) -> Deque[str]:
result: Deque[str] = collections.deque()

for option, values_list in options.items():
if values_list is None:
result.append(option)
continue

for value in values_list:
result += [option, value]

return result


def _make_key(value: str) -> str:
value = value.replace("_", "-").strip(" -")
_prefix = "-" if len(value) == 1 else "--"
Expand All @@ -100,6 +104,13 @@ def _make_value(value: Union[str, bool]) -> ParamValue:
def _prepare_argv(user_given_argv: List[str]) -> Tuple[str, ...]: # noqa:C901
result: Deque[str] = collections.deque()

options_from_config_file = _convert_options_to_argv(
_get_options_from_config_files()
)

if not options_from_config_file:
return tuple(user_given_argv)

if "--help" in user_given_argv or "--version" in user_given_argv:
return tuple(user_given_argv)

Expand All @@ -113,9 +124,11 @@ def _prepare_argv(user_given_argv: List[str]) -> Tuple[str, ...]: # noqa:C901
f"Please define options in config file or use --{NO_CONFIG_FLAG} flag."
)

if "--check" in user_given_argv:
user_given_argv.remove("--check")
result.append("--check")
for argument_name in ALLOWED_ARGUMENTS:
if argument_name not in user_given_argv:
continue
user_given_argv.remove(argument_name)
result.append(argument_name)

if "-c" in user_given_argv or "--code" in user_given_argv:
try:
Expand All @@ -128,13 +141,8 @@ def _prepare_argv(user_given_argv: List[str]) -> Tuple[str, ...]: # noqa:C901
user_given_argv.pop(_code_arg_index),
]

for option, values_list in _get_options_from_config_files().items():
if values_list is None:
result.append(option)
continue

for value in values_list:
result += [option, value]
if isinstance(options_from_config_file, collections.deque):
result += options_from_config_file

for arg in user_given_argv:
_maybe_path = arg if os.path.isabs(arg) else os.path.join(PWD, arg)
Expand Down
6 changes: 3 additions & 3 deletions tests/test_black_configparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ def test_get_options_from_config_files(*_mocks: mock.MagicMock) -> None:
"--file-ipsum": "lorem",
}

def _mocked_get_options_from_stream(
def _mocked_get_options_from_file_stream(
file_stream: IO[str], file_name: str
) -> Dict[str, str]:
return {f"--file-{file_name}": file_stream.read()}

with mock.patch.object(
black_configparser,
"_get_options_from_stream",
side_effect=_mocked_get_options_from_stream,
"_get_options_from_file_stream",
side_effect=_mocked_get_options_from_file_stream,
):
result = black_configparser._get_options_from_config_files()

Expand Down
4 changes: 2 additions & 2 deletions tests/test_get_options_from_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@
"given_config_file, expected_result",
zip(GIVEN_CONFIG_FILES, EXPECTED_CONFIG_OPTIONS),
)
def test_get_options_from_stream(
def test_get_options_from_file_stream(
given_config_file: str, expected_result: Dict[str, Any]
) -> None:
file = io.StringIO(dedent(given_config_file))
result = black_configparser._get_options_from_stream(file, "lorem_ipsum")
result = black_configparser._get_options_from_file_stream(file, "lorem_ipsum")
assert result == expected_result
Loading

0 comments on commit 3b93fbd

Please sign in to comment.