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
1 change: 0 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ jobs:
strategy:
matrix:
python-version: # All Python versions supported by Impulse.
- "3.9"
- "3.10"
- "3.11"
- "3.12"
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Changelog
=========

latest
------

* Drop support for Python 3.9.

2.1 (2025-10-31)
----------------

Expand Down
1 change: 0 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# Configuration file for the Sphinx documentation builder.
#
Expand Down
12 changes: 11 additions & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ lint:
@echo
@echo '👍 {{GREEN}} Linting all good.{{NORMAL}}'

# Fix any ruff errors
autofix:
@uv run ruff check --fix

# Build docs.
build-docs:
@uv run --group=docs sphinx-build -b html docs dist/docs --fail-on-warning --fresh-env --quiet
Expand All @@ -72,4 +76,10 @@ check:
@just lint
@just build-docs
@just test-all
@echo '👍 {{GREEN}} Linting, docs and smoke tests all good.{{NORMAL}}'
@echo '👍 {{GREEN}} Linting, docs and smoke tests all good.{{NORMAL}}'

# Upgrade Python code to the supplied version. (E.g. just upgrade 310)
upgrade-python MIN_VERSION:
@find {docs,src,tests} -name "*.py" -not -path "tests/assets/*" -exec uv run pyupgrade --py{{MIN_VERSION}}-plus --exit-zero-even-if-changed {} +
@just autofix
@just format
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description = "Command line interface for analyzing Python imports."
authors = [
{name = "David Seddon", email = "david@seddonym.me"},
]
requires-python = ">=3.9"
requires-python = ">=3.10"
dependencies = [
"click>=6",
"grimp==3.13",
Expand All @@ -20,7 +20,6 @@ classifiers = [
"Operating System :: POSIX",
"Operating System :: Microsoft :: Windows",
"Programming Language :: Python",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand Down Expand Up @@ -84,6 +83,7 @@ import-linter = { workspace = true }
dev = [
"mypy>=1.18.2",
"pre-commit>=4.3.0",
"pyupgrade>=3.21.0",
"ruff>=0.13.2",
]
docs = [
Expand Down
13 changes: 6 additions & 7 deletions src/impulse/application/use_cases.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from collections.abc import Set
from typing import Callable
from collections.abc import Callable
import itertools
import grimp
from impulse import ports, dotfile
from typing import Optional


def draw_graph(
Expand Down Expand Up @@ -64,7 +63,7 @@ def prepare_graph(self, grimp_graph: grimp.ImportGraph, children: Set[str]) -> N

def build_edge(
self, grimp_graph: grimp.ImportGraph, upstream: str, downstream: str
) -> Optional[dotfile.Edge]:
) -> dotfile.Edge | None:
raise NotImplementedError


Expand All @@ -77,7 +76,7 @@ def prepare_graph(self, grimp_graph: grimp.ImportGraph, children: Set[str]) -> N

def build_edge(
self, grimp_graph: grimp.ImportGraph, upstream: str, downstream: str
) -> Optional[dotfile.Edge]:
) -> dotfile.Edge | None:
if grimp_graph.direct_import_exists(importer=downstream, imported=upstream):
return dotfile.Edge(source=downstream, destination=upstream)
return None
Expand All @@ -94,7 +93,7 @@ def __init__(
self.module_name = module_name
self.show_import_totals = show_import_totals
self.show_cycle_breakers = show_cycle_breakers
self.cycle_breakers: Optional[set[tuple[str, str]]] = None
self.cycle_breakers: set[tuple[str, str]] | None = None

def should_concentrate(self) -> bool:
# We need to see edge direction emphasized separately.
Expand Down Expand Up @@ -123,15 +122,15 @@ def _get_coarse_grained_cycle_breakers(
return coarse_grained_cycle_breakers

@staticmethod
def _get_self_or_ancestor(candidate: str, ancestors: Set[str]) -> Optional[str]:
def _get_self_or_ancestor(candidate: str, ancestors: Set[str]) -> str | None:
for ancestor in ancestors:
if candidate == ancestor or candidate.startswith(f"{ancestor}."):
return ancestor
return None

def build_edge(
self, grimp_graph: grimp.ImportGraph, upstream: str, downstream: str
) -> Optional[dotfile.Edge]:
) -> dotfile.Edge | None:
if grimp_graph.direct_import_exists(
importer=downstream, imported=upstream, as_packages=True
):
Expand Down
3 changes: 1 addition & 2 deletions tests/unit/application/test_use_cases.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from typing import Optional
from impulse.application import use_cases
from copy import copy
from impulse import dotfile
Expand Down Expand Up @@ -59,7 +58,7 @@ def build_fake_graph(package_name: str) -> grimp.ImportGraph:

class SpyGraphViewer(ports.GraphViewer):
def __init__(self) -> None:
self.called_with_dot: Optional[dotfile.DotGraph] = None
self.called_with_dot: dotfile.DotGraph | None = None

def view(self, dot: dotfile.DotGraph) -> None:
self.called_with_dot = dot
Expand Down
Loading