From ef6c447e1f3ff6b6a8f7e5a2a15d416a7c971d19 Mon Sep 17 00:00:00 2001 From: Peter Linss Date: Mon, 1 Jun 2020 22:03:57 -0700 Subject: [PATCH 1/8] Add check for missing `f` prefix for f-strings. Fixes #1 --- .gitignore | 3 ++ README.md | 16 +++++-- flake8_use_fstring/__init__.py | 2 +- flake8_use_fstring/base.py | 6 +-- flake8_use_fstring/prefix.py | 80 ++++++++++++++++++++++++++++++++++ setup.py | 1 + tests/conftest.py | 3 ++ tests/example.py | 13 ++++++ tests/test_00.py | 11 +++++ 9 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 flake8_use_fstring/prefix.py diff --git a/.gitignore b/.gitignore index ece6e41..d0ffaa2 100644 --- a/.gitignore +++ b/.gitignore @@ -16,5 +16,8 @@ dist/ .pytest_cache/ .coverage +# mypy +.mypy_cache/ + # System .DS_Store diff --git a/README.md b/README.md index 9cd6e57..b5ba2ec 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,11 @@ pip install flake8-use-fstring * `FS002`: `.format` formatting is used. +* `FS003`: f-string missing prefix. + ## Available Configurations -### `--percent-greedy` and `--format-greedy` +### `--percent-greedy`, `--format-greedy`, and `--fstring-missing-prefix` This plugin checks each python statement (logical line) and see if `%` or `.format` is used. @@ -45,5 +47,13 @@ Thus level 0 is the default level. However, for most projects it should be reasonable to use greedy level 2 with confidence. To set greedy levels, -set `--percent-greedy` and `--format-greedy` in the command line, -or set `percent-greedy` and `format-greedy` in the `.flake8` config file. +set `--percent-greedy=` and `--format-greedy=` in the command line, +or set `percent-greedy=` and `format-greedy=` in the `.flake8` config file. + +Optionally, this plugin can also check for strings that appear to be indended to be f-strings +but are missing the `f` prefix. +This check is intended to assist when converting code to use f-strings. +Due to the potential for false positives, this check (`FS003`) is disabled by default. +To enable this check, +add the `--fstring-missing-prefix` command line option, +or set `fstring-missing-prefix=True` in the `.flake8` config file. \ No newline at end of file diff --git a/flake8_use_fstring/__init__.py b/flake8_use_fstring/__init__.py index 7e49527..439eb0c 100644 --- a/flake8_use_fstring/__init__.py +++ b/flake8_use_fstring/__init__.py @@ -1 +1 @@ -__version__ = '1.0' +__version__ = '1.1' diff --git a/flake8_use_fstring/base.py b/flake8_use_fstring/base.py index b669743..9660dcb 100644 --- a/flake8_use_fstring/base.py +++ b/flake8_use_fstring/base.py @@ -1,5 +1,5 @@ import token as _token -import typing as _typing +from typing import Iterator, List, Tuple from tokenize import ( TokenInfo as _TokenInfo, ) @@ -13,7 +13,7 @@ class BaseLogicalLineChecker(object): def __init__( self, logical_line: str, - tokens: _typing.List[_TokenInfo], + tokens: List[_TokenInfo], ): self.logical_line = logical_line self.tokens = tokens @@ -24,7 +24,7 @@ def __getitem__(self, i: int) -> bool: def __call__(self, i: int) -> str: raise NotImplementedError # pragma: no cover - def __iter__(self) -> _typing.Iterator[_typing.Tuple[int, str]]: + def __iter__(self) -> Iterator[Tuple[Tuple[int, int], str]]: met_string = False for i in range(len(self.tokens)): diff --git a/flake8_use_fstring/prefix.py b/flake8_use_fstring/prefix.py new file mode 100644 index 0000000..aae9b9f --- /dev/null +++ b/flake8_use_fstring/prefix.py @@ -0,0 +1,80 @@ +import re +import token as _token +from typing import Iterator, Tuple + +from flake8.options.manager import ( + OptionManager as _OptionManager, +) + +from .base import ( + BaseLogicalLineChecker as _Base, +) + +FSTRING_REGEX = re.compile(r'^([a-zA-Z]*?[fF][a-zA-Z]*?){1}["\']') +NON_FSTRING_REGEX = re.compile( + r'^[a-zA-Z]*(?:\'\'\'|\'|"""|")(.*?{.+?}.*)(?:\'|\'\'\'|"|""")$') + + +class MissingPrefixDetector(_Base): + name = 'use-fstring-prefix' + version = '1.0' + greedy = '0' + enabled = False + + def __getitem__(self, i: int) -> bool: + if (not self.enabled): + return False + + token = self.tokens[i] + if token.exact_type != _token.STRING: + return False + + if FSTRING_REGEX.search(token.string): # already is an f-string + return False + + # look ahead for % or .format and skip if present + for next_index, next_token in enumerate(self.tokens[i + 1:], i + 1): + if next_token.exact_type == _token.STRING: + continue + if next_token.exact_type == _token.PERCENT: + return False + if next_token.exact_type == _token.DOT: + try: + next_token = self.tokens[next_index + 1] + if next_token.exact_type != _token.NAME: + break + if next_token.string == 'format': + return False + except IndexError: + pass + break + + value = token.string.replace('{{', '').replace('}}', '') + return NON_FSTRING_REGEX.search(value) is not None + + def __call__(self, i: int) -> str: + return 'FS003 f-string missing prefix' + + def __iter__(self) -> Iterator[Tuple[Tuple[int, int], str]]: + for i in range(len(self.tokens)): + if not self[i]: + continue + yield self.tokens[i].start, self(i) + + @classmethod + def add_options(cls, option_manager: _OptionManager): + option_manager.add_option( + f'--{cls.OPTION_NAME}', + action='store_true', + default=False, + parse_from_config=True, + ) + + g = None + + @classmethod + def parse_options(cls, options): + option_var = cls.OPTION_NAME.replace('-', '_') + cls.enabled = vars(options)[option_var] + + OPTION_NAME = 'fstring-missing-prefix' diff --git a/setup.py b/setup.py index 6957b9b..7e0f495 100644 --- a/setup.py +++ b/setup.py @@ -50,6 +50,7 @@ 'flake8.extension': [ 'FS001 = flake8_use_fstring.percent:PercentFormatDetector', 'FS002 = flake8_use_fstring.format:StrFormatDetector', + 'FS003 = flake8_use_fstring.prefix:MissingPrefixDetector', ], }, diff --git a/tests/conftest.py b/tests/conftest.py index 0b00959..597450e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,6 +7,7 @@ class TestFlake8Cmd(object): def __init__(self): self.percent_greedy = 0 self.format_greedy = 0 + self.missing_prefix = False self.expected_output = None def test(self): @@ -19,6 +20,8 @@ def test(self): f'--percent-greedy={self.percent_greedy}', f'--format-greedy={self.format_greedy}', ] + if (self.missing_prefix): + cmd.append('--fstring-missing-prefix') p = subprocess.run( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, diff --git a/tests/example.py b/tests/example.py index 8d9cdc5..e39066e 100644 --- a/tests/example.py +++ b/tests/example.py @@ -36,5 +36,18 @@ def format(self): # noqa: A003 # false positive greedy level 2 m = C().format() +# missing prefix false positive +n = (rf'{m}' + '{' + '}' + 'm' + '' + '{}' + '{{m}}') + +# match missing prefix +o = ('{n}' + '{{m}} {n}') + # no errors below; coverage ''.strip() diff --git a/tests/test_00.py b/tests/test_00.py index 24ea713..45ae423 100644 --- a/tests/test_00.py +++ b/tests/test_00.py @@ -49,3 +49,14 @@ def test_greedy_different(test_flake8_cmd): tests/example.py:18:9: FS002 '.format' used """ test_flake8_cmd.test() + + +def test_missing_prefix(test_flake8_cmd): + test_flake8_cmd.missing_prefix = True + test_flake8_cmd.expected_output = b"""\ +tests/example.py:2:10: FS001 '%' operator used +tests/example.py:18:9: FS002 '.format' used +tests/example.py:49:6: FS003 f-string missing prefix +tests/example.py:50:6: FS003 f-string missing prefix +""" + test_flake8_cmd.test() From 38cf5f772a101940a2413cd348cb24429d0e2bc1 Mon Sep 17 00:00:00 2001 From: Peter Linss Date: Tue, 2 Jun 2020 09:36:06 -0700 Subject: [PATCH 2/8] switch prefix check to off by default add option to ignore format for prefix check split base class to generic and greedy classes --- flake8_use_fstring/base.py | 14 +++++++-- flake8_use_fstring/format.py | 2 +- flake8_use_fstring/percent.py | 2 +- flake8_use_fstring/prefix.py | 53 ++++++++++++++--------------------- tests/conftest.py | 9 ++++-- tests/example.py | 2 +- tests/test_00.py | 24 ++++++++++++---- 7 files changed, 59 insertions(+), 47 deletions(-) diff --git a/flake8_use_fstring/base.py b/flake8_use_fstring/base.py index 9660dcb..5ab642c 100644 --- a/flake8_use_fstring/base.py +++ b/flake8_use_fstring/base.py @@ -1,5 +1,5 @@ import token as _token -from typing import Iterator, List, Tuple +from typing import List as _List, Iterator as _Iterator, Tuple as _Tuple from tokenize import ( TokenInfo as _TokenInfo, ) @@ -13,7 +13,7 @@ class BaseLogicalLineChecker(object): def __init__( self, logical_line: str, - tokens: List[_TokenInfo], + tokens: _List[_TokenInfo], ): self.logical_line = logical_line self.tokens = tokens @@ -24,7 +24,15 @@ def __getitem__(self, i: int) -> bool: def __call__(self, i: int) -> str: raise NotImplementedError # pragma: no cover - def __iter__(self) -> Iterator[Tuple[Tuple[int, int], str]]: + def __iter__(self) -> _Iterator[_Tuple[_Tuple[int, int], str]]: + for i in range(len(self.tokens)): + if not self[i]: + continue + yield self.tokens[i].start, self(i) + + +class BaseGreedyLogicalLineChecker(BaseLogicalLineChecker): + def __iter__(self) -> _Iterator[_Tuple[_Tuple[int, int], str]]: met_string = False for i in range(len(self.tokens)): diff --git a/flake8_use_fstring/format.py b/flake8_use_fstring/format.py index 79c3387..6a8c495 100644 --- a/flake8_use_fstring/format.py +++ b/flake8_use_fstring/format.py @@ -1,7 +1,7 @@ import token as _token from .base import ( - BaseLogicalLineChecker as _Base, + BaseGreedyLogicalLineChecker as _Base, ) diff --git a/flake8_use_fstring/percent.py b/flake8_use_fstring/percent.py index a5afa81..baf6c90 100644 --- a/flake8_use_fstring/percent.py +++ b/flake8_use_fstring/percent.py @@ -1,7 +1,7 @@ import token as _token from .base import ( - BaseLogicalLineChecker as _Base, + BaseGreedyLogicalLineChecker as _Base, ) diff --git a/flake8_use_fstring/prefix.py b/flake8_use_fstring/prefix.py index aae9b9f..9cffdad 100644 --- a/flake8_use_fstring/prefix.py +++ b/flake8_use_fstring/prefix.py @@ -1,6 +1,5 @@ import re import token as _token -from typing import Iterator, Tuple from flake8.options.manager import ( OptionManager as _OptionManager, @@ -18,13 +17,10 @@ class MissingPrefixDetector(_Base): name = 'use-fstring-prefix' version = '1.0' - greedy = '0' - enabled = False + ignore_format = False + off_by_default = True def __getitem__(self, i: int) -> bool: - if (not self.enabled): - return False - token = self.tokens[i] if token.exact_type != _token.STRING: return False @@ -32,22 +28,23 @@ def __getitem__(self, i: int) -> bool: if FSTRING_REGEX.search(token.string): # already is an f-string return False - # look ahead for % or .format and skip if present - for next_index, next_token in enumerate(self.tokens[i + 1:], i + 1): - if next_token.exact_type == _token.STRING: - continue - if next_token.exact_type == _token.PERCENT: - return False - if next_token.exact_type == _token.DOT: - try: - next_token = self.tokens[next_index + 1] - if next_token.exact_type != _token.NAME: - break - if next_token.string == 'format': - return False - except IndexError: - pass - break + if not self.ignore_format: + # look ahead for % or .format and skip if present + for next_i, next_token in enumerate(self.tokens[i + 1:], i + 1): + if next_token.exact_type == _token.STRING: + continue + if next_token.exact_type == _token.PERCENT: + return False + if next_token.exact_type == _token.DOT: + try: + next_token = self.tokens[next_i + 1] + if next_token.exact_type != _token.NAME: + break + if next_token.string == 'format': + return False + except IndexError: + pass + break value = token.string.replace('{{', '').replace('}}', '') return NON_FSTRING_REGEX.search(value) is not None @@ -55,12 +52,6 @@ def __getitem__(self, i: int) -> bool: def __call__(self, i: int) -> str: return 'FS003 f-string missing prefix' - def __iter__(self) -> Iterator[Tuple[Tuple[int, int], str]]: - for i in range(len(self.tokens)): - if not self[i]: - continue - yield self.tokens[i].start, self(i) - @classmethod def add_options(cls, option_manager: _OptionManager): option_manager.add_option( @@ -70,11 +61,9 @@ def add_options(cls, option_manager: _OptionManager): parse_from_config=True, ) - g = None - @classmethod def parse_options(cls, options): option_var = cls.OPTION_NAME.replace('-', '_') - cls.enabled = vars(options)[option_var] + cls.ignore_format = vars(options)[option_var] - OPTION_NAME = 'fstring-missing-prefix' + OPTION_NAME = 'fstring-ignore-format' diff --git a/tests/conftest.py b/tests/conftest.py index 597450e..c97f586 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,7 +7,8 @@ class TestFlake8Cmd(object): def __init__(self): self.percent_greedy = 0 self.format_greedy = 0 - self.missing_prefix = False + self.enable_prefix = False + self.ignore_format = False self.expected_output = None def test(self): @@ -20,8 +21,10 @@ def test(self): f'--percent-greedy={self.percent_greedy}', f'--format-greedy={self.format_greedy}', ] - if (self.missing_prefix): - cmd.append('--fstring-missing-prefix') + if self.enable_prefix: + cmd.append('--enable-extensions=FS003') + if self.ignore_format: + cmd.append('--fstring-ignore-format') p = subprocess.run( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, diff --git a/tests/example.py b/tests/example.py index e39066e..410ea6a 100644 --- a/tests/example.py +++ b/tests/example.py @@ -15,7 +15,7 @@ f = 3 % 2 # match greedy level 0 -g = '{}'.format(123) +g = '{val}'.format(val=123) # match greedy level 1 h = ('x' + '{}').format(123) diff --git a/tests/test_00.py b/tests/test_00.py index 45ae423..c762f3d 100644 --- a/tests/test_00.py +++ b/tests/test_00.py @@ -1,7 +1,7 @@ def test_greedy_0(test_flake8_cmd): test_flake8_cmd.expected_output = b"""\ tests/example.py:2:10: FS001 '%' operator used -tests/example.py:18:9: FS002 '.format' used +tests/example.py:18:12: FS002 '.format' used """ test_flake8_cmd.test() @@ -13,7 +13,7 @@ def test_greedy_1(test_flake8_cmd): tests/example.py:2:10: FS001 '%' operator used tests/example.py:5:18: FS001 '%' operator used tests/example.py:12:16: FS001 '%' operator used -tests/example.py:18:9: FS002 '.format' used +tests/example.py:18:12: FS002 '.format' used tests/example.py:21:17: FS002 '.format' used tests/example.py:34:13: FS002 '.format' used """ @@ -29,7 +29,7 @@ def test_greedy_2(test_flake8_cmd): tests/example.py:9:7: FS001 '%' operator used tests/example.py:12:16: FS001 '%' operator used tests/example.py:15:7: FS001 '%' operator used -tests/example.py:18:9: FS002 '.format' used +tests/example.py:18:12: FS002 '.format' used tests/example.py:21:17: FS002 '.format' used tests/example.py:25:6: FS002 '.format' used tests/example.py:34:13: FS002 '.format' used @@ -46,16 +46,28 @@ def test_greedy_different(test_flake8_cmd): tests/example.py:9:7: FS001 '%' operator used tests/example.py:12:16: FS001 '%' operator used tests/example.py:15:7: FS001 '%' operator used -tests/example.py:18:9: FS002 '.format' used +tests/example.py:18:12: FS002 '.format' used """ test_flake8_cmd.test() def test_missing_prefix(test_flake8_cmd): - test_flake8_cmd.missing_prefix = True + test_flake8_cmd.enable_prefix = True test_flake8_cmd.expected_output = b"""\ tests/example.py:2:10: FS001 '%' operator used -tests/example.py:18:9: FS002 '.format' used +tests/example.py:18:12: FS002 '.format' used +tests/example.py:49:6: FS003 f-string missing prefix +tests/example.py:50:6: FS003 f-string missing prefix +""" + test_flake8_cmd.test() + +def test_missing_prefix_ignore_format(test_flake8_cmd): + test_flake8_cmd.enable_prefix = True + test_flake8_cmd.ignore_format = True + test_flake8_cmd.expected_output = b"""\ +tests/example.py:2:10: FS001 '%' operator used +tests/example.py:18:5: FS003 f-string missing prefix +tests/example.py:18:12: FS002 '.format' used tests/example.py:49:6: FS003 f-string missing prefix tests/example.py:50:6: FS003 f-string missing prefix """ From 26f8201af8a3d1d4d800a8baa356e791ece10473 Mon Sep 17 00:00:00 2001 From: Peter Linss Date: Tue, 2 Jun 2020 09:41:56 -0700 Subject: [PATCH 3/8] update readme --- README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b5ba2ec..6433475 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,11 @@ pip install flake8-use-fstring * `FS002`: `.format` formatting is used. -* `FS003`: f-string missing prefix. +* `FS003`: f-string missing prefix (ignored by default). ## Available Configurations -### `--percent-greedy`, `--format-greedy`, and `--fstring-missing-prefix` +### `--percent-greedy`, `--format-greedy`, and `--fstring-ignore-format` This plugin checks each python statement (logical line) and see if `%` or `.format` is used. @@ -50,10 +50,15 @@ To set greedy levels, set `--percent-greedy=` and `--format-greedy=` in the command line, or set `percent-greedy=` and `format-greedy=` in the `.flake8` config file. -Optionally, this plugin can also check for strings that appear to be indended to be f-strings +Optionally, this plugin can also check for strings that appear to be intended to be f-strings but are missing the `f` prefix. -This check is intended to assist when converting code to use f-strings. +This check is meant to assist when converting code to use f-strings. Due to the potential for false positives, this check (`FS003`) is disabled by default. To enable this check, -add the `--fstring-missing-prefix` command line option, -or set `fstring-missing-prefix=True` in the `.flake8` config file. \ No newline at end of file +add the `--enable-extensions=FS003` command line option, +or set `enable-extensions=FS003` in the `.flake8` config file. + +The missing prefix check normally ignores strings that are using `%` or `.format` formatting, +to check those strings as well, +add the `--fstring-ignore-format` command line option, +or set `fstring-ignore-format=True` in the `.flake8` config file. \ No newline at end of file From 14a200834ec239e95547669cf216c8d100b63e82 Mon Sep 17 00:00:00 2001 From: Peter Linss Date: Tue, 2 Jun 2020 09:45:31 -0700 Subject: [PATCH 4/8] fix linting issue --- tests/test_00.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_00.py b/tests/test_00.py index c762f3d..7b0d9d3 100644 --- a/tests/test_00.py +++ b/tests/test_00.py @@ -61,6 +61,7 @@ def test_missing_prefix(test_flake8_cmd): """ test_flake8_cmd.test() + def test_missing_prefix_ignore_format(test_flake8_cmd): test_flake8_cmd.enable_prefix = True test_flake8_cmd.ignore_format = True From 7f6eed01927265bb470c049cfa06254ba8ff18ae Mon Sep 17 00:00:00 2001 From: Michael Kim Date: Sun, 7 Jun 2020 19:32:18 -0700 Subject: [PATCH 5/8] update styles for consistency --- flake8_use_fstring/base.py | 10 ++++++---- flake8_use_fstring/prefix.py | 9 +++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/flake8_use_fstring/base.py b/flake8_use_fstring/base.py index 5ab642c..f0aea02 100644 --- a/flake8_use_fstring/base.py +++ b/flake8_use_fstring/base.py @@ -1,5 +1,5 @@ import token as _token -from typing import List as _List, Iterator as _Iterator, Tuple as _Tuple +import typing as _typing from tokenize import ( TokenInfo as _TokenInfo, ) @@ -8,12 +8,14 @@ OptionManager as _OptionManager, ) +Flake8Output = _typing.Tuple[_typing.Tuple[int, int], str] + class BaseLogicalLineChecker(object): def __init__( self, logical_line: str, - tokens: _List[_TokenInfo], + tokens: _typing.List[_TokenInfo], ): self.logical_line = logical_line self.tokens = tokens @@ -24,7 +26,7 @@ def __getitem__(self, i: int) -> bool: def __call__(self, i: int) -> str: raise NotImplementedError # pragma: no cover - def __iter__(self) -> _Iterator[_Tuple[_Tuple[int, int], str]]: + def __iter__(self) -> _typing.Iterator[Flake8Output]: for i in range(len(self.tokens)): if not self[i]: continue @@ -32,7 +34,7 @@ def __iter__(self) -> _Iterator[_Tuple[_Tuple[int, int], str]]: class BaseGreedyLogicalLineChecker(BaseLogicalLineChecker): - def __iter__(self) -> _Iterator[_Tuple[_Tuple[int, int], str]]: + def __iter__(self) -> _typing.Iterator[Flake8Output]: met_string = False for i in range(len(self.tokens)): diff --git a/flake8_use_fstring/prefix.py b/flake8_use_fstring/prefix.py index 9cffdad..66f592e 100644 --- a/flake8_use_fstring/prefix.py +++ b/flake8_use_fstring/prefix.py @@ -1,4 +1,4 @@ -import re +import re as _re import token as _token from flake8.options.manager import ( @@ -9,9 +9,10 @@ BaseLogicalLineChecker as _Base, ) -FSTRING_REGEX = re.compile(r'^([a-zA-Z]*?[fF][a-zA-Z]*?){1}["\']') -NON_FSTRING_REGEX = re.compile( - r'^[a-zA-Z]*(?:\'\'\'|\'|"""|")(.*?{.+?}.*)(?:\'|\'\'\'|"|""")$') +FSTRING_REGEX = _re.compile(r'^([a-zA-Z]*?[fF][a-zA-Z]*?){1}["\']') +NON_FSTRING_REGEX = _re.compile( + r'^[a-zA-Z]*(?:\'\'\'|\'|"""|")(.*?{.+?}.*)(?:\'|\'\'\'|"|""")$', +) class MissingPrefixDetector(_Base): From 8533c42fbbc1543f64ce0917395b854cbe156da1 Mon Sep 17 00:00:00 2001 From: Michael Kim Date: Sun, 7 Jun 2020 19:41:33 -0700 Subject: [PATCH 6/8] fix ci coverage reporting --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 7e0f495..a0d430b 100644 --- a/setup.py +++ b/setup.py @@ -3,6 +3,7 @@ from flake8_use_fstring import __version__ extra_test = [ + 'coverage==4.*', 'pytest>=4', 'pytest-cov>=2', From fb780c64b4d9c66df0390d23d23f2f96b00a169c Mon Sep 17 00:00:00 2001 From: Michael Kim Date: Sun, 7 Jun 2020 19:48:35 -0700 Subject: [PATCH 7/8] update README --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6433475..d5263e1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,11 @@ # flake8-use-fstring -[![Build Status](https://travis-ci.com/MichaelKim0407/flake8-use-fstring.svg?branch=master)](https://travis-ci.com/MichaelKim0407/flake8-use-fstring) -[![Coverage Status](https://coveralls.io/repos/github/MichaelKim0407/flake8-use-fstring/badge.svg?branch=master)](https://coveralls.io/github/MichaelKim0407/flake8-use-fstring?branch=master) +* `master` (release) + [![Build Status](https://travis-ci.com/MichaelKim0407/flake8-use-fstring.svg?branch=master)](https://travis-ci.com/MichaelKim0407/flake8-use-fstring) + [![Coverage Status](https://coveralls.io/repos/github/MichaelKim0407/flake8-use-fstring/badge.svg?branch=master)](https://coveralls.io/github/MichaelKim0407/flake8-use-fstring?branch=master) +* `develop` (main) + [![Build Status](https://travis-ci.com/MichaelKim0407/flake8-use-fstring.svg?branch=develop)](https://travis-ci.com/MichaelKim0407/flake8-use-fstring) + [![Coverage Status](https://coveralls.io/repos/github/MichaelKim0407/flake8-use-fstring/badge.svg?branch=develop)](https://coveralls.io/github/MichaelKim0407/flake8-use-fstring?branch=develop) Jump-start into modern Python by forcing yourself to use f-strings. From e834b40671a698871c3a162eacbae509172d08db Mon Sep 17 00:00:00 2001 From: Michael Kim Date: Sun, 7 Jun 2020 19:55:47 -0700 Subject: [PATCH 8/8] Add GitHub action for publishing to pypi --- .github/workflows/python-publish.yml | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/python-publish.yml diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000..40595e4 --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,31 @@ +# This workflows will upload a Python Package using Twine when a release is created +# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries + +name: Upload Python Package + +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.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools twine + - name: Build and publish + env: + TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + python setup.py sdist + twine upload dist/*