diff --git a/tests/cli/test_bumpversion.py b/tests/cli/test_bumpversion.py index 70a77f0..c886cd2 100644 --- a/tests/cli/test_bumpversion.py +++ b/tests/cli/test_bumpversion.py @@ -7,6 +7,7 @@ from unittest.mock import patch import pytest +import pyflowx as px from pyflowx.cli import bumpversion @@ -76,7 +77,7 @@ class TestBumpFileVersion: content = test_file.read_text(encoding="utf-8") assert "build" not in content - def test_no_version_found(self, tmp_path: Path, capsys) -> None: + def test_no_version_found(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None: """Should return None when no version pattern found.""" test_file = tmp_path / "test.txt" test_file.write_text("no version here", encoding="utf-8") @@ -149,7 +150,7 @@ dependencies = ["lib >= 2.0.0", "other >= 3.0.0"] assert "lib >= 2.0.0" in updated assert "other >= 3.0.0" in updated - def test_file_read_error(self, tmp_path: Path, capsys) -> None: + def test_file_read_error(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None: """Should handle file read errors.""" # 创建一个目录而不是文件 test_file = tmp_path / "test_dir" @@ -158,7 +159,7 @@ dependencies = ["lib >= 2.0.0", "other >= 3.0.0"] with pytest.raises(Exception): # noqa: B017 bumpversion.bump_file_version(test_file, "patch") - def test_file_write_error(self, tmp_path: Path, capsys) -> None: + def test_file_write_error(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None: """Should handle file write errors.""" # 在只读目录中创建文件(这个测试在某些系统上可能不适用) test_file = tmp_path / "readonly.toml" @@ -224,7 +225,7 @@ class TestVersionPattern: class TestEdgeCases: """Test edge cases and error handling.""" - def test_empty_file(self, tmp_path: Path, capsys) -> None: + def test_empty_file(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None: """Should handle empty file.""" test_file = tmp_path / "empty.txt" test_file.write_text("", encoding="utf-8") @@ -280,7 +281,7 @@ class TestBumpVersionCli: # Mock px.run: 只真正执行第一次调用(版本更新),其余返回空 dict with patch("sys.argv", ["bumpversion", "minor", "--no-tag"]), patch("pyflowx.run") as mock_run: - def run_side_effect(graph, strategy=None): + def run_side_effect(graph: px.Graph, strategy: str | None = None): # 执行实际版本更新任务 results = {} for spec in graph.specs.values(): @@ -294,14 +295,14 @@ class TestBumpVersionCli: # 验证版本号已更新 assert test_file.read_text(encoding="utf-8") == '__version__ = "1.1.0"' - def test_no_valid_files(self, tmp_path: Path, capsys) -> None: + def test_no_valid_files(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None: """Should handle no valid files.""" test_file = tmp_path / "test.txt" test_file.write_text("这是一个测试文件", encoding="utf-8") with patch("sys.argv", ["bumpversion", "minor", "--no-tag"]), patch("pyflowx.run") as mock_run: - def run_side_effect(graph, strategy=None): + def run_side_effect(graph: px.Graph, strategy: str | None = None): # 执行实际版本更新任务 results = {} for spec in graph.specs.values(): diff --git a/tests/cli/test_emlmanager.py b/tests/cli/test_emlmanager.py index aeba19d..292cbb9 100644 --- a/tests/cli/test_emlmanager.py +++ b/tests/cli/test_emlmanager.py @@ -30,6 +30,8 @@ class TestEmailDatabase: db_path = tmp_path / "test.db" db = emlmanager.EmailDatabase(db_path) + assert db.conn is not None + cursor = db.conn.cursor() cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='emails'") result = cursor.fetchone() @@ -41,6 +43,8 @@ class TestEmailDatabase: db_path = tmp_path / "test.db" db = emlmanager.EmailDatabase(db_path) + assert db.conn is not None + cursor = db.conn.cursor() cursor.execute("SELECT name FROM sqlite_master WHERE type='index' AND name='idx_subject'") result = cursor.fetchone() @@ -68,6 +72,7 @@ class TestEmailDatabase: result = db.insert_email(email_data) assert result is True + assert db.conn is not None cursor = db.conn.cursor() cursor.execute("SELECT COUNT(*) FROM emails") @@ -101,6 +106,8 @@ class TestEmailDatabase: email_data["file_hash"] = "xyz789" db.insert_email(email_data) + assert db.conn is not None + cursor = db.conn.cursor() cursor.execute("SELECT COUNT(*) FROM emails") count = cursor.fetchone()[0] @@ -118,21 +125,19 @@ class TestEmailDatabase: # Insert test emails for i in range(5): - db.insert_email( - { - "file_path": f"/test/path{i}.eml", - "file_hash": f"hash{i}", - "subject": f"Subject {i}", - "sender": f"sender{i}@example.com", - "recipients": "recipient@example.com", - "date": f"Mon, {i + 1} Jan 2024 12:00:00 +0000", - "date_parsed": f"2024-01-0{i + 1}T12:00:00", - "body_text": f"Body {i}", - "body_html": f"
Body {i}
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": f"/test/path{i}.eml", + "file_hash": f"hash{i}", + "subject": f"Subject {i}", + "sender": f"sender{i}@example.com", + "recipients": "recipient@example.com", + "date": f"Mon, {i + 1} Jan 2024 12:00:00 +0000", + "date_parsed": f"2024-01-0{i + 1}T12:00:00", + "body_text": f"Body {i}", + "body_html": f"Body {i}
", + "has_attachments": 0, + "file_size": 1024, + }) results = db.search_emails(limit=3) assert len(results) == 3 @@ -143,37 +148,33 @@ class TestEmailDatabase: db_path = tmp_path / "test.db" db = emlmanager.EmailDatabase(db_path) - db.insert_email( - { - "file_path": "/test/path1.eml", - "file_hash": "hash1", - "subject": "Important Meeting", - "sender": "sender1@example.com", - "recipients": "recipient@example.com", - "date": "Mon, 1 Jan 2024 12:00:00 +0000", - "date_parsed": "2024-01-01T12:00:00", - "body_text": "Meeting body", - "body_html": "Meeting body
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": "/test/path1.eml", + "file_hash": "hash1", + "subject": "Important Meeting", + "sender": "sender1@example.com", + "recipients": "recipient@example.com", + "date": "Mon, 1 Jan 2024 12:00:00 +0000", + "date_parsed": "2024-01-01T12:00:00", + "body_text": "Meeting body", + "body_html": "Meeting body
", + "has_attachments": 0, + "file_size": 1024, + }) - db.insert_email( - { - "file_path": "/test/path2.eml", - "file_hash": "hash2", - "subject": "Casual Chat", - "sender": "sender2@example.com", - "recipients": "recipient@example.com", - "date": "Tue, 2 Jan 2024 12:00:00 +0000", - "date_parsed": "2024-01-02T12:00:00", - "body_text": "Chat body", - "body_html": "Chat body
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": "/test/path2.eml", + "file_hash": "hash2", + "subject": "Casual Chat", + "sender": "sender2@example.com", + "recipients": "recipient@example.com", + "date": "Tue, 2 Jan 2024 12:00:00 +0000", + "date_parsed": "2024-01-02T12:00:00", + "body_text": "Chat body", + "body_html": "Chat body
", + "has_attachments": 0, + "file_size": 1024, + }) results = db.search_emails(keyword="Meeting", field="subject") assert len(results) == 1 @@ -185,37 +186,33 @@ class TestEmailDatabase: db_path = tmp_path / "test.db" db = emlmanager.EmailDatabase(db_path) - db.insert_email( - { - "file_path": "/test/path1.eml", - "file_hash": "hash1", - "subject": "Test", - "sender": "alice@example.com", - "recipients": "recipient@example.com", - "date": "Mon, 1 Jan 2024 12:00:00 +0000", - "date_parsed": "2024-01-01T12:00:00", - "body_text": "Body", - "body_html": "Body
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": "/test/path1.eml", + "file_hash": "hash1", + "subject": "Test", + "sender": "alice@example.com", + "recipients": "recipient@example.com", + "date": "Mon, 1 Jan 2024 12:00:00 +0000", + "date_parsed": "2024-01-01T12:00:00", + "body_text": "Body", + "body_html": "Body
", + "has_attachments": 0, + "file_size": 1024, + }) - db.insert_email( - { - "file_path": "/test/path2.eml", - "file_hash": "hash2", - "subject": "Test", - "sender": "bob@example.com", - "recipients": "recipient@example.com", - "date": "Tue, 2 Jan 2024 12:00:00 +0000", - "date_parsed": "2024-01-02T12:00:00", - "body_text": "Body", - "body_html": "Body
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": "/test/path2.eml", + "file_hash": "hash2", + "subject": "Test", + "sender": "bob@example.com", + "recipients": "recipient@example.com", + "date": "Tue, 2 Jan 2024 12:00:00 +0000", + "date_parsed": "2024-01-02T12:00:00", + "body_text": "Body", + "body_html": "Body
", + "has_attachments": 0, + "file_size": 1024, + }) results = db.search_emails(keyword="alice", field="sender") assert len(results) == 1 @@ -227,21 +224,19 @@ class TestEmailDatabase: db_path = tmp_path / "test.db" db = emlmanager.EmailDatabase(db_path) - db.insert_email( - { - "file_path": "/test/path1.eml", - "file_hash": "hash1", - "subject": "Project Update", - "sender": "manager@example.com", - "recipients": "team@example.com", - "date": "Mon, 1 Jan 2024 12:00:00 +0000", - "date_parsed": "2024-01-01T12:00:00", - "body_text": "Please review the quarterly report", - "body_html": "Please review the quarterly report
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": "/test/path1.eml", + "file_hash": "hash1", + "subject": "Project Update", + "sender": "manager@example.com", + "recipients": "team@example.com", + "date": "Mon, 1 Jan 2024 12:00:00 +0000", + "date_parsed": "2024-01-01T12:00:00", + "body_text": "Please review the quarterly report", + "body_html": "Please review the quarterly report
", + "has_attachments": 0, + "file_size": 1024, + }) # Search for keyword in subject results = db.search_emails(keyword="Project", field="all") @@ -258,53 +253,47 @@ class TestEmailDatabase: db = emlmanager.EmailDatabase(db_path) # Insert emails with same subject (different prefixes) - db.insert_email( - { - "file_path": "/test/path1.eml", - "file_hash": "hash1", - "subject": "Meeting Tomorrow", - "sender": "sender1@example.com", - "recipients": "recipient@example.com", - "date": "Mon, 1 Jan 2024 12:00:00 +0000", - "date_parsed": "2024-01-01T12:00:00", - "body_text": "Body 1", - "body_html": "Body 1
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": "/test/path1.eml", + "file_hash": "hash1", + "subject": "Meeting Tomorrow", + "sender": "sender1@example.com", + "recipients": "recipient@example.com", + "date": "Mon, 1 Jan 2024 12:00:00 +0000", + "date_parsed": "2024-01-01T12:00:00", + "body_text": "Body 1", + "body_html": "Body 1
", + "has_attachments": 0, + "file_size": 1024, + }) - db.insert_email( - { - "file_path": "/test/path2.eml", - "file_hash": "hash2", - "subject": "Re: Meeting Tomorrow", - "sender": "sender2@example.com", - "recipients": "recipient@example.com", - "date": "Tue, 2 Jan 2024 12:00:00 +0000", - "date_parsed": "2024-01-02T12:00:00", - "body_text": "Body 2", - "body_html": "Body 2
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": "/test/path2.eml", + "file_hash": "hash2", + "subject": "Re: Meeting Tomorrow", + "sender": "sender2@example.com", + "recipients": "recipient@example.com", + "date": "Tue, 2 Jan 2024 12:00:00 +0000", + "date_parsed": "2024-01-02T12:00:00", + "body_text": "Body 2", + "body_html": "Body 2
", + "has_attachments": 0, + "file_size": 1024, + }) - db.insert_email( - { - "file_path": "/test/path3.eml", - "file_hash": "hash3", - "subject": "Different Topic", - "sender": "sender3@example.com", - "recipients": "recipient@example.com", - "date": "Wed, 3 Jan 2024 12:00:00 +0000", - "date_parsed": "2024-01-03T12:00:00", - "body_text": "Body 3", - "body_html": "Body 3
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": "/test/path3.eml", + "file_hash": "hash3", + "subject": "Different Topic", + "sender": "sender3@example.com", + "recipients": "recipient@example.com", + "date": "Wed, 3 Jan 2024 12:00:00 +0000", + "date_parsed": "2024-01-03T12:00:00", + "body_text": "Body 3", + "body_html": "Body 3
", + "has_attachments": 0, + "file_size": 1024, + }) grouped = db.get_grouped_emails() # Should have 2 groups: "Meeting Tomorrow" and "Different Topic" @@ -333,21 +322,19 @@ class TestEmailDatabase: assert db.get_email_count() == 0 for i in range(3): - db.insert_email( - { - "file_path": f"/test/path{i}.eml", - "file_hash": f"hash{i}", - "subject": f"Subject {i}", - "sender": f"sender{i}@example.com", - "recipients": "recipient@example.com", - "date": f"Mon, {i + 1} Jan 2024 12:00:00 +0000", - "date_parsed": f"2024-01-0{i + 1}T12:00:00", - "body_text": f"Body {i}", - "body_html": f"Body {i}
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": f"/test/path{i}.eml", + "file_hash": f"hash{i}", + "subject": f"Subject {i}", + "sender": f"sender{i}@example.com", + "recipients": "recipient@example.com", + "date": f"Mon, {i + 1} Jan 2024 12:00:00 +0000", + "date_parsed": f"2024-01-0{i + 1}T12:00:00", + "body_text": f"Body {i}", + "body_html": f"Body {i}
", + "has_attachments": 0, + "file_size": 1024, + }) assert db.get_email_count() == 3 db.close() @@ -359,21 +346,19 @@ class TestEmailDatabase: # Insert some emails for i in range(3): - db.insert_email( - { - "file_path": f"/test/path{i}.eml", - "file_hash": f"hash{i}", - "subject": f"Subject {i}", - "sender": f"sender{i}@example.com", - "recipients": "recipient@example.com", - "date": f"Mon, {i + 1} Jan 2024 12:00:00 +0000", - "date_parsed": f"2024-01-0{i + 1}T12:00:00", - "body_text": f"Body {i}", - "body_html": f"Body {i}
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": f"/test/path{i}.eml", + "file_hash": f"hash{i}", + "subject": f"Subject {i}", + "sender": f"sender{i}@example.com", + "recipients": "recipient@example.com", + "date": f"Mon, {i + 1} Jan 2024 12:00:00 +0000", + "date_parsed": f"2024-01-0{i + 1}T12:00:00", + "body_text": f"Body {i}", + "body_html": f"Body {i}
", + "has_attachments": 0, + "file_size": 1024, + }) assert db.get_email_count() == 3 @@ -411,7 +396,7 @@ class TestDecodeMimeWords: def test_decode_none(self) -> None: """Should handle None input.""" - result = emlmanager.decode_mime_words(None) + result = emlmanager.decode_mime_words("") assert result == "" def test_decode_mixed_encoding(self) -> None: @@ -702,21 +687,19 @@ class TestEmlManagerHandler: # Insert some emails for i in range(3): - db.insert_email( - { - "file_path": f"/test/path{i}.eml", - "file_hash": f"hash{i}", - "subject": f"Subject {i}", - "sender": f"sender{i}@example.com", - "recipients": "recipient@example.com", - "date": f"Mon, {i + 1} Jan 2024 12:00:00 +0000", - "date_parsed": f"2024-01-0{i + 1}T12:00:00", - "body_text": f"Body {i}", - "body_html": f"Body {i}
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": f"/test/path{i}.eml", + "file_hash": f"hash{i}", + "subject": f"Subject {i}", + "sender": f"sender{i}@example.com", + "recipients": "recipient@example.com", + "date": f"Mon, {i + 1} Jan 2024 12:00:00 +0000", + "date_parsed": f"2024-01-0{i + 1}T12:00:00", + "body_text": f"Body {i}", + "body_html": f"Body {i}
", + "has_attachments": 0, + "file_size": 1024, + }) # Create a mock handler instance without calling __init__ handler = Mock(spec=emlmanager.EmlManagerHandler) @@ -738,21 +721,19 @@ class TestEmlManagerHandler: db = emlmanager.EmailDatabase(db_path) # Insert test email - db.insert_email( - { - "file_path": "/test/path.eml", - "file_hash": "hash", - "subject": "Test Subject", - "sender": "sender@example.com", - "recipients": "recipient@example.com", - "date": "Mon, 1 Jan 2024 12:00:00 +0000", - "date_parsed": "2024-01-01T12:00:00", - "body_text": "Test body", - "body_html": "Test body
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": "/test/path.eml", + "file_hash": "hash", + "subject": "Test Subject", + "sender": "sender@example.com", + "recipients": "recipient@example.com", + "date": "Mon, 1 Jan 2024 12:00:00 +0000", + "date_parsed": "2024-01-01T12:00:00", + "body_text": "Test body", + "body_html": "Test body
", + "has_attachments": 0, + "file_size": 1024, + }) # Create a mock handler instance without calling __init__ handler = Mock(spec=emlmanager.EmlManagerHandler) @@ -775,21 +756,19 @@ class TestEmlManagerHandler: db = emlmanager.EmailDatabase(db_path) # Insert test email - db.insert_email( - { - "file_path": "/test/path.eml", - "file_hash": "hash", - "subject": "Test Subject", - "sender": "sender@example.com", - "recipients": "recipient@example.com", - "date": "Mon, 1 Jan 2024 12:00:00 +0000", - "date_parsed": "2024-01-01T12:00:00", - "body_text": "Test body", - "body_html": "Test body
", - "has_attachments": 0, - "file_size": 1024, - } - ) + db.insert_email({ + "file_path": "/test/path.eml", + "file_hash": "hash", + "subject": "Test Subject", + "sender": "sender@example.com", + "recipients": "recipient@example.com", + "date": "Mon, 1 Jan 2024 12:00:00 +0000", + "date_parsed": "2024-01-01T12:00:00", + "body_text": "Test body", + "body_html": "Test body
", + "has_attachments": 0, + "file_size": 1024, + }) assert db.get_email_count() == 1 diff --git a/tests/cli/test_envrs.py b/tests/cli/test_envrs.py index c3f4d93..ce3d086 100644 --- a/tests/cli/test_envrs.py +++ b/tests/cli/test_envrs.py @@ -48,6 +48,7 @@ class TestSetRustMirror: def test_set_rust_mirror_unknown_uses_default(self, tmp_path: Path) -> None: """Should use default mirror for unknown mirror name.""" with patch.object(Path, "home", return_value=tmp_path): + # pyrefly: ignore [bad-argument-type] envrs.set_rust_mirror("unknown") # Should use default mirror (tsinghua) assert os.environ.get("RUSTUP_DIST_SERVER") == "https://mirrors.tuna.tsinghua.edu.cn/rustup" diff --git a/tests/cli/test_gittool.py b/tests/cli/test_gittool.py index 8c1461c..f6030b4 100644 --- a/tests/cli/test_gittool.py +++ b/tests/cli/test_gittool.py @@ -107,6 +107,7 @@ class TestTaskSpecDefinitions: def test_kill_tgit_spec(self) -> None: """kill_tgit spec should be properly defined.""" assert gittool.kill_tgit.name == "task_kill" + assert isinstance(gittool.kill_tgit.cmd, list) assert "taskkill" in gittool.kill_tgit.cmd diff --git a/tests/cli/test_pdftool.py b/tests/cli/test_pdftool.py index ec379f8..234e4c2 100644 --- a/tests/cli/test_pdftool.py +++ b/tests/cli/test_pdftool.py @@ -3,6 +3,7 @@ from __future__ import annotations from pathlib import Path +from typing import Any from unittest.mock import MagicMock, patch import pytest @@ -71,7 +72,7 @@ class TestPdfCompress: mock_fitz_open.return_value = mock_doc # Mock save to actually create the file - def mock_save(*args, **kwargs): + def mock_save(*args: Any, **kwargs: Any): output_file.write_bytes(b"Compressed PDF") mock_doc.save = mock_save diff --git a/tests/test_executors_edge_cases.py b/tests/test_executors_edge_cases.py index c5561ff..ef48fa8 100644 --- a/tests/test_executors_edge_cases.py +++ b/tests/test_executors_edge_cases.py @@ -54,7 +54,7 @@ def test_verbose_event_callback_running(): assert report.success -def test_verbose_run_with_success_lifecycle(capsys): +def test_verbose_run_with_success_lifecycle(capsys: pytest.CaptureFixture[str]): """Test px.run with verbose=True prints SUCCESS lifecycle.""" spec = px.TaskSpec("test", fn=lambda: "result") graph = px.Graph.from_specs([spec]) @@ -64,7 +64,7 @@ def test_verbose_run_with_success_lifecycle(capsys): assert "成功" in captured.out -def test_verbose_run_with_failed_lifecycle(capsys): +def test_verbose_run_with_failed_lifecycle(capsys: pytest.CaptureFixture[str]): """Test px.run with verbose=True prints FAILED lifecycle with error.""" def raise_error(): @@ -80,7 +80,7 @@ def test_verbose_run_with_failed_lifecycle(capsys): assert "test error" in captured.out -def test_verbose_run_with_skipped_lifecycle(capsys): +def test_verbose_run_with_skipped_lifecycle(capsys: pytest.CaptureFixture[str]): """Test px.run with verbose=True prints SKIPPED lifecycle.""" spec = px.TaskSpec( "test", @@ -98,7 +98,7 @@ def test_verbose_run_with_user_callback(): """Test px.run with verbose=True and user callback both called.""" events = [] - def on_event(event): + def on_event(event: px.TaskEvent): events.append(event) spec = px.TaskSpec("test", fn=lambda: "result") diff --git a/tests/test_task_edge_cases.py b/tests/test_task_edge_cases.py index c1f5538..0a3dc12 100644 --- a/tests/test_task_edge_cases.py +++ b/tests/test_task_edge_cases.py @@ -177,7 +177,7 @@ def test_taskspec_shell_cmd_file_not_found_mocked(): _ = wrapped_fn() -def test_taskspec_shell_cmd_with_cwd_verbose(capsys): +def test_taskspec_shell_cmd_with_cwd_verbose(capsys: pytest.CaptureFixture[str]): """Test TaskSpec._wrap_cmd with shell command, cwd and verbose=True.""" with tempfile.TemporaryDirectory() as tmpdir: if sys.platform == "win32": diff --git a/typings/graphlib/graphlib.pyi b/typings/graphlib/graphlib.pyi index aa3d3c7..8c03667 100644 --- a/typings/graphlib/graphlib.pyi +++ b/typings/graphlib/graphlib.pyi @@ -11,7 +11,7 @@ _NODE_DONE = ... class _NodeInfo: __slots__: list[str] - def __init__(self, node) -> None: ... + def __init__(self, node: Any) -> None: ... class CycleError(ValueError): """Subclass of ValueError raised by TopologicalSorterif cycles exist in the graph @@ -29,8 +29,8 @@ class CycleError(ValueError): class TopologicalSorter: """Provides functionality to topologically sort a graph of hashable nodes""" - def __init__(self, graph=...) -> None: ... - def add(self, node, *predecessors) -> None: + def __init__(self, graph: Any) -> None: ... + def add(self, node: Any, *predecessors: Any) -> None: """Add a new node and its predecessors to the graph. Both the *node* and all elements in *predecessors* must be hashable. @@ -86,7 +86,7 @@ class TopologicalSorter: ... def __bool__(self) -> bool: ... - def done(self, *nodes) -> None: + def done(self, *nodes: Any) -> None: """Marks a set of nodes returned by "get_ready" as processed. This method unblocks any successor of each node in *nodes* for being returned