From 5cc73d1caa7d103c15c236d34ef766b6a048ae4b Mon Sep 17 00:00:00 2001 From: Dimitri Merejkowsky Date: Sat, 22 May 2021 14:52:29 +0200 Subject: [PATCH 1/2] Specify encoding when reading or writing files --- Changelog.rst | 2 ++ tbump/config.py | 4 ++-- tbump/file_bumper.py | 2 +- tbump/test/conftest.py | 2 +- tbump/test/data/after.py | 2 +- tbump/test/data/before.py | 2 +- tbump/test/test_config.py | 6 +++--- tbump/test/test_file_bumper.py | 25 ++++++++++++++++--------- tbump/test/test_git_bumper.py | 2 +- tbump/test/test_hooks.py | 6 +++--- tbump/test/test_init.py | 6 +++--- tbump/test/test_main.py | 22 +++++++++++----------- 12 files changed, 45 insertions(+), 36 deletions(-) diff --git a/Changelog.rst b/Changelog.rst index 5bd82f6..252fddb 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -6,6 +6,8 @@ Next release Default development branch is now called `main`. +Always use `utf-8` encoding explicitly + 6.3.2 (2021-04-19) ------------------ diff --git a/tbump/config.py b/tbump/config.py index e110606..d267230 100644 --- a/tbump/config.py +++ b/tbump/config.py @@ -191,12 +191,12 @@ def get_config_file(project_path: Path) -> ConfigFile: def _get_config_file(project_path: Path) -> ConfigFile: toml_path = project_path / "tbump.toml" if toml_path.exists(): - doc = tomlkit.loads(toml_path.read_text()) + doc = tomlkit.loads(toml_path.read_text(encoding="utf-8")) return TbumpTomlConfig(toml_path, doc) pyproject_path = project_path / "pyproject.toml" if pyproject_path.exists(): - doc = tomlkit.loads(pyproject_path.read_text()) + doc = tomlkit.loads(pyproject_path.read_text(encoding="utf-8")) try: doc["tool"]["tbump"] except KeyError: diff --git a/tbump/file_bumper.py b/tbump/file_bumper.py index 7e0c73a..8abf3ac 100644 --- a/tbump/file_bumper.py +++ b/tbump/file_bumper.py @@ -216,7 +216,7 @@ def compute_patches_for_change_request( for file_path_str in glob.glob(str(file_path_glob), recursive=True): file_path = Path(file_path_str) expanded_src = file_path.relative_to(self.working_path) - old_lines = file_path.read_text().splitlines(keepends=False) + old_lines = file_path.read_text(encoding="utf-8").splitlines(keepends=False) for i, old_line in enumerate(old_lines): if should_replace(old_line, old_string, search): diff --git a/tbump/test/conftest.py b/tbump/test/conftest.py index 0953bca..de3a7e8 100644 --- a/tbump/test/conftest.py +++ b/tbump/test/conftest.py @@ -36,7 +36,7 @@ def restore_cwd() -> Iterator[None]: def file_contains(path: Path, text: str) -> bool: - for line in path.read_text().splitlines(): + for line in path.read_text(encoding="utf-8").splitlines(): if text in line: return True return False diff --git a/tbump/test/data/after.py b/tbump/test/data/after.py index d016274..1fcd29a 100644 --- a/tbump/test/data/after.py +++ b/tbump/test/data/after.py @@ -7,7 +7,7 @@ def main() -> None: - Path("after-hook.stamp").write_text("") + Path("after-hook.stamp").write_text("", encoding="utf-8") if __name__ == "__main__": diff --git a/tbump/test/data/before.py b/tbump/test/data/before.py index 20fb4b6..99b329d 100644 --- a/tbump/test/data/before.py +++ b/tbump/test/data/before.py @@ -9,7 +9,7 @@ def main() -> None: current, new = sys.argv[1:] - Path("before-hook.stamp").write_text(current + " -> " + new) + Path("before-hook.stamp").write_text(current + " -> " + new, encoding="utf-8") if __name__ == "__main__": diff --git a/tbump/test/test_config.py b/tbump/test/test_config.py index 696a013..9971938 100644 --- a/tbump/test/test_config.py +++ b/tbump/test/test_config.py @@ -57,7 +57,7 @@ def test_uses_pyproject_if_tbump_toml_is_missing( to_write = tomlkit.dumps(pyproject_config) pyproject_toml = tmp_path / "pyproject.toml" - pyproject_toml.write_text(to_write) + pyproject_toml.write_text(to_write, encoding="utf-8") actual_file = tbump.config.get_config_file(tmp_path) assert actual_file.get_config() == expected_file.get_config() @@ -71,7 +71,7 @@ def test_complain_if_pyproject_does_not_contain_tbump_config(tmp_path: Path) -> profile = "black" """ ) - pyproject_toml.write_text(to_write) + pyproject_toml.write_text(to_write, encoding="utf-8") with pytest.raises(tbump.config.ConfigNotFound): tbump.config.get_config_file(tmp_path) @@ -100,7 +100,7 @@ def test_validate_schema_in_pyrpoject_toml(tmp_path: Path) -> None: ''' """ ) - pyproject_toml.write_text(to_write) + pyproject_toml.write_text(to_write, encoding="utf-8") with pytest.raises(tbump.config.InvalidConfig) as e: tbump.config.get_config_file(tmp_path) diff --git a/tbump/test/test_file_bumper.py b/tbump/test/test_file_bumper.py index 8a9b967..7386b70 100644 --- a/tbump/test/test_file_bumper.py +++ b/tbump/test/test_file_bumper.py @@ -39,7 +39,7 @@ def test_file_bumper_preserve_endings(test_repo: Path) -> None: package_json = test_repo / "package.json" # Make sure package.json contain CRLF line endings - lines = package_json.read_text().splitlines(keepends=False) + lines = package_json.read_text(encoding="utf-8").splitlines(keepends=False) package_json.write_bytes(b"\r\n".join([x.encode() for x in lines])) bumper.set_config_file(config_file) @@ -75,13 +75,15 @@ def test_looking_for_empty_groups(tmp_path: Path) -> None: src = "foo" version_template = "{major}.{minor}.{patch}" - """ + """, + encoding="utf-8", ) foo_path = tmp_path / "foo" foo_path.write_text( """ version = "1.2" - """ + """, + encoding="utf-8", ) config_file = tbump.config.get_config_file(tmp_path) bumper = tbump.file_bumper.FileBumper(tmp_path) @@ -106,10 +108,11 @@ def test_current_version_not_found(tmp_path: Path) -> None: [[file]] src = "version.txt" - """ + """, + encoding="utf-8", ) version_txt_path = tmp_path / "version.txt" - version_txt_path.write_text("nope") + version_txt_path.write_text("nope", encoding="utf-8") config_file = tbump.config.get_config_file(tmp_path) bumper = tbump.file_bumper.FileBumper(tmp_path) @@ -143,13 +146,15 @@ def test_replacing_with_empty_groups(tmp_path: Path) -> None: src = "foo" version_template = "{major}.{minor}.{patch}" - """ + """, + encoding="utf-8", ) foo_path = tmp_path / "foo" foo_path.write_text( """ version = "1.2.3" - """ + """, + encoding="utf-8", ) bumper = tbump.file_bumper.FileBumper(tmp_path) @@ -189,7 +194,8 @@ def test_changing_same_file_twice(tmp_path: Path) -> None: src = "foo.c" search = "FULL_VERSION" - """ + """, + encoding="utf-8", ) foo_c = tmp_path / "foo.c" @@ -197,7 +203,8 @@ def test_changing_same_file_twice(tmp_path: Path) -> None: """ #define FULL_VERSION "1.2.3" #define PUBLIC_VERSION "1.2" - """ + """, + encoding="utf-8", ) bumper = tbump.file_bumper.FileBumper(tmp_path) config_file = tbump.config.get_config_file(tmp_path) diff --git a/tbump/test/test_git_bumper.py b/tbump/test/test_git_bumper.py index 40217c8..3780669 100644 --- a/tbump/test/test_git_bumper.py +++ b/tbump/test/test_git_bumper.py @@ -25,7 +25,7 @@ def test_git_bumper_happy_path(test_repo: Path, test_git_bumper: GitBumper) -> N test_git_bumper.check_branch_state(new_version) # Make sure git add does not fail: # we could use file_bumper here instead - (test_repo / "VERSION").write_text(new_version) + (test_repo / "VERSION").write_text(new_version, encoding="utf-8") commands = test_git_bumper.get_commands(new_version) for command in commands: command.run() diff --git a/tbump/test/test_hooks.py b/tbump/test/test_hooks.py index 57f2c15..b330921 100644 --- a/tbump/test/test_hooks.py +++ b/tbump/test/test_hooks.py @@ -12,7 +12,7 @@ def add_hook(test_repo: Path, name: str, cmd: str, after_push: bool = False) -> None: """Patch the configuration file so that we can also test hooks.""" cfg_path = test_repo / "tbump.toml" - parsed = tomlkit.loads(cfg_path.read_text()) + parsed = tomlkit.loads(cfg_path.read_text(encoding="utf-8")) if after_push: key = "after_push" else: @@ -24,7 +24,7 @@ def add_hook(test_repo: Path, name: str, cmd: str, after_push: bool = False) -> hook_config.add("name", name) parsed[key].append(hook_config) - cfg_path.write_text(tomlkit.dumps(parsed)) + cfg_path.write_text(tomlkit.dumps(parsed), encoding="utf-8") tbump.git.run_git(test_repo, "add", ".") tbump.git.run_git(test_repo, "commit", "--message", "update hooks") @@ -64,7 +64,7 @@ def test_working_hook(test_repo: Path) -> None: add_before_hook(test_repo) tbump.main.main(["-C", str(test_repo), "1.2.41-alpha-2", "--non-interactive"]) hook_stamp = test_repo / "before-hook.stamp" - assert hook_stamp.read_text() == "1.2.41-alpha-1 -> 1.2.41-alpha-2" + assert hook_stamp.read_text(encoding="utf-8") == "1.2.41-alpha-1 -> 1.2.41-alpha-2" def test_hook_fails(test_repo: Path) -> None: diff --git a/tbump/test/test_init.py b/tbump/test/test_init.py index 16fbd06..37ebf86 100644 --- a/tbump/test/test_init.py +++ b/tbump/test/test_init.py @@ -17,7 +17,7 @@ def test_creates_tbump_toml_config(test_repo: Path) -> None: tbump.main.main(["-C", str(test_repo), "init", current_version]) assert tbump_path.exists() - config = tomlkit.loads(tbump_path.read_text()) + config = tomlkit.loads(tbump_path.read_text(encoding="utf-8")) assert config["version"]["current"] == "1.2.41-alpha1" @@ -29,13 +29,13 @@ def test_append_to_pyproject(test_repo: Path) -> None: profile = "black" """ ) - cfg_path.write_text(isort_config) + cfg_path.write_text(isort_config, encoding="utf-8") current_version = "1.2.41-alpha1" tbump.main.main(["-C", str(test_repo), "init", "--pyproject", current_version]) assert cfg_path.exists() - config = tomlkit.loads(cfg_path.read_text()) + config = tomlkit.loads(cfg_path.read_text(encoding="utf-8")) assert config["tool"]["tbump"]["version"]["current"] == "1.2.41-alpha1" assert config["tool"]["isort"]["profile"] == "black" diff --git a/tbump/test/test_main.py b/tbump/test/test_main.py index 54537ee..256f389 100644 --- a/tbump/test/test_main.py +++ b/tbump/test/test_main.py @@ -14,11 +14,11 @@ def files_bumped(test_repo: Path, using_pyproject: bool = False) -> bool: if using_pyproject: cfg_path = test_repo / "pyproject.toml" - new_toml = tomlkit.loads(cfg_path.read_text()) + new_toml = tomlkit.loads(cfg_path.read_text(encoding="utf-8")) current_version = new_toml["tool"]["tbump"]["version"]["current"] else: cfg_path = test_repo / "tbump.toml" - new_toml = tomlkit.loads(cfg_path.read_text()) + new_toml = tomlkit.loads(cfg_path.read_text(encoding="utf-8")) current_version = new_toml["version"]["current"] assert current_version == "1.2.41-alpha-2" @@ -34,7 +34,7 @@ def files_bumped(test_repo: Path, using_pyproject: bool = False) -> bool: def files_not_bumped(test_repo: Path) -> bool: toml_path = test_repo / "tbump.toml" - new_toml = tomlkit.loads(toml_path.read_text()) + new_toml = tomlkit.loads(toml_path.read_text(encoding="utf-8")) assert new_toml["version"]["current"] == "1.2.41-alpha-1" return all( @@ -127,7 +127,7 @@ def test_end_to_end_using_pyproject_toml(test_repo: Path) -> None: tbump_toml_path = test_repo / "tbump.toml" # Convert tbump config to a config inside a tool.tbump section: - tbump_config = tomlkit.loads(tbump_toml_path.read_text()) + tbump_config = tomlkit.loads(tbump_toml_path.read_text(encoding="utf-8")) tools_config = tomlkit.table() tools_config.add("tbump", tbump_config) pyproject_config = tomlkit.table() @@ -136,7 +136,7 @@ def test_end_to_end_using_pyproject_toml(test_repo: Path) -> None: # Write the pyproject.toml and remove tbump.toml pyproject_toml_path = test_repo / "pyproject.toml" - pyproject_toml_path.write_text(to_write) + pyproject_toml_path.write_text(to_write, encoding="utf-8") tbump_toml_path.unlink() tbump.git.run_git(test_repo, "add", ".") tbump.git.run_git( @@ -207,9 +207,9 @@ def test_tbump_toml_bad_syntax( test_repo: Path, message_recorder: MessageRecorder ) -> None: toml_path = test_repo / "tbump.toml" - bad_toml = tomlkit.loads(toml_path.read_text()) + bad_toml = tomlkit.loads(toml_path.read_text(encoding="utf-8")) del bad_toml["git"] - toml_path.write_text(tomlkit.dumps(bad_toml)) + toml_path.write_text(tomlkit.dumps(bad_toml), encoding="utf-8") with pytest.raises(SystemExit): tbump.main.main(["-C", str(test_repo), "1.2.42", "--non-interactive"]) assert message_recorder.find("Invalid config") @@ -271,7 +271,7 @@ def test_abort_if_file_does_not_match( test_repo: Path, message_recorder: MessageRecorder ) -> None: invalid_src = test_repo / "foo.txt" - invalid_src.write_text("this is foo") + invalid_src.write_text("this is foo", encoding="utf-8") tbump_path = test_repo / "tbump.toml" with tbump_path.open("a") as f: f.write( @@ -320,7 +320,7 @@ def test_interactive_proceed(test_repo: Path, mocker: Any) -> None: def test_do_not_add_untracked_files(test_repo: Path) -> None: - (test_repo / "untracked.txt").write_text("please don't add me") + (test_repo / "untracked.txt").write_text("please don't add me", encoding="utf-8") tbump.main.main(["-C", str(test_repo), "1.2.42", "--non-interactive"]) _, out = tbump.git.run_git_captured(test_repo, "show", "--stat", "HEAD") assert "untracked.txt" not in out @@ -328,9 +328,9 @@ def test_do_not_add_untracked_files(test_repo: Path) -> None: def test_bad_substitution(test_repo: Path, message_recorder: MessageRecorder) -> None: toml_path = test_repo / "tbump.toml" - new_toml = tomlkit.loads(toml_path.read_text()) + new_toml = tomlkit.loads(toml_path.read_text(encoding="utf-8")) new_toml["file"][0]["version_template"] = "{release}" - toml_path.write_text(tomlkit.dumps(new_toml)) + toml_path.write_text(tomlkit.dumps(new_toml), encoding="utf-8") tbump.git.run_git(test_repo, "add", ".") tbump.git.run_git(test_repo, "commit", "--message", "update repo") with pytest.raises(SystemExit): From e5fd224f70711bfd1a2dd924b3a3960443a1533d Mon Sep 17 00:00:00 2001 From: Dimitri Merejkowsky Date: Sat, 22 May 2021 15:07:09 +0200 Subject: [PATCH 2/2] Add semgrep to the list of linters --- poetry.lock | 137 ++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + semgrep.yml | 13 +++++ tasks.py | 7 +++ 4 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 semgrep.yml diff --git a/poetry.lock b/poetry.lock index db69f64..f2b6479 100644 --- a/poetry.lock +++ b/poetry.lock @@ -253,6 +253,24 @@ pipfile_deprecated_finder = ["pipreqs", "requirementslib"] requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] +[[package]] +name = "jsonschema" +version = "3.2.0" +description = "An implementation of JSON Schema validation for Python" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +attrs = ">=17.4.0" +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} +pyrsistent = ">=0.14.0" +six = ">=1.11.0" + +[package.extras] +format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"] +format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator (>0.1.0)", "rfc3339-validator"] + [[package]] name = "mccabe" version = "0.6.1" @@ -361,6 +379,14 @@ category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +[[package]] +name = "pyrsistent" +version = "0.17.3" +description = "Persistent/Functional/Immutable data structures" +category = "dev" +optional = false +python-versions = ">=3.5" + [[package]] name = "pytest" version = "6.2.4" @@ -446,6 +472,29 @@ urllib3 = ">=1.21.1,<1.27" security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +[[package]] +name = "ruamel.yaml" +version = "0.17.4" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +category = "dev" +optional = false +python-versions = ">=3" + +[package.dependencies] +"ruamel.yaml.clib" = {version = ">=0.1.2", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.10\""} + +[package.extras] +docs = ["ryd"] +jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] + +[[package]] +name = "ruamel.yaml.clib" +version = "0.2.2" +description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "safety" version = "1.10.3" @@ -471,6 +520,31 @@ python-versions = "*" [package.dependencies] contextlib2 = ">=0.5.5" +[[package]] +name = "semgrep" +version = "0.52.0" +description = "Lightweight static analysis for many languages. Find bug variants with patterns that look like source code." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +attrs = ">=19.3.0" +colorama = ">=0.4.3" +jsonschema = ">=3.2.0,<3.3.0" +packaging = ">=20.4" +requests = ">=2.22.0" +"ruamel.yaml" = ">=0.16.0,<0.18" +tqdm = ">=4.46.1" + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + [[package]] name = "tabulate" version = "0.8.9" @@ -498,6 +572,19 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "tqdm" +version = "4.60.0" +description = "Fast, Extensible Progress Meter" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" + +[package.extras] +dev = ["py-make (>=0.1.0)", "twine", "wheel"] +notebook = ["ipywidgets (>=6)"] +telegram = ["requests"] + [[package]] name = "typed-ast" version = "1.4.3" @@ -550,7 +637,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = "^3.6.2" -content-hash = "36d16dfa1b6d0127eae2b3ae83969ad41fe8f871a1935036ae50de0fcc1a542b" +content-hash = "fc0d0d151cfb20be777375f03c04eb05e26f1bd7482be5859cfdb5792f33dbb9" [metadata.files] appdirs = [ @@ -694,6 +781,10 @@ isort = [ {file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"}, {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"}, ] +jsonschema = [ + {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, + {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, +] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, @@ -750,6 +841,9 @@ pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] +pyrsistent = [ + {file = "pyrsistent-0.17.3.tar.gz", hash = "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"}, +] pytest = [ {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"}, {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"}, @@ -832,6 +926,34 @@ requests = [ {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, ] +"ruamel.yaml" = [ + {file = "ruamel.yaml-0.17.4-py3-none-any.whl", hash = "sha256:ac79fb25f5476e8e9ed1c53b8a2286d2c3f5dde49eb37dbcee5c7eb6a8415a22"}, + {file = "ruamel.yaml-0.17.4.tar.gz", hash = "sha256:44bc6b54fddd45e4bc0619059196679f9e8b79c027f4131bb072e6a22f4d5e28"}, +] +"ruamel.yaml.clib" = [ + {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:28116f204103cb3a108dfd37668f20abe6e3cafd0d3fd40dba126c732457b3cc"}, + {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:daf21aa33ee9b351f66deed30a3d450ab55c14242cfdfcd377798e2c0d25c9f1"}, + {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-win32.whl", hash = "sha256:30dca9bbcbb1cc858717438218d11eafb78666759e5094dd767468c0d577a7e7"}, + {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-win_amd64.whl", hash = "sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f"}, + {file = "ruamel.yaml.clib-0.2.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:73b3d43e04cc4b228fa6fa5d796409ece6fcb53a6c270eb2048109cbcbc3b9c2"}, + {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:53b9dd1abd70e257a6e32f934ebc482dac5edb8c93e23deb663eac724c30b026"}, + {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:839dd72545ef7ba78fd2aa1a5dd07b33696adf3e68fae7f31327161c1093001b"}, + {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-win32.whl", hash = "sha256:b1e981fe1aff1fd11627f531524826a4dcc1f26c726235a52fcb62ded27d150f"}, + {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4e52c96ca66de04be42ea2278012a2342d89f5e82b4512fb6fb7134e377e2e62"}, + {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a873e4d4954f865dcb60bdc4914af7eaae48fb56b60ed6daa1d6251c72f5337c"}, + {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ab845f1f51f7eb750a78937be9f79baea4a42c7960f5a94dde34e69f3cce1988"}, + {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-win32.whl", hash = "sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2"}, + {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:2602e91bd5c1b874d6f93d3086f9830f3e907c543c7672cf293a97c3fabdcd91"}, + {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:44c7b0498c39f27795224438f1a6be6c5352f82cb887bc33d962c3a3acc00df6"}, + {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8e8fd0a22c9d92af3a34f91e8a2594eeb35cba90ab643c5e0e643567dc8be43e"}, + {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-win32.whl", hash = "sha256:464e66a04e740d754170be5e740657a3b3b6d2bcc567f0c3437879a6e6087ff6"}, + {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:52ae5739e4b5d6317b52f5b040b1b6639e8af68a5b8fd606a8b08658fbd0cab5"}, + {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df5019e7783d14b79217ad9c56edf1ba7485d614ad5a385d1b3c768635c81c0"}, + {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99"}, + {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win32.whl", hash = "sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1"}, + {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b"}, + {file = "ruamel.yaml.clib-0.2.2.tar.gz", hash = "sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7"}, +] safety = [ {file = "safety-1.10.3-py2.py3-none-any.whl", hash = "sha256:5f802ad5df5614f9622d8d71fedec2757099705c2356f862847c58c6dfe13e84"}, {file = "safety-1.10.3.tar.gz", hash = "sha256:30e394d02a20ac49b7f65292d19d38fa927a8f9582cdfd3ad1adbbc66c641ad5"}, @@ -840,6 +962,15 @@ schema = [ {file = "schema-0.7.4-py2.py3-none-any.whl", hash = "sha256:cf97e4cd27e203ab6bb35968532de1ed8991bce542a646f0ff1d643629a4945d"}, {file = "schema-0.7.4.tar.gz", hash = "sha256:fbb6a52eb2d9facf292f233adcc6008cffd94343c63ccac9a1cb1f3e6de1db17"}, ] +semgrep = [ + {file = "semgrep-0.52.0-cp36.cp37.cp38.cp39.py36.py37.py38.py39-none-any.whl", hash = "sha256:cf45a701f72194624adca1928b3f107361f6bcd88ffad7757129f16f44f17821"}, + {file = "semgrep-0.52.0-cp36.cp37.cp38.cp39.py36.py37.py38.py39-none-macosx_10_14_x86_64.whl", hash = "sha256:cab5795a624bc0404ff73d3a30f0333999d6bda5da1aebaefc23ecf06b045629"}, + {file = "semgrep-0.52.0.tar.gz", hash = "sha256:e4e267bdc86f26159c8aa0595abd924ca5813f35cd3a605d86346610fea5d308"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] tabulate = [ {file = "tabulate-0.8.9-py3-none-any.whl", hash = "sha256:d7c013fe7abbc5e491394e10fa845f8f32fe54f8dc60c6622c6cf482d25d47e4"}, {file = "tabulate-0.8.9.tar.gz", hash = "sha256:eb1d13f25760052e8931f2ef80aaf6045a6cceb47514db8beab24cded16f13a7"}, @@ -852,6 +983,10 @@ tomlkit = [ {file = "tomlkit-0.7.0-py2.py3-none-any.whl", hash = "sha256:6babbd33b17d5c9691896b0e68159215a9387ebfa938aa3ac42f4a4beeb2b831"}, {file = "tomlkit-0.7.0.tar.gz", hash = "sha256:ac57f29693fab3e309ea789252fcce3061e19110085aa31af5446ca749325618"}, ] +tqdm = [ + {file = "tqdm-4.60.0-py2.py3-none-any.whl", hash = "sha256:daec693491c52e9498632dfbe9ccfc4882a557f5fa08982db1b4d3adbe0887c3"}, + {file = "tqdm-4.60.0.tar.gz", hash = "sha256:ebdebdb95e3477ceea267decfc0784859aa3df3e27e22d23b83e9b272bf157ae"}, +] typed-ast = [ {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, diff --git a/pyproject.toml b/pyproject.toml index 5d96963..b13b562 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,7 @@ pytest = "^6.2.1" pytest-cov = "^2.8.1" pytest-mock = "^2.0.0" safety = "^1.9.0" +semgrep = "^0.52.0" [tool.poetry.scripts] tbump = "tbump.main:main" diff --git a/semgrep.yml b/semgrep.yml new file mode 100644 index 0000000..bec38b8 --- /dev/null +++ b/semgrep.yml @@ -0,0 +1,13 @@ +rules: + - id: python-no-implicit-encoding-when-reading + languages: + - python + message: Specify encoding when using read_text() + pattern: $OBJECT.read_text() + severity: ERROR + - id: python-no-implicit-encoding-when-writing + languages: + - python + message: Specify encoding when using write_text() + pattern: $OBJECT.write_text($X) + severity: ERROR diff --git a/tasks.py b/tasks.py index 414504e..38a82bf 100644 --- a/tasks.py +++ b/tasks.py @@ -39,6 +39,12 @@ def mypy(c, machine_readable=False): c.run(cmd) +@task +def semgrep(c): + print("Running semgrep") + c.run("semgrep -c semgrep.yml") + + @task def test(c): print("Running pytest") @@ -47,6 +53,7 @@ def test(c): @task( pre=[ + call(semgrep), call(black, check=True), call(isort, check=True), call(flake8),