Skip to content

Commit 8092d1e

Browse files
feat: support python 3.13 (#539)
* feat: support python 3.13 * revert linters to 3.12, satisfy mypy * Add CHANGELOG entry --------- Co-authored-by: Scott Bailey <[email protected]>
1 parent a6d44bc commit 8092d1e

File tree

8 files changed

+666
-522
lines changed

8 files changed

+666
-522
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
fail-fast: false
2323
matrix:
2424
os: [ubuntu-latest, windows-latest, macos-latest]
25-
python-version: [3.8, 3.9, "3.10", 3.11, 3.12]
25+
python-version: [3.8, 3.9, "3.10", 3.11, 3.12, 3.13]
2626
include:
2727
- os: ubuntu-latest
2828
path: ~/.cache/pypoetry

.github/workflows/publish.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ jobs:
99
runs-on: ubuntu-latest
1010
steps:
1111
- uses: actions/checkout@f095bcc56b7c2baf48f3ac70d6d6782f4f553222
12-
- name: Set up Python 3.12
12+
- name: Set up Python 3.13
1313
uses: actions/setup-python@db9987b4c1f10f0404fa60ee629f675fafbd6763
1414
with:
15-
python-version: 3.12
15+
python-version: 3.13
1616
- name: Install dependencies
1717
run: |
1818
pip install --upgrade pip

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
v5.0.2 - Mmmm DD 2024
2+
---------------------
3+
4+
* [#539](https://github.com/godaddy/tartufo/pull/539) - Add support for python
5+
3.13, and update dependencies to latest versions.
6+
17
v5.0.1 - July 25 2024
28
---------------------
39

poetry.lock

+628-500
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+6-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ classifiers = [
1717
"Programming Language :: Python :: 3.10",
1818
"Programming Language :: Python :: 3.11",
1919
"Programming Language :: Python :: 3.12",
20+
"Programming Language :: Python :: 3.13",
2021
"Programming Language :: Python :: Implementation :: CPython",
2122
"Programming Language :: Python :: Implementation :: PyPy",
2223
"Topic :: Security",
@@ -39,10 +40,13 @@ tartufo = "tartufo.cli:main"
3940

4041
[tool.poetry.dependencies]
4142
GitPython = "^3.1.43"
42-
pygit2 = "^1.11.0"
43+
pygit2 = [
44+
{version = "^1.11.0", python = "<3.10"},
45+
{version = "^1.16.0", python = ">=3.10"}
46+
]
4347
click = "^8.1.7"
4448
colorama = {version = "*", markers = "sys_platform == 'win32'"}
45-
python = ">=3.8, <3.13"
49+
python = ">=3.8, <3.14"
4650
tomlkit = "^0.13.0"
4751
cached-property = "^1.5.2"
4852

tartufo/scanner.py

+19-14
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ def __init__(self, global_options: types.GlobalOptions, repo_path: str) -> None:
705705
# Disable ownership sanity checks to maintain compatibility with
706706
# behavior of libgit2 1.4.2 and earlier; later versions (i.e. with
707707
# pygit2 1.9.2 and later) fail in docker context otherwise.
708-
pygit2.option(pygit2.GIT_OPT_SET_OWNER_VALIDATION, 0)
708+
pygit2.option(pygit2.GIT_OPT_SET_OWNER_VALIDATION, 0) # type: ignore[attr-defined]
709709

710710
# Load any configuration file in the target repository. This comes
711711
# *BEFORE* load_repo() because that method may rely on configuration data
@@ -735,13 +735,13 @@ def _iter_diff_index(
735735
file_path = (
736736
delta.new_file.path if delta.new_file.path else delta.old_file.path
737737
)
738-
if delta.status == pygit2.GIT_DELTA_DELETED:
738+
if delta.status == pygit2.GIT_DELTA_DELETED: # type: ignore[attr-defined]
739739
self.logger.debug("Skipping as the file was a git delete operation")
740740
continue
741741
if delta.is_binary:
742742
self.logger.debug("Binary file skipped: %s", file_path)
743743
continue
744-
printable_diff: str = patch.text
744+
printable_diff: str = patch.text or ""
745745
if not self.global_options.scan_filenames:
746746
# The `printable_diff` contains diff header,
747747
# so we need to strip that before analyzing it
@@ -773,7 +773,7 @@ def filter_submodules(self, repo: pygit2.Repository) -> None:
773773
self.logger.info("Excluding submodules paths from scan.")
774774
try:
775775
for module in repo.listall_submodules():
776-
submodule = repo.lookup_submodule(module)
776+
submodule = repo.lookup_submodule(module) # type: ignore[attr-defined]
777777
patterns.append(re.compile(f"^{submodule.path}"))
778778
except AttributeError as exc:
779779
raise TartufoException(
@@ -825,11 +825,14 @@ def load_repo(self, repo_path: str) -> pygit2.Repository:
825825
raise types.GitLocalException(str(exc)) from exc
826826

827827
def _get_chunks(
828-
self, commits: Iterable, already_searched: Set[bytes], branch_name: str
828+
self,
829+
commits: Iterable[pygit2.Commit],
830+
already_searched: Set[bytes],
831+
branch_name: str,
829832
) -> Generator[types.Chunk, None, None]:
830833
diff_hash: bytes
831-
curr_commit: pygit2.Commit = None
832-
prev_commit: pygit2.Commit = None
834+
curr_commit: Optional[pygit2.Commit] = None
835+
prev_commit: Optional[pygit2.Commit] = None
833836
for curr_commit in commits:
834837
try:
835838
prev_commit = curr_commit.parents[0]
@@ -847,7 +850,7 @@ def _get_chunks(
847850
).digest()
848851
if diff_hash in already_searched:
849852
continue
850-
diff: pygit2.Diff = self._repo.diff(prev_commit, curr_commit)
853+
diff: pygit2.Diff = self._repo.diff(prev_commit, curr_commit) # type: ignore[attr-defined]
851854
already_searched.add(diff_hash)
852855
diff.find_similar()
853856
for blob, file_path in self._iter_diff_index(diff):
@@ -860,7 +863,7 @@ def _get_chunks(
860863

861864
# Finally, yield the first commit to the branch
862865
if curr_commit:
863-
tree: pygit2.Tree = self._repo.revparse_single(str(curr_commit.id)).tree
866+
tree: pygit2.Tree = self._repo.revparse_single(str(curr_commit.id)).tree # type: ignore[attr-defined]
864867
tree_diff: pygit2.Diff = tree.diff_to_tree(swap=True)
865868
iter_diff = self._iter_diff_index(tree_diff)
866869
for blob, file_path in iter_diff:
@@ -882,7 +885,7 @@ def chunks(self) -> Generator[types.Chunk, None, None]:
882885
try:
883886
if self.git_options.branch:
884887
# Single branch only
885-
branch = self._repo.branches.get(self.git_options.branch)
888+
branch = self._repo.branches.get(self.git_options.branch) # type: ignore[attr-defined]
886889
if not branch:
887890
raise BranchNotFoundException(
888891
f"Branch {self.git_options.branch} was not found."
@@ -899,7 +902,7 @@ def chunks(self) -> Generator[types.Chunk, None, None]:
899902
# scan not only the locally checked out branches (as provided
900903
# by self._repo.listall_branches()), but to also scan all
901904
# available remote refs
902-
branches = list(self._repo.branches)
905+
branches = list(self._repo.branches) # type: ignore[attr-defined]
903906
except pygit2.GitError as exc:
904907
raise types.GitRemoteException(str(exc)) from exc
905908

@@ -911,13 +914,15 @@ def chunks(self) -> Generator[types.Chunk, None, None]:
911914
branch_len = len(branches)
912915
for branch_name in branches:
913916
self.logger.info("Scanning branch: %s", branch_name)
917+
commits: Iterable[pygit2.Commit]
914918
if branch_name == "HEAD":
915-
commits = [self._repo.get(self._repo.head.target)]
919+
commits = [self._repo.get(self._repo.head.target)] # type: ignore[attr-defined]
916920
else:
917-
branch = self._repo.branches.get(branch_name)
921+
branch = self._repo.branches.get(branch_name) # type: ignore[attr-defined]
918922
try:
919923
commits = self._repo.walk(
920-
branch.resolve().target, pygit2.GIT_SORT_TOPOLOGICAL
924+
branch.resolve().target,
925+
pygit2.GIT_SORT_TOPOLOGICAL, # type: ignore[attr-defined]
921926
)
922927

923928
except AttributeError:

tests/test_git_repo_scanner.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ def test_excluded_files_are_not_scanned(self, mock_should: mock.MagicMock):
469469
test_scanner = scanner.GitRepoScanner(
470470
self.global_options, self.git_options, "."
471471
)
472-
diffs = list(test_scanner._iter_diff_index([mock_diff]))
472+
diffs = list(test_scanner._iter_diff_index([mock_diff])) # type: ignore[arg-type]
473473
self.assertEqual(diffs, [])
474474
mock_should.assert_called_once()
475475

@@ -502,7 +502,7 @@ def test_all_files_are_yielded(self, mock_should: mock.MagicMock):
502502
test_scanner = scanner.GitRepoScanner(
503503
self.global_options, self.git_options, "."
504504
)
505-
diffs = list(test_scanner._iter_diff_index([mock_diff_1, mock_diff_2]))
505+
diffs = list(test_scanner._iter_diff_index([mock_diff_1, mock_diff_2])) # type: ignore[arg-type]
506506
self.assertEqual(
507507
diffs,
508508
[

tox.ini

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
minversion = 3.8.0
33
toxworkdir = {env:TOX_WORK_DIR:.tox}
44
skip_missing_interpreters = True
5-
envlist = py{38,39,pypy3,310,311,312},black,mypy,pylint,vulture,docs
5+
envlist = py{38,39,pypy3,310,311,312,313},black,mypy,pylint,vulture,docs
66
parallel_show_output = True
77
isolated_build = True
88

@@ -13,6 +13,7 @@ python =
1313
3.10: py310
1414
3.11: py311
1515
3.12: py312
16+
3.13: py313
1617
pypy3: pypy3
1718

1819
[testenv]

0 commit comments

Comments
 (0)