flynt


Nameflynt JSON
Version 1.0.1 PyPI version JSON
download
home_page
SummaryCLI tool to convert a python project's %-formatted strings to f-strings.
upload_time2023-07-28 09:58:57
maintainer
docs_urlNone
authorIlya Kamenshchikov
requires_python>=3.7
license
keywords strings utility
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            # flynt - string formatting converter

<p align="center">
<a href="https://github.com/ikamensh/flynt/actions"><img alt="Actions Status" src="https://github.com/ikamensh/flynt/workflows/Test/badge.svg"></a>
<a href="https://github.com/ikamensh/flynt/blob/main/LICENSE"><img alt="License: MIT" src="https://black.readthedocs.io/en/stable/_static/license.svg"></a>
<a href="https://pypi.org/project/flynt/"><img alt="PyPI" src="https://img.shields.io/pypi/v/flynt"></a>
<a href="https://pepy.tech/project/flynt"><img alt="Downloads" src="https://pepy.tech/badge/flynt"></a>
<a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
</p>

`flynt` is a command line tool to automatically convert a project's Python code from old "%-formatted" and .format(...) strings into Python 3.6+'s "f-strings".

F-Strings:

> Not only are they more readable, more concise, and less prone to error than other ways of formatting, but they are also faster!

### Installation

`pip install flynt`. It requires Python version 3.7+.

### Usage

*Flynt will modify the files it runs on. Add your project to version control system before using flynt.*

To run: `flynt {source_file_or_directory}`

* Given a single file, it will 'f-stringify' it: replace all applicable string formatting in this file (file will be modified).
* Given a folder, it will search the folder recursively and f-stringify all the .py files it finds. It skips some hard-coded folder names: `blacklist = {'.tox', 'venv', 'site-packages', '.eggs'}`.

It turns the code it runs on into Python 3.6+, since 3.6 is when "f-strings" were introduced.

### Command line options

From the output of `flynt -h`:

<!-- begin-options -->
```
usage: flynt [-h] [-v | -q] [--no-multiline | -ll LINE_LENGTH]
             [-d | --stdout] [-s] [--no-tp] [--no-tf] [-tc] [-tj]
             [-f] [-a] [-e EXCLUDE [EXCLUDE ...]] [--version]
             [src ...]

flynt v.0.78

positional arguments:
  src                   source file(s) or directory (or a single `-`
                        to read stdin and output to stdout)

optional arguments:
  -h, --help            show this help message and exit
  -v, --verbose         run with verbose output
  -q, --quiet           run without outputting statistics to stdout
  --no-multiline        convert only single line expressions
  -ll LINE_LENGTH, --line-length LINE_LENGTH
                        for expressions spanning multiple lines,
                        convert only if the resulting single line
                        will fit into the line length limit. Default
                        value is 88 characters.
  -d, --dry-run         Do not change the files in-place and print
                        the diff instead. Note that this must be
                        used in conjunction with '--fail-on-change'
                        when used for linting purposes.
  --stdout              Do not change the files in-place and print
                        the result instead. This argument implies
                        --quiet, i.e. no statistics are printed to
                        stdout, only the resulting code. It is
                        incompatible with --dry-run and --verbose.
  -s, --string          Interpret the input as a Python code snippet
                        and print the converted version. The snippet
                        must use single quotes or escaped double
                        quotes.
  --no-tp, --no-transform-percent
                        Don't transform % formatting to f-strings
                        (default: do so)
  --no-tf, --no-transform-format
                        Don't transform .format formatting to
                        f-strings (default: do so)
  -tc, --transform-concats
                        Replace string concatenations (defined as +
                        operations involving string literals) with
                        f-strings. Available only if flynt is
                        installed with 3.8+ interpreter.
  -tj, --transform-joins
                        Replace static joins (where the joiner is a
                        string literal and the joinee is a static-
                        length list) with f-strings. Available only
                        if flynt is installed with 3.8+ interpreter.
  -f, --fail-on-change  Fail when changing files (for linting
                        purposes)
  -a, --aggressive      Include conversions with potentially changed
                        behavior.
  -e EXCLUDE [EXCLUDE ...], --exclude EXCLUDE [EXCLUDE ...]
                        ignore files with given strings in it's
                        absolute path.
  --version             Print the current version number and exit.

```

