From 6154f327d1eda38d3bd8cc3ea56509afa31795c3 Mon Sep 17 00:00:00 2001 From: ada1ra Date: Thu, 27 Nov 2025 23:40:17 +0300 Subject: [PATCH 1/2] Add file for ruff --- pyproject.toml | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b477208 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,78 @@ +# ruff.toml +target-version = "py311" +line-length = 100 + +# включить все основные правила +select = [ + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # Pyflakes + "I", # isort + "N", # pep8-naming + "UP", # pyupgrade + "YTT", # flake8-2020 + "S", # flake8-bandit + "A", # flake8-builtins + "COM", # flake8-commas + "C4", # flake8-comprehensions + "DTZ", # flake8-datetimez + "T10", # flake8-debugger + "EM", # flake8-errmsg + "EXE", # flake8-executable + "ISC", # flake8-implicit-str-concat + "ICN", # flake8-import-conventions + "G", # flake8-logging-format + "INP", # flake8-no-pep420 + "PIE", # flake8-pie + "T20", # flake8-print + "PYI", # flake8-pyi + "PT", # flake8-pytest-style + "Q", # flake8-quotes + "RSE", # flake8-raise + "RET", # flake8-return + "SLF", # flake8-self + "SIM", # flake8-simplify + "TID", # flake8-tidy-imports + "TCH", # flake8-type-checking + "INT", # flake8-gettext + "ARG", # flake8-unused-arguments + "FBT", # flake8-boolean-trap + "B", # flake8-bugbear + "AIR", # flake8-airflow + "PERF", # flake8-perflint +] + +# игнорировать правила +ignore = [ + "E501", # line too long - handled by formatter + "S101", # assert used - ok in tests + "T201", # print found - sometimes needed + "COM812", # trailing comma missing - not always required +] + +# настройки для конкретных файлов +[per-file-ignores] +"__init__.py" = ["F401"] # Unused imports allowed in __init__.py +"tests/**" = ["S101", "SLF001"] # Allow assert and self in tests +"**/migrations/**" = ["ALL"] # Ignore all in migrations + +# настройки форматтера +[format] +indent-style = "space" +quote-style = "double" +skip-magic-trailing-comma = false +line-ending = "auto" + +# настройки для конкретных правил +[flake8-quotes] +docstring-quotes = "double" +inline-quotes = "double" + +[flake8-tidy-imports] +ban-relative-imports = "all" + +[isort] +known-first-party = ["myapp"] +lines-after-imports = 2 +combine-as-imports = true +split-on-trailing-comma = true From f51abef957c3683293c36e98b3bef329b0708932 Mon Sep 17 00:00:00 2001 From: ada1ra Date: Thu, 27 Nov 2025 23:40:50 +0300 Subject: [PATCH 2/2] Add homework 10 with DFS --- src/hw_10_dfs/hw_10_dfs.py | 98 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 src/hw_10_dfs/hw_10_dfs.py diff --git a/src/hw_10_dfs/hw_10_dfs.py b/src/hw_10_dfs/hw_10_dfs.py new file mode 100644 index 0000000..51454f9 --- /dev/null +++ b/src/hw_10_dfs/hw_10_dfs.py @@ -0,0 +1,98 @@ +class Graph: + + # МЕТОДЫ СОЗДАНИЯ ГРАФА + + def __init__(self): + """Инициализация неориентированного графа""" + self.connections_list = {} + + def add_vertex(self, vertex): + """Добавление вершины в граф""" + if vertex not in self.connections_list: + self.connections_list[vertex] = [] + + def add_edge(self, vertex1, vertex2): + """Добавление ребра""" + # добавляем вершины, если их нет + self.add_vertex(vertex1) + self.add_vertex(vertex2) + + # добавляем связи в обе стороны + if vertex2 not in self.connections_list[vertex1]: + self.connections_list[vertex1].append(vertex2) + if vertex1 not in self.connections_list[vertex2]: + self.connections_list[vertex2].append(vertex1) + + # РЕАЛИЗАЦИЯ ПРОТОКОЛОВ ИНТЕРФЕЙСОВ + + def __iter__(self): + """Делает граф итерируемым""" + self._dfs_order = self.dfs() + self._index = 0 + return self + + def __next__(self): + """Возвращает следующую вершину при итерации""" + if self._index < len(self._dfs_order): + vertex = self._dfs_order[self._index] + self._index += 1 + return vertex + raise StopIteration + + def __str__(self): + """Строковое представление""" + result = [] + for vertex, neighbors in self.connections_list.items(): + result.append(f"{vertex}: {neighbors}") + return "\n".join(result) + + def __contains__(self, vertex): + """Проверка наличия вершины""" + return vertex in self.connections_list + + # ДОПОЛНИТЕЛЬНЫЕ МЕТОДЫ ДЛЯ РАБОТЫ С ГРАФОМ + + def get_vertices(self): + """Возвращает список всех вершин""" + return list(self.connections_list.keys()) + + def get_edges(self): + """Возвращает список всех рёбер""" + edges = set() + for vertex, neighbors in self.connections_list.items(): + for neighbor in neighbors: + edge = tuple(sorted((vertex, neighbor))) + edges.add(edge) + + return list(edges) + + # ОСНОВНОЕ ЗАДАНИЕ + + def dfs(self, start_vertex=None): + """ + Обход графа в глубину | Depth-first search | DFS + """ + if not self.connections_list: + return [] + + # если none, берём 1-ую вершину из словаря + if start_vertex is None: + start_vertex = next(iter(self.connections_list)) + + # проверяем существование начальной вершины + if start_vertex not in self.connections_list: + raise ValueError(f"Вершина {start_vertex} не существует в графе") + + visited = [] # посещённые вершины + stack = [start_vertex] # вершины, которые необходимо обработать + + while stack: + vertex = stack.pop() + if vertex not in visited: + visited.append(vertex) + # добавляем в обратном порядке для сохранения естественного порядка + for neighbor in reversed(self.connections_list[vertex]): + if neighbor not in visited: + stack.append(neighbor) + + return visited