Skip to content

Commit deccf10

Browse files
authored
Merge pull request #30 from faif/master
Syncing from upstream faif/python-patterns (master)
2 parents 11a2627 + 39708b9 commit deccf10

11 files changed

Lines changed: 159 additions & 9 deletions

File tree

.github/workflows/lint_pr.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
has_python_changes: ${{ steps.changed-files.outputs.has_python_changes }}
88
files: ${{ steps.changed-files.outputs.files }}
99
steps:
10-
- uses: actions/checkout@v3
10+
- uses: actions/checkout@v6
1111
with:
1212
fetch-depth: 0 # To get all history for git diff commands
1313

@@ -71,15 +71,15 @@ jobs:
7171
exit 0
7272
fi
7373
74-
- uses: actions/checkout@v3
74+
- uses: actions/checkout@v6
7575
with:
7676
fetch-depth: 0
7777

78-
- uses: actions/setup-python@v4
78+
- uses: actions/setup-python@v6
7979
with:
8080
python-version: 3.12
8181

82-
- uses: actions/cache@v3
82+
- uses: actions/cache@v5
8383
with:
8484
path: ~/.cache/pip
8585
key: ${{ runner.os }}-pip-${{ hashFiles('requirements-dev.txt') }}
@@ -273,7 +273,7 @@ jobs:
273273
if: ${{ always() }}
274274
runs-on: ubuntu-24.04
275275
steps:
276-
- uses: actions/checkout@v3
276+
- uses: actions/checkout@v6
277277

278278
- name: Summarize results
279279
run: |

.github/workflows/lint_python.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ jobs:
44
lint_python:
55
runs-on: ubuntu-24.04
66
steps:
7-
- uses: actions/checkout@v3
8-
- uses: actions/setup-python@v4
7+
- uses: actions/checkout@v6
8+
- uses: actions/setup-python@v6
99
with:
1010
python-version: 3.12
1111
- name: Install dependencies

patterns/behavioral/chain_of_responsibility.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
As a variation some receivers may be capable of sending requests out
1515
in several directions, forming a `tree of responsibility`.
1616
17+
*Examples in Python ecosystem:
18+
Django Middleware: https://docs.djangoproject.com/en/stable/topics/http/middleware/
19+
The middleware components act as a chain where each processes the request/response.
20+
1721
*TL;DR
1822
Allow a request to pass down a chain of receivers until it is handled.
1923
"""

patterns/behavioral/memento.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"""
77

88
from copy import copy, deepcopy
9-
from typing import Callable, List
9+
from typing import Any, Callable, List, Type
1010

1111

1212
def memento(obj: Any, deep: bool = False) -> Callable:

patterns/structural/mvc.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"""
55

66
from abc import ABC, abstractmethod
7-
from ProductModel import Price
87
from typing import Dict, List, Union, Any
98
from inspect import signature
109
from sys import argv

pytest_local.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[pytest]
2+
addopts = -q
3+
testpaths = tests

tests/creational/test_factory.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import unittest
2+
from patterns.creational.factory import get_localizer, GreekLocalizer, EnglishLocalizer
3+
4+
class TestFactory(unittest.TestCase):
5+
def test_get_localizer_greek(self):
6+
localizer = get_localizer("Greek")
7+
self.assertIsInstance(localizer, GreekLocalizer)
8+
self.assertEqual(localizer.localize("dog"), "σκύλος")
9+
self.assertEqual(localizer.localize("cat"), "γάτα")
10+
# Test unknown word returns the word itself
11+
self.assertEqual(localizer.localize("monkey"), "monkey")
12+
13+
def test_get_localizer_english(self):
14+
localizer = get_localizer("English")
15+
self.assertIsInstance(localizer, EnglishLocalizer)
16+
self.assertEqual(localizer.localize("dog"), "dog")
17+
self.assertEqual(localizer.localize("cat"), "cat")
18+
19+
def test_get_localizer_default(self):
20+
# Test default argument
21+
localizer = get_localizer()
22+
self.assertIsInstance(localizer, EnglishLocalizer)
23+
24+
def test_get_localizer_unknown_language(self):
25+
# Test fallback for unknown language if applicable,
26+
# or just verify what happens.
27+
# Based on implementation: localizers.get(language, EnglishLocalizer)()
28+
# It defaults to EnglishLocalizer for unknown keys.
29+
localizer = get_localizer("Spanish")
30+
self.assertIsInstance(localizer, EnglishLocalizer)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import pytest
2+
3+
from patterns.fundamental.delegation_pattern import Delegator, Delegate
4+
5+
6+
def test_delegator_delegates_attribute_and_call():
7+
d = Delegator(Delegate())
8+
assert d.p1 == 123
9+
assert d.do_something("something") == "Doing something"
10+
assert d.do_something("something", kw=", hi") == "Doing something, hi"
11+
12+
13+
def test_delegator_missing_attribute_raises():
14+
d = Delegator(Delegate())
15+
with pytest.raises(AttributeError):
16+
_ = d.p2

tests/structural/test_facade.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from patterns.structural.facade import ComputerFacade
2+
3+
4+
def test_computer_facade_start(capsys):
5+
cf = ComputerFacade()
6+
cf.start()
7+
out = capsys.readouterr().out
8+
assert "Freezing processor." in out
9+
assert "Loading from 0x00 data:" in out
10+
assert "Jumping to: 0x00" in out
11+
assert "Executing." in out

tests/structural/test_flyweight.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from patterns.structural.flyweight import Card
2+
3+
4+
def test_card_flyweight_identity_and_repr():
5+
c1 = Card("9", "h")
6+
c2 = Card("9", "h")
7+
assert c1 is c2
8+
assert repr(c1) == "<Card: 9h>"
9+
10+
11+
def test_card_attribute_persistence_and_pool_clear():
12+
Card._pool.clear()
13+
c1 = Card("A", "s")
14+
c1.temp = "t"
15+
c2 = Card("A", "s")
16+
assert hasattr(c2, "temp")
17+
18+
Card._pool.clear()
19+
c3 = Card("A", "s")
20+
assert not hasattr(c3, "temp")

0 commit comments

Comments
 (0)