### Sample output of a successful run:
```
38f9d3a65222:~ ikkamens$ git clone https://github.com/pallets/flask.git
Cloning into 'flask'...
...
Resolving deltas: 100% (12203/12203), done.

38f9d3a65222:open_source ikkamens$ flynt flask
Running flynt v.0.40

Flynt run has finished. Stats:

Execution time:                            0.789s
Files modified:                            21
Character count reduction:                 299 (0.06%)

Per expression type:
Old style (`%`) expressions attempted:     40/42 (95.2%)
`.format(...)` calls attempted:            26/33 (78.8%)
F-string expressions created:              48
Out of all attempted transforms, 7 resulted in errors.
To find out specific error messages, use --verbose flag.

_-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_.
Please run your tests before committing. Did flynt get a perfect conversion? give it a star at:
~ https://github.com/ikamensh/flynt ~
Thank you for using flynt. Upgrade more projects and recommend it to your colleagues!

38f9d3a65222:~ ikkamens$
```

### Pre-commit hook

To make sure all formatted strings are always converted to f-strings, you can
add flynt to your [pre-commit](https://www.pre-commit.com) hooks.

Add a new section to `.pre-commit-config.yaml`:
```
-   repo: https://github.com/ikamensh/flynt/
    rev: ''
    hooks:
    -   id: flynt
```

This will run flynt on all modified files before committing.

You can skip conversion of certain lines by adding `# noqa [: anything else] flynt [anything else]`


### Configuration files

Since v0.71 flynt can be configured using `pyproject.toml` file on a per-project basis. 
Use same arguments as in CLI, and add them to `[tool.flynt]` section. CLI arguments takes precedence over the config file.
It can also be configured globally with a toml file located in `~/.config/flynt.toml` on Unix / `~/.flynt.toml` on Windows.

### About

Read up on f-strings here:
- https://realpython.com/python-f-strings/
- https://www.python.org/dev/peps/pep-0498/

After obsessively refactoring a project at work, and not even covering 50% of f-string candidates, I realized there was some place for automation. Also it was very interesting to work with ast module.

### Dangers of conversion
It is not guaranteed that formatted strings will be exactly the same as before conversion.

`'%s' % var` is converted to `f'{var}'`. There is a case when this will behave different from the original -  if var is a tuple of one element. In this case, %s displays the element, and f-string displays the tuple. Example:

```
foo = (1,)
print('%s' % foo) # prints '1'
print(f'{foo}')   # prints '(1,)'
```

Furthermore, some arguments cause formatting of strings to throw exceptions. One example where f-strings are inconsistent with previous formatting is %d vs {:d} - new format no longer accepts floats. While most cases are covered by taking the formatting specifiers to the f-strings format, the precise exception behaviour might differ as well. Make sure you have sufficient test coverage.

### Other Credits / Dependencies / Links

- [astor](https://github.com/berkerpeksag/astor) is used to turn the transformed AST back into code.
- Thanks to folks from [pyddf](https://www.pyddf.de/) for their support, advice and participation during spring hackathon 2019, in particular Holger Hass, Farid Muradov, Charlie Clark.
- Logic finding the pyproject.toml and parsing it was partially copied from [black](https://github.com/psf/black) 

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "flynt",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "strings,utility",
    "author": "Ilya Kamenshchikov",
    "author_email": "",
    "download_url": "https://files.pythonhosted.org/packages/2a/6d/7ff4354c9b7cc3f4fc96758350d8dedf87fe7f036bd49d394f96327faca4/flynt-1.0.1.tar.gz",
    "platform": null,
    "description": "# flynt - string formatting converter\n\n<p align=\"center\">\n<a href=\"https://github.com/ikamensh/flynt/actions\"><img alt=\"Actions Status\" src=\"https://github.com/ikamensh/flynt/workflows/Test/badge.svg\"></a>\n<a href=\"https://github.com/ikamensh/flynt/blob/main/LICENSE\"><img alt=\"License: MIT\" src=\"https://black.readthedocs.io/en/stable/_static/license.svg\"></a>\n<a href=\"https://pypi.org/project/flynt/\"><img alt=\"PyPI\" src=\"https://img.shields.io/pypi/v/flynt\"></a>\n<a href=\"https://pepy.tech/project/flynt\"><img alt=\"Downloads\" src=\"https://pepy.tech/badge/flynt\"></a>\n<a href=\"https://github.com/psf/black\"><img alt=\"Code style: black\" src=\"https://img.shields.io/badge/code%20style-black-000000.svg\"></a>\n</p>\n\n`flynt` is a command line tool to automatically convert a project's Python code from old \"%-formatted\" and .format(...) strings into Python 3.6+'s \"f-strings\".\n\nF-Strings:\n\n> Not only are they more readable, more concise, and less prone to error than other ways of formatting, but they are also faster!\n\n### Installation\n\n`pip install flynt`. It requires Python version 3.7+.\n\n### Usage\n\n*Flynt will modify the files it runs on. Add your project to version control system before using flynt.*\n\nTo run: `flynt {source_file_or_directory}`\n\n* Given a single file, it will 'f-stringify' it: replace all applicable string formatting in this file (file will be modified).\n* Given a folder, it will search the folder recursively and f-stringify all the .py files it finds. It skips some hard-coded folder names: `blacklist = {'.tox', 'venv', 'site-packages', '.eggs'}`.\n\nIt turns the code it runs on into Python 3.6+, since 3.6 is when \"f-strings\" were introduced.\n\n### Command line options\n\nFrom the output of `flynt -h`:\n\n<!-- begin-options -->\n```\nusage: flynt [-h] [-v | -q] [--no-multiline | -ll LINE_LENGTH]\n             [-d | --stdout] [-s] [--no-tp] [--no-tf] [-tc] [-tj]\n             [-f] [-a] [-e EXCLUDE [EXCLUDE ...]] [--version]\n             [src ...]\n\nflynt v.0.78\n\npositional arguments:\n  src                   source file(s) or directory (or a single `-`\n                        to read stdin and output to stdout)\n\noptional arguments:\n  -h, --help            show this help message and exit\n  -v, --verbose         run with verbose output\n  -q, --quiet           run without outputting statistics to stdout\n  --no-multiline        convert only single line expressions\n  -ll LINE_LENGTH, --line-length LINE_LENGTH\n                        for expressions spanning multiple lines,\n                        convert only if the resulting single line\n                        will fit into the line length limit. Default\n                        value is 88 characters.\n  -d, --dry-run         Do not change the files in-place and print\n                        the diff instead. Note that this must be\n                        used in conjunction with '--fail-on-change'\n                        when used for linting purposes.\n  --stdout              Do not change the files in-place and print\n                        the result instead. This argument implies\n                        --quiet, i.e. no statistics are printed to\n                        stdout, only the resulting code. It is\n                        incompatible with --dry-run and --verbose.\n  -s, --string          Interpret the input as a Python code snippet\n                        and print the converted version. The snippet\n                        must use single quotes or escaped double\n                        quotes.\n  --no-tp, --no-transform-percent\n                        Don't transform % formatting to f-strings\n                        (default: do so)\n  --no-tf, --no-transform-format\n                        Don't transform .format formatting to\n                        f-strings (default: do so)\n  -tc, --transform-concats\n                        Replace string concatenations (defined as +\n                        operations involving string literals) with\n                        f-strings. Available only if flynt is\n                        installed with 3.8+ interpreter.\n  -tj, --transform-joins\n                        Replace static joins (where the joiner is a\n                        string literal and the joinee is a static-\n                        length list) with f-strings. Available only\n                        if flynt is installed with 3.8+ interpreter.\n  -f, --fail-on-change  Fail when changing files (for linting\n                        purposes)\n  -a, --aggressive      Include conversions with potentially changed\n                        behavior.\n  -e EXCLUDE [EXCLUDE ...], --exclude EXCLUDE [EXCLUDE ...]\n                        ignore files with given strings in it's\n                        absolute path.\n  --version             Print the current version number and exit.\n\n```\n\n### Sample output of a successful run:\n```\n38f9d3a65222:~ ikkamens$ git clone https://github.com/pallets/flask.git\nCloning into 'flask'...\n...\nResolving deltas: 100% (12203/12203), done.\n\n38f9d3a65222:open_source ikkamens$ flynt flask\nRunning flynt v.0.40\n\nFlynt run has finished. Stats:\n\nExecution time:                            0.789s\nFiles modified:                            21\nCharacter count reduction:                 299 (0.06%)\n\nPer expression type:\nOld style (`%`) expressions attempted:     40/42 (95.2%)\n`.format(...)` calls attempted:            26/33 (78.8%)\nF-string expressions created:              48\nOut of all attempted transforms, 7 resulted in errors.\nTo find out specific error messages, use --verbose flag.\n\n_-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_.\nPlease run your tests before committing. Did flynt get a perfect conversion? give it a star at:\n~ https://github.com/ikamensh/flynt ~\nThank you for using flynt. Upgrade more projects and recommend it to your colleagues!\n\n38f9d3a65222:~ ikkamens$\n```\n\n### Pre-commit hook\n\nTo make sure all formatted strings are always converted to f-strings, you can\nadd flynt to your [pre-commit](https://www.pre-commit.com) hooks.\n\nAdd a new section to `.pre-commit-config.yaml`:\n```\n-   repo: https://github.com/ikamensh/flynt/\n    rev: ''\n    hooks:\n    -   id: flynt\n```\n\nThis will run flynt on all modified files before committing.\n\nYou can skip conversion of certain lines by adding `# noqa [: anything else] flynt [anything else]`\n\n\n### Configuration files\n\nSince v0.71 flynt can be configured using `pyproject.toml` file on a per-project basis. \nUse same arguments as in CLI, and add them to `[tool.flynt]` section. CLI arguments takes precedence over the config file.\nIt can also be configured globally with a toml file located in `~/.config/flynt.toml` on Unix / `~/.flynt.toml` on Windows.\n\n### About\n\nRead up on f-strings here:\n- https://realpython.com/python-f-strings/\n- https://www.python.org/dev/peps/pep-0498/\n\nAfter obsessively refactoring a project at work, and not even covering 50% of f-string candidates, I realized there was some place for automation. Also it was very interesting to work with ast module.\n\n### Dangers of conversion\nIt is not guaranteed that formatted strings will be exactly the same as before conversion.\n\n`'%s' % var` is converted to `f'{var}'`. There is a case when this will behave different from the original -  if var is a tuple of one element. In this case, %s displays the element, and f-string displays the tuple. Example:\n\n```\nfoo = (1,)\nprint('%s' % foo) # prints '1'\nprint(f'{foo}')   # prints '(1,)'\n```\n\nFurthermore, some arguments cause formatting of strings to throw exceptions. One example where f-strings are inconsistent with previous formatting is %d vs {:d} - new format no longer accepts floats. While most cases are covered by taking the formatting specifiers to the f-strings format, the precise exception behaviour might differ as well. Make sure you have sufficient test coverage.\n\n### Other Credits / Dependencies / Links\n\n- [astor](https://github.com/berkerpeksag/astor) is used to turn the transformed AST back into code.\n- Thanks to folks from [pyddf](https://www.pyddf.de/) for their support, advice and participation during spring hackathon 2019, in particular Holger Hass, Farid Muradov, Charlie Clark.\n- Logic finding the pyproject.toml and parsing it was partially copied from [black](https://github.com/psf/black) \n",
    "bugtrack_url": null,
    "license": "",
    "summary": "CLI tool to convert a python project's %-formatted strings to f-strings.",
    "version": "1.0.1",
    "project_urls": {
        "Homepage": "https://github.com/ikamensh/flynt"
    },
    "split_keywords": [
        "strings",
        "utility"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ab4f493b893a60860cfd0b21104098ac97c7e9cdc784a3d8191b690f84a20b3b",
                "md5": "4eacadc7b4bff14123ad00a416f807bd",
                "sha256": "65d1c546434827275123222a98408e9561bcd67db832dd58f530ff17b8329ec1"
            },
            "downloads": -1,
            "filename": "flynt-1.0.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "4eacadc7b4bff14123ad00a416f807bd",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 33305,
            "upload_time": "2023-07-28T09:58:55",
            "upload_time_iso_8601": "2023-07-28T09:58:55.087057Z",
            "url": "https://files.pythonhosted.org/packages/ab/4f/493b893a60860cfd0b21104098ac97c7e9cdc784a3d8191b690f84a20b3b/flynt-1.0.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2a6d7ff4354c9b7cc3f4fc96758350d8dedf87fe7f036bd49d394f96327faca4",
                "md5": "f234c3600d84b9a8016c36ffb21fb3e5",
                "sha256": "988aac00672a5469726cc0a17cef7d1178c284a9fe8563458db2475d0aaed965"
            },
            "downloads": -1,
            "filename": "flynt-1.0.1.tar.gz",
            "has_sig": false,
            "md5_digest": "f234c3600d84b9a8016c36ffb21fb3e5",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 23174,
            "upload_time": "2023-07-28T09:58:57",
            "upload_time_iso_8601": "2023-07-28T09:58:57.803420Z",
            "url": "https://files.pythonhosted.org/packages/2a/6d/7ff4354c9b7cc3f4fc96758350d8dedf87fe7f036bd49d394f96327faca4/flynt-1.0.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-07-28 09:58:57",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ikamensh",
    "github_project": "flynt",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "lcname": "flynt"
}
        
Elapsed time: 0.09718s