From 8658a58648aae3152b117c6b39cc6bec153e4ba8 Mon Sep 17 00:00:00 2001 From: radaevdaniil Date: Fri, 9 Jan 2026 16:44:14 +0300 Subject: [PATCH 1/7] add README.md --- radaev/README.md | Bin 0 -> 32 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 radaev/README.md diff --git a/radaev/README.md b/radaev/README.md new file mode 100644 index 0000000000000000000000000000000000000000..dfb2a4a4d61660b79410e3de511ef2bd66b47bad GIT binary patch literal 32 kcmezWPnki1!Gj@{AqNQa8FYZWbcRfZ5(Y&EUIs1(0D{H^{Qv*} literal 0 HcmV?d00001 From 02dcd700638e404407bd643853fa47b4cbdd2c16 Mon Sep 17 00:00:00 2001 From: radaevdaniil Date: Fri, 9 Jan 2026 22:13:02 +0300 Subject: [PATCH 2/7] Fix CI workflow --- .github/workflows/ci.yml | 25 +++++++++++++++++++++++ .github/workflows/github-actions-demo.yml | 18 ---------------- .github/workflows/test-pipeline.yml | 18 ---------------- main.py | 2 ++ test_main.py | 4 ++++ 5 files changed, 31 insertions(+), 36 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/github-actions-demo.yml delete mode 100644 .github/workflows/test-pipeline.yml create mode 100644 main.py create mode 100644 test_main.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9087a3a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,25 @@ +name: CI + +on: + push: + branches: [ main ] + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install dependencies + run: pip install pytest + + - name: Run tests + run: pytest diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml deleted file mode 100644 index b00f8e9..0000000 --- a/.github/workflows/github-actions-demo.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: GitHub Actions Demo -run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 -on: [push] -jobs: - Explore-GitHub-Actions: - runs-on: ubuntu-latest - steps: - - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." - - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" - - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." - - name: Check out repository code - uses: actions/checkout@v5 - - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." - - run: echo "🖥️ The workflow is now ready to test your code on the runner." - - name: List files in the repository - run: | - ls ${{ github.workspace }} - - run: echo "🍏 This job's status is ${{ job.status }}." diff --git a/.github/workflows/test-pipeline.yml b/.github/workflows/test-pipeline.yml deleted file mode 100644 index b16d2ae..0000000 --- a/.github/workflows/test-pipeline.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Test pipeline -run-name: Testing our repository -on: [push] -jobs: - Build: - runs-on: ubuntu-latest - steps: - - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." - - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" - - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." - - name: Check out repository code - uses: actions/checkout@v5 - - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." - - run: echo "🖥️ The workflow is now ready to test your code on the runner." - - name: List files in the repository - run: | - ls ${{ github.workspace }} - - run: echo "🍏 This job's status is ${{ job.status }}." diff --git a/main.py b/main.py new file mode 100644 index 0000000..3bddbbe --- /dev/null +++ b/main.py @@ -0,0 +1,2 @@ +def hello(): + return "Hello, CI/CD!" diff --git a/test_main.py b/test_main.py new file mode 100644 index 0000000..c49be78 --- /dev/null +++ b/test_main.py @@ -0,0 +1,4 @@ +from main import hello + +def test_hello(): + assert hello() == "Hello, CI/CD!" From b62000ac061727cfe8980145d6a8c05bb4b6de85 Mon Sep 17 00:00:00 2001 From: radaevdaniil Date: Fri, 9 Jan 2026 22:22:22 +0300 Subject: [PATCH 3/7] Update CI to run on feature/radaev branch --- .github/workflows/ci.yml | 2 +- test_file.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 test_file.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9087a3a..74570cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [ main ] + branches: [ main, feature/radaev ] pull_request: jobs: diff --git a/test_file.txt b/test_file.txt new file mode 100644 index 0000000..3a37543 --- /dev/null +++ b/test_file.txt @@ -0,0 +1 @@ +# Test for CI From 89fdb2f4bb0361696248c9baca438bf5e07450e3 Mon Sep 17 00:00:00 2001 From: radaevdaniil Date: Fri, 9 Jan 2026 22:26:56 +0300 Subject: [PATCH 4/7] Add release workflow for automatic GitHub releases --- .github/workflows/release.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..3e6afc8 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,22 @@ +name: Release + +on: + push: + tags: + - 'v*.*.*' + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Build project + run: echo "Собираем проект..." + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + name: Release ${{ github.ref_name }} + body: Автоматический релиз новой версии From 7f558969dca0c801733c46d581b28f2f7486702e Mon Sep 17 00:00:00 2001 From: radaevdaniil Date: Fri, 9 Jan 2026 23:13:44 +0300 Subject: [PATCH 5/7] Add 4 design patterns: Singleton, Factory Method, Abstract Factory, Builder --- design_patterns/abstract_factory.py | 15 +++++++++++++++ design_patterns/builder.py | 19 +++++++++++++++++++ design_patterns/factory_method.py | 18 ++++++++++++++++++ design_patterns/singleton.py | 6 ++++++ 4 files changed, 58 insertions(+) create mode 100644 design_patterns/abstract_factory.py create mode 100644 design_patterns/builder.py create mode 100644 design_patterns/factory_method.py create mode 100644 design_patterns/singleton.py diff --git a/design_patterns/abstract_factory.py b/design_patterns/abstract_factory.py new file mode 100644 index 0000000..d5ea41c --- /dev/null +++ b/design_patterns/abstract_factory.py @@ -0,0 +1,15 @@ +from abc import ABC, abstractmethod + +class Button(ABC): + @abstractmethod + def paint(self): pass + +class WinButton(Button): + def paint(self): return "Windows button" + +class GUIFactory(ABC): + @abstractmethod + def create_button(self): pass + +class WinFactory(GUIFactory): + def create_button(self): return WinButton() diff --git a/design_patterns/builder.py b/design_patterns/builder.py new file mode 100644 index 0000000..24a318d --- /dev/null +++ b/design_patterns/builder.py @@ -0,0 +1,19 @@ +class Car: + def __init__(self): + self.engine = None + self.seats = None + +class CarBuilder: + def __init__(self): + self.car = Car() + + def set_engine(self, engine): + self.car.engine = engine + return self + + def set_seats(self, seats): + self.car.seats = seats + return self + + def build(self): + return self.car diff --git a/design_patterns/factory_method.py b/design_patterns/factory_method.py new file mode 100644 index 0000000..df5208b --- /dev/null +++ b/design_patterns/factory_method.py @@ -0,0 +1,18 @@ +from abc import ABC, abstractmethod + +class Transport(ABC): + @abstractmethod + def deliver(self): pass + +class Truck(Transport): + def deliver(self): return "Доставка грузовиком" + +class Logistics(ABC): + @abstractmethod + def create_transport(self): pass + + def plan(self): + return self.create_transport().deliver() + +class RoadLogistics(Logistics): + def create_transport(self): return Truck() diff --git a/design_patterns/singleton.py b/design_patterns/singleton.py new file mode 100644 index 0000000..7a835a3 --- /dev/null +++ b/design_patterns/singleton.py @@ -0,0 +1,6 @@ +class Singleton: + _instance = None + def __new__(cls): + if not cls._instance: + cls._instance = super().__new__(cls) + return cls._instance From 3b1eabb40d7a81f0d4148cf7a3699231afa7bc6a Mon Sep 17 00:00:00 2001 From: radaevdaniil Date: Fri, 9 Jan 2026 23:21:29 +0300 Subject: [PATCH 6/7] Add 6 patterns: Strategy, Chain, Iterator, Proxy, Bridge, Adapter --- patterns2/adapter.py | 7 +++++++ patterns2/bridge.py | 4 ++++ patterns2/chain.py | 5 +++++ patterns2/iterator.py | 10 ++++++++++ patterns2/proxy.py | 6 ++++++ patterns2/strategy.py | 4 ++++ 6 files changed, 36 insertions(+) create mode 100644 patterns2/adapter.py create mode 100644 patterns2/bridge.py create mode 100644 patterns2/chain.py create mode 100644 patterns2/iterator.py create mode 100644 patterns2/proxy.py create mode 100644 patterns2/strategy.py diff --git a/patterns2/adapter.py b/patterns2/adapter.py new file mode 100644 index 0000000..bf7ad5f --- /dev/null +++ b/patterns2/adapter.py @@ -0,0 +1,7 @@ +class Adaptee: + def specific_request(self): return "Адаптируемый" +class Adapter: + def __init__(self, adaptee): + self.adaptee = adaptee + def request(self): + return self.adaptee.specific_request() diff --git a/patterns2/bridge.py b/patterns2/bridge.py new file mode 100644 index 0000000..8a874aa --- /dev/null +++ b/patterns2/bridge.py @@ -0,0 +1,4 @@ +class Implementor: + def operation(self): pass +class ConcreteImpl(Implementor): + def operation(self): return "Мост" diff --git a/patterns2/chain.py b/patterns2/chain.py new file mode 100644 index 0000000..339f942 --- /dev/null +++ b/patterns2/chain.py @@ -0,0 +1,5 @@ +class Handler: + def __init__(self, nxt=None): + self.next = nxt + def handle(self, req): + if self.next: return self.next.handle(req) diff --git a/patterns2/iterator.py b/patterns2/iterator.py new file mode 100644 index 0000000..3ed672b --- /dev/null +++ b/patterns2/iterator.py @@ -0,0 +1,10 @@ +class Iterator: + def __init__(self, items): + self.items = items + self.index = 0 + def __next__(self): + if self.index < len(self.items): + item = self.items[self.index] + self.index += 1 + return item + raise StopIteration diff --git a/patterns2/proxy.py b/patterns2/proxy.py new file mode 100644 index 0000000..5e68ad1 --- /dev/null +++ b/patterns2/proxy.py @@ -0,0 +1,6 @@ +class Proxy: + def __init__(self, real): + self.real = real + def operation(self): + if not self.real: self.real = Real() + return self.real.operation() diff --git a/patterns2/strategy.py b/patterns2/strategy.py new file mode 100644 index 0000000..d3e2393 --- /dev/null +++ b/patterns2/strategy.py @@ -0,0 +1,4 @@ +class Strategy: + def execute(self): pass +class ConcreteStrategy(Strategy): + def execute(self): return "Стратегия" From e7351dd0096cca256deeab6e89223cee75298cc1 Mon Sep 17 00:00:00 2001 From: radaevdaniil Date: Fri, 9 Jan 2026 23:34:10 +0300 Subject: [PATCH 7/7] Update pattern implementations with my code --- patterns2/adapter.py | 41 ++++++++++++++++++++++++++++++++++------ patterns2/bridge.py | 43 ++++++++++++++++++++++++++++++++++++++---- patterns2/chain.py | 44 +++++++++++++++++++++++++++++++++++++++---- patterns2/iterator.py | 34 +++++++++++++++++++++++++++------ patterns2/proxy.py | 38 +++++++++++++++++++++++++++++++------ patterns2/strategy.py | 41 ++++++++++++++++++++++++++++++++++++---- 6 files changed, 211 insertions(+), 30 deletions(-) diff --git a/patterns2/adapter.py b/patterns2/adapter.py index bf7ad5f..9ff9698 100644 --- a/patterns2/adapter.py +++ b/patterns2/adapter.py @@ -1,7 +1,36 @@ -class Adaptee: - def specific_request(self): return "Адаптируемый" +cat > adapter.py << 'EOF' +class EuropeanSocket: + def voltage(self): + return 220 + + def plug(self): + return "Европейская вилка" + +class AmericanSocket: + def voltage(self): + return 110 + + def plug_type(self): + return "Американская вилка" + class Adapter: - def __init__(self, adaptee): - self.adaptee = adaptee - def request(self): - return self.adaptee.specific_request() + def __init__(self, socket): + self.socket = socket + + def voltage(self): + return self.socket.voltage() + + def plug(self): + if hasattr(self.socket, 'plug_type'): + return f"Адаптер для {self.socket.plug_type()}" + return self.socket.plug() + +# Пример +if __name__ == "__main__": + eu_socket = EuropeanSocket() + print(f"Европа: {eu_socket.voltage()}V, {eu_socket.plug()}") + + us_socket = AmericanSocket() + adapter = Adapter(us_socket) + print(f"США через адаптер: {adapter.voltage()}V, {adapter.plug()}") +EOF \ No newline at end of file diff --git a/patterns2/bridge.py b/patterns2/bridge.py index 8a874aa..6c977a7 100644 --- a/patterns2/bridge.py +++ b/patterns2/bridge.py @@ -1,4 +1,39 @@ -class Implementor: - def operation(self): pass -class ConcreteImpl(Implementor): - def operation(self): return "Мост" +cat > bridge.py << 'EOF' +class Device: + def turn_on(self): + pass + + def turn_off(self): + pass + +class TV(Device): + def turn_on(self): + return "TV включен" + + def turn_off(self): + return "TV выключен" + +class Radio(Device): + def turn_on(self): + return "Radio включен" + + def turn_off(self): + return "Radio выключен" + +class Remote: + def __init__(self, device): + self.device = device + + def toggle_power(self): + pass + +class BasicRemote(Remote): + def toggle_power(self): + return self.device.turn_on() + +# Пример +if __name__ == "__main__": + tv = TV() + remote = BasicRemote(tv) + print(remote.toggle_power()) +EOF \ No newline at end of file diff --git a/patterns2/chain.py b/patterns2/chain.py index 339f942..26c290c 100644 --- a/patterns2/chain.py +++ b/patterns2/chain.py @@ -1,5 +1,41 @@ +cat > chain_of_responsibility.py << 'EOF' class Handler: - def __init__(self, nxt=None): - self.next = nxt - def handle(self, req): - if self.next: return self.next.handle(req) + def __init__(self): + self.next = None + + def set_next(self, handler): + self.next = handler + return handler + + def handle(self, request): + if self.next: + return self.next.handle(request) + return None + +class TechnicalSupport(Handler): + def handle(self, request): + if request == "": + return " " + return super().handle(request) + +class BillingSupport(Handler): + def handle(self, request): + if request == "": + return " " + return super().handle(request) + +class GeneralSupport(Handler): + def handle(self, request): + return " " + +# +if __name__ == "__main__": + tech = TechnicalSupport() + billing = BillingSupport() + general = GeneralSupport() + + tech.set_next(billing).set_next(general) + + print(tech.handle("")) + print(tech.handle("")) +EOF \ No newline at end of file diff --git a/patterns2/iterator.py b/patterns2/iterator.py index 3ed672b..22be342 100644 --- a/patterns2/iterator.py +++ b/patterns2/iterator.py @@ -1,10 +1,32 @@ -class Iterator: - def __init__(self, items): - self.items = items +cat > iterator.py << 'EOF' +class BookCollection: + def __init__(self): + self.books = [] + + def add_book(self, book): + self.books.append(book) + + def __iter__(self): + return BookIterator(self.books) + +class BookIterator: + def __init__(self, books): + self.books = books self.index = 0 + def __next__(self): - if self.index < len(self.items): - item = self.items[self.index] + if self.index < len(self.books): + book = self.books[self.index] self.index += 1 - return item + return book raise StopIteration + +# +if __name__ == "__main__": + library = BookCollection() + library.add_book(" ") + library.add_book(" ") + + for book in library: + print(f": {book}") +EOF \ No newline at end of file diff --git a/patterns2/proxy.py b/patterns2/proxy.py index 5e68ad1..3a21d49 100644 --- a/patterns2/proxy.py +++ b/patterns2/proxy.py @@ -1,6 +1,32 @@ -class Proxy: - def __init__(self, real): - self.real = real - def operation(self): - if not self.real: self.real = Real() - return self.real.operation() +cat > proxy.py << 'EOF' +class Image: + def display(self): + pass + +class RealImage(Image): + def __init__(self, filename): + self.filename = filename + self.load_from_disk() + + def load_from_disk(self): + print(f" {self.filename}") + + def display(self): + print(f" {self.filename}") + +class ProxyImage(Image): + def __init__(self, filename): + self.filename = filename + self.real_image = None + + def display(self): + if not self.real_image: + self.real_image = RealImage(self.filename) + self.real_image.display() + +# +if __name__ == "__main__": + image = ProxyImage("photo.jpg") + image.display() # + image.display() # ( ) +EOF \ No newline at end of file diff --git a/patterns2/strategy.py b/patterns2/strategy.py index d3e2393..52a5f77 100644 --- a/patterns2/strategy.py +++ b/patterns2/strategy.py @@ -1,4 +1,37 @@ -class Strategy: - def execute(self): pass -class ConcreteStrategy(Strategy): - def execute(self): return "Стратегия" +cat > strategy.py << 'EOF' +class PaymentStrategy: + def pay(self, amount): + pass + +class CreditCardPayment(PaymentStrategy): + def pay(self, amount): + return f"Оплата {amount} руб. кредитной картой" + +class PayPalPayment(PaymentStrategy): + def pay(self, amount): + return f"Оплата {amount} руб. через PayPal" + +class ShoppingCart: + def __init__(self): + self.items = [] + self.strategy = None + + def set_payment_strategy(self, strategy): + self.strategy = strategy + + def add_item(self, item): + self.items.append(item) + + def checkout(self): + total = sum(self.items) + return self.strategy.pay(total) + +# Пример +if __name__ == "__main__": + cart = ShoppingCart() + cart.add_item(100) + cart.add_item(200) + + cart.set_payment_strategy(CreditCardPayment()) + print(cart.checkout()) +EOF \ No newline at end of file