Skip to content

Commit d418f62

Browse files
authored
Merge branch 'master' into fix-timsort-typehints
2 parents 4d12ec8 + abf7168 commit d418f62

19 files changed

Lines changed: 164 additions & 52 deletions

File tree

.github/workflows/sphinx.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
- run: uv sync --group=docs
4242
- uses: actions/configure-pages@v6
4343
- run: uv run sphinx-build -c docs . docs/_build/html
44-
- uses: actions/upload-pages-artifact@v4
44+
- uses: actions/upload-pages-artifact@v5
4545
with:
4646
path: docs/_build/html
4747

.pre-commit-config.yaml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,20 @@ repos:
1919
- id: auto-walrus
2020

2121
- repo: https://github.com/astral-sh/ruff-pre-commit
22-
rev: v0.14.14
22+
rev: v0.15.9
2323
hooks:
2424
- id: ruff-check
2525
- id: ruff-format
2626

2727
- repo: https://github.com/codespell-project/codespell
28-
rev: v2.4.1
28+
rev: v2.4.2
2929
hooks:
3030
- id: codespell
3131
additional_dependencies:
3232
- tomli
3333

3434
- repo: https://github.com/tox-dev/pyproject-fmt
35-
rev: v2.12.1
35+
rev: v2.21.0
3636
hooks:
3737
- id: pyproject-fmt
3838

@@ -45,19 +45,19 @@ repos:
4545
pass_filenames: false
4646

4747
- repo: https://github.com/abravalheri/validate-pyproject
48-
rev: v0.24.1
48+
rev: v0.25
4949
hooks:
5050
- id: validate-pyproject
5151

52-
- repo: https://github.com/pre-commit/mirrors-mypy
53-
rev: v1.19.1
54-
hooks:
55-
- id: mypy
56-
args:
57-
- --explicit-package-bases
58-
- --ignore-missing-imports
59-
- --install-types
60-
- --non-interactive
52+
# - repo: https://github.com/pre-commit/mirrors-mypy
53+
# rev: v1.20.0
54+
# hooks:
55+
# - id: mypy
56+
# args:
57+
# - --explicit-package-bases
58+
# - --ignore-missing-imports
59+
# - --install-types
60+
# - --non-interactive
6161

6262
- repo: https://github.com/pre-commit/mirrors-prettier
6363
rev: v4.0.0-alpha.8

