Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,10 @@ To clear the cache, run:
```python
from twyn import check_dependencies

typos = check_dependencies("all")
typos = check_dependencies()

for typo in typos.errors:
print(f"Dependency:{typo.dependency}")
print(f"Did you mean any of [{','.join(typo.similars)}]")

```
```
2 changes: 1 addition & 1 deletion src/twyn/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ def run(

try:
possible_typos = check_dependencies(
selector_method=selector_method,
dependencies=set(dependency) or None,
config_file=config,
dependency_file=dependency_file,
selector_method=selector_method,
verbosity=verbosity,
use_cache=not no_cache,
use_track=False if json else not no_track,
Expand Down
4 changes: 2 additions & 2 deletions src/twyn/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import logging
from typing import Optional
from typing import Optional, Union

from rich.progress import track

Expand All @@ -26,7 +26,7 @@


def check_dependencies(
selector_method: SelectorMethod,
selector_method: Union[SelectorMethod, None] = None,
Comment thread
scastlara marked this conversation as resolved.
config_file: Optional[str] = None,
dependency_file: Optional[str] = None,
dependencies: Optional[set[str]] = None,
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

@contextmanager
def create_tmp_file(path: Path, data: str) -> Iterator[str]:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(data)
yield str(path)

Expand Down
52 changes: 32 additions & 20 deletions tests/main/test_main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from pathlib import Path
from typing import Any, Union
from unittest.mock import Mock, patch

import pytest
Expand Down Expand Up @@ -93,10 +95,10 @@ class TestCheckDependencies:
)
def test_options_priorities_assignation(
self,
cli_config,
file_config,
expected_resolved_config,
):
cli_config: dict[str, Any],
file_config: dict[str, Any],
expected_resolved_config: TwynConfiguration,
) -> None:
"""
Checks that the configuration values are picked accordingly to the priority they have.

Expand Down Expand Up @@ -133,7 +135,12 @@ def test_options_priorities_assignation(
(AvailableLoggingLevels.none, "debug", AvailableLoggingLevels.debug),
],
)
def test_logging_level(self, passed_logging_level, config, logging_level):
def test_logging_level(
self,
passed_logging_level: AvailableLoggingLevels,
config: Union[str, None],
logging_level: AvailableLoggingLevels,
) -> None:
log_level = _get_logging_level(
cli_verbosity=passed_logging_level,
config_logging_level=config,
Expand All @@ -143,8 +150,8 @@ def test_logging_level(self, passed_logging_level, config, logging_level):
@patch("twyn.main.get_parsed_dependencies_from_file")
@patch("twyn.trusted_packages.references.TopPyPiReference._get_packages_from_cache")
def test_check_dependencies_detects_typosquats(
self, mock_get_packages_from_cache, mock_get_parsed_dependencies_from_file
):
self, mock_get_packages_from_cache: Mock, mock_get_parsed_dependencies_from_file: Mock
) -> None:
mock_get_parsed_dependencies_from_file.return_value = {"my-package"}
mock_get_packages_from_cache.return_value = {"mypackage"}
error = check_dependencies(
Expand All @@ -159,7 +166,9 @@ def test_check_dependencies_detects_typosquats(
)

@patch("twyn.trusted_packages.references.TopPyPiReference._get_packages_from_cache")
def test_check_dependencies_with_input_from_cli_detects_typosquats(self, mock_get_packages_from_cache):
def test_check_dependencies_with_input_from_cli_detects_typosquats(
self, mock_get_packages_from_cache: Mock
) -> None:
mock_get_packages_from_cache.return_value = {"mypackage"}
error = check_dependencies(
config_file=None,
Expand All @@ -174,10 +183,9 @@ def test_check_dependencies_with_input_from_cli_detects_typosquats(self, mock_ge

@patch("twyn.trusted_packages.references.TopPyPiReference._get_packages_from_cache")
def test_check_dependencies_with_input_loads_file_from_different_location(
self, mock_get_packages_from_cache, tmp_path, tmpdir
self, mock_get_packages_from_cache: Mock, tmp_path: Path
) -> None:
mock_get_packages_from_cache.return_value = {"mypackage"}
tmpdir.mkdir("fake-dir")
tmp_file = tmp_path / "fake-dir" / "requirements.txt"
with create_tmp_file(tmp_file, "mypackag"):
error = check_dependencies(
Expand All @@ -192,7 +200,9 @@ def test_check_dependencies_with_input_loads_file_from_different_location(
)

@patch("twyn.trusted_packages.references.TopPyPiReference._get_packages_from_cache")
def test_check_dependencies_with_input_from_cli_accepts_multiple_dependencies(self, mock_get_packages_from_cache):
def test_check_dependencies_with_input_from_cli_accepts_multiple_dependencies(
self, mock_get_packages_from_cache: Mock
) -> None:
mock_get_packages_from_cache.return_value = {"requests", "mypackage"}

error = check_dependencies(
Expand All @@ -209,8 +219,8 @@ def test_check_dependencies_with_input_from_cli_accepts_multiple_dependencies(se
@patch("twyn.main.TopPyPiReference")
@patch("twyn.main.get_parsed_dependencies_from_file")
def test_check_dependencies_ignores_package_in_allowlist(
self, mock_get_parsed_dependencies_from_file, mock_top_pypi_reference
):
self, mock_get_parsed_dependencies_from_file: Mock, mock_top_pypi_reference: Mock
) -> None:
mock_top_pypi_reference.return_value.get_packages.return_value = {"mypackage"}
mock_get_parsed_dependencies_from_file.return_value = {"my-package"}

Expand Down Expand Up @@ -255,7 +265,7 @@ def test_check_dependencies_ignores_package_in_allowlist(
],
)
@patch("twyn.trusted_packages.references.TopPyPiReference._get_packages_from_cache")
def test_normalize_package(self, mock_get_packages_from_cache, package_name):
def test_normalize_package(self, mock_get_packages_from_cache: Mock, package_name: Mock) -> None:
mock_get_packages_from_cache.return_value = {"requests", "mypackage"}
error = check_dependencies(
config_file=None,
Expand All @@ -274,8 +284,8 @@ def test_normalize_package(self, mock_get_packages_from_cache, package_name):
@patch("twyn.main.get_parsed_dependencies_from_file")
@patch("twyn.trusted_packages.references.TopPyPiReference._get_packages_from_cache")
def test_check_dependencies_does_not_error_on_same_package(
self, mock_get_packages_from_cache, mock_get_parsed_dependencies_from_file, package_name
):
self, mock_get_packages_from_cache: Mock, mock_get_parsed_dependencies_from_file: Mock, package_name: Mock
) -> None:
mock_get_parsed_dependencies_from_file.return_value = {package_name}
mock_get_packages_from_cache.return_value = {"my-package"}
error = check_dependencies(
Expand All @@ -289,7 +299,7 @@ def test_check_dependencies_does_not_error_on_same_package(

@patch("twyn.dependency_parser.dependency_selector.DependencySelector.get_dependency_parser")
@patch("twyn.dependency_parser.requirements_txt_parser.RequirementsTxtParser.parse")
def test_get_parsed_dependencies_from_file(self, mock_parse: Mock, mock_get_dependency_parser: Mock):
def test_get_parsed_dependencies_from_file(self, mock_parse: Mock, mock_get_dependency_parser: Mock) -> None:
mock_get_dependency_parser.return_value = RequirementsTxtParser()
mock_parse.return_value = {"boto3"}
assert get_parsed_dependencies_from_file() == {"boto3"}
Expand All @@ -302,14 +312,16 @@ def test_track_is_disabled_by_default_when_used_as_package(
mock_top_pypi_reference.return_value.get_packages.return_value = {"mypackage"}
mock_get_parsed_dependencies_from_file.return_value = {"my-package"}
with patch("twyn.main.track") as m_track:
check_dependencies("all")
check_dependencies()
assert m_track.call_count == 0

@patch("twyn.main.TopPyPiReference")
@patch("twyn.main.get_parsed_dependencies_from_file")
def test_track_is_shown_when_enabled(self, mock_get_parsed_dependencies_from_file, mock_top_pypi_reference) -> None:
def test_track_is_shown_when_enabled(
self, mock_get_parsed_dependencies_from_file: Mock, mock_top_pypi_reference: Mock
) -> None:
mock_top_pypi_reference.return_value.get_packages.return_value = {"mypackage"}
mock_get_parsed_dependencies_from_file.return_value = {"my-package"}
with patch("twyn.main.track") as m_track:
check_dependencies("all", use_track=True)
Copy link
Copy Markdown
Collaborator Author

@sdn4z sdn4z Sep 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This proves it is still working after the new changes

check_dependencies(use_track=True)
assert m_track.call_count == 1