digital_image_processing/filters/local_binary_pattern.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def get_neighbors_pixel(
1919

2020
try:
2121
return int(image[x_coordinate][y_coordinate] >= center)
22-
except (IndexError, TypeError):
22+
except IndexError, TypeError:
2323
return 0
2424

2525

divide_and_conquer/convex_hull.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def _construct_points(
124124
else:
125125
try:
126126
points.append(Point(p[0], p[1]))
127-
except (IndexError, TypeError):
127+
except IndexError, TypeError:
128128
print(
129129
f"Ignoring deformed point {p}. All points"
130130
" must have at least 2 coordinates."

dynamic_programming/catalan_numbers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def catalan_numbers(upper_limit: int) -> "list[int]":
7171
print(f"The Catalan numbers from 0 through {N} are:")
7272
print(catalan_numbers(N))
7373
print("Try another upper limit for the sequence: ", end="")
74-
except (NameError, ValueError):
74+
except NameError, ValueError:
7575
print("\n********* Invalid input, goodbye! ************\n")
7676

7777
import doctest

geometry/segment_intersection.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
"""
2+
Given two line segments, determine whether they intersect.
3+
4+
This is based on the algorithm described in Introduction to Algorithms
5+
(CLRS), Chapter 33.
6+
7+
Reference:
8+
- https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
9+
- https://en.wikipedia.org/wiki/Orientation_(geometry)
10+
"""
11+
12+
from __future__ import annotations
13+
14+
from typing import NamedTuple
15+
16+
17+
class Point(NamedTuple):
18+
"""A point in 2D space.
19+
20+
>>> Point(0, 0)
21+
Point(x=0, y=0)
22+
>>> Point(1, -3)
23+
Point(x=1, y=-3)
24+
"""
25+
26+
x: float
27+
y: float
28+
29+
30+
def direction(pivot: Point, target: Point, query: Point) -> float:
31+
"""Return the cross product of vectors (pivot->query) and (pivot->target).
32+
33+
The sign of the result encodes the orientation of the ordered triple
34+
(pivot, target, query):
35+
- Negative -> counter-clockwise (left turn)
36+
- Positive -> clockwise (right turn)
37+
- Zero -> collinear
38+
39+
>>> direction(Point(0, 0), Point(1, 0), Point(0, 1))
40+
-1
41+
>>> direction(Point(0, 0), Point(0, 1), Point(1, 0))
42+
1
43+
>>> direction(Point(0, 0), Point(1, 1), Point(2, 2))
44+
0
45+
"""
46+
return (query.x - pivot.x) * (target.y - pivot.y) - (target.x - pivot.x) * (
47+
query.y - pivot.y
48+
)
49+
50+
51+
def on_segment(seg_start: Point, seg_end: Point, point: Point) -> bool:
52+
"""Check whether *point*, known to be collinear with the segment, lies on it.
53+
54+
>>> on_segment(Point(0, 0), Point(4, 4), Point(2, 2))
55+
True
56+
>>> on_segment(Point(0, 0), Point(4, 4), Point(5, 5))
57+
False
58+
>>> on_segment(Point(0, 0), Point(4, 0), Point(2, 0))
59+
True
60+
"""
61+
return min(seg_start.x, seg_end.x) <= point.x <= max(
62+
seg_start.x, seg_end.x
63+
) and min(seg_start.y, seg_end.y) <= point.y <= max(seg_start.y, seg_end.y)
64+
65+
66+
def segments_intersect(p1: Point, p2: Point, p3: Point, p4: Point) -> bool:
67+
"""Return True if line segment p1p2 intersects line segment p3p4.
68+
69+
Uses the CLRS cross-product / orientation method. Handles both the
70+
general case (proper crossing) and degenerate cases where one endpoint
71+
lies exactly on the other segment.
72+
73+
>>> segments_intersect(Point(0, 0), Point(2, 2), Point(0, 2), Point(2, 0))
74+
True
75+
>>> segments_intersect(Point(0, 0), Point(2, 2), Point(1, 1), Point(3, 3))
76+
True
77+
>>> segments_intersect(Point(0, 0), Point(1, 0), Point(2, 0), Point(3, 0))
78+
False
79+
>>> segments_intersect(Point(0, 0), Point(1, 1), Point(1, 0), Point(2, 1))
80+
False
81+
>>> segments_intersect(Point(0, 0), Point(1, 1), Point(0, 1), Point(0, 2))
82+
False
83+
>>> segments_intersect(Point(0, 0), Point(1, 0), Point(1, 0), Point(2, 0))
84+
True
85+
"""
86+
d1 = direction(p3, p4, p1)
87+
d2 = direction(p3, p4, p2)
88+
d3 = direction(p1, p2, p3)
89+
d4 = direction(p1, p2, p4)
90+
91+
if ((d1 < 0 < d2) or (d2 < 0 < d1)) and ((d3 < 0 < d4) or (d4 < 0 < d3)):
92+
return True
93+
94+
if d1 == 0 and on_segment(p3, p4, p1):
95+
return True
96+
if d2 == 0 and on_segment(p3, p4, p2):
97+
return True
98+
if d3 == 0 and on_segment(p1, p2, p3):
99+
return True
100+
return d4 == 0 and on_segment(p1, p2, p4)
101+
102+
103+
if __name__ == "__main__":
104+
import doctest
105+
106+
doctest.testmod()
107+
108+
print("Enter four points as 'x y' pairs (one per line):")
109+
points = [Point(*map(float, input().split())) for _ in range(4)]
110+
p1, p2, p3, p4 = points
111+
result = segments_intersect(p1, p2, p3, p4)
112+
print(1 if result else 0)

hashes/hamming_code.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ def emitter_converter(size_par, data):
118118
data_ord.append(None)
119119

120120
# Calculates parity
121-
qtd_bp = 0 # parity bit counter
122121
for bp in range(1, size_par + 1):
123122
# Bit counter one for a given parity
124123
cont_bo = 0
@@ -133,8 +132,6 @@ def emitter_converter(size_par, data):
133132
cont_bo += 1
134133
parity.append(cont_bo % 2)
135134

136-
qtd_bp += 1
137-
138135
# Mount the message
139136
cont_bp = 0 # parity bit counter
140137
for x in range(size_par + len(data)):
@@ -208,7 +205,6 @@ def receptor_converter(size_par, data):
208205
data_ord.append(None)
209206

210207
# Calculates parity
211-
qtd_bp = 0 # parity bit counter
212208
for bp in range(1, size_par + 1):
213209
# Bit counter one for a certain parity
214210
cont_bo = 0
@@ -222,8 +218,6 @@ def receptor_converter(size_par, data):
222218
cont_bo += 1
223219
parity.append(str(cont_bo % 2))
224220

225-
qtd_bp += 1
226-
227221
# Mount the message
228222
cont_bp = 0 # Parity bit counter
229223
for x in range(size_par + len(data_output)):

maths/greatest_common_divisor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def main():
7373
f"{greatest_common_divisor(num_1, num_2)}"
7474
)
7575
print(f"By iterative gcd({num_1}, {num_2}) = {gcd_by_iterative(num_1, num_2)}")
76-
except (IndexError, UnboundLocalError, ValueError):
76+
except IndexError, UnboundLocalError, ValueError:
7777
print("Wrong input")
7878

7979

project_euler/problem_002/sol4.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def solution(n: int = 4000000) -> int:
5656

5757
try:
5858
n = int(n)
59-
except (TypeError, ValueError):
59+
except TypeError, ValueError:
6060
raise TypeError("Parameter n must be int or castable to int.")
6161
if n <= 0:
6262
raise ValueError("Parameter n must be greater than or equal to one.")

project_euler/problem_003/sol1.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def solution(n: int = 600851475143) -> int:
8080

8181
try:
8282
n = int(n)
83-
except (TypeError, ValueError):
83+
except TypeError, ValueError:
8484
raise TypeError("Parameter n must be int or castable to int.")
8585
if n <= 0:
8686
raise ValueError("Parameter n must be greater than or equal to one.")

0 commit comments

Comments
 (0)