knit-graphs 0.0.9__py3-none-any.whl → 0.0.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docs/source/conf.py +71 -71
- docs/source/index.rst +0 -4
- knit_graphs/Course.py +3 -1
- knit_graphs/Knit_Graph.py +80 -45
- knit_graphs/Knit_Graph_Visualizer.py +362 -149
- knit_graphs/Loop.py +77 -11
- knit_graphs/Pull_Direction.py +2 -0
- knit_graphs/Yarn.py +74 -12
- knit_graphs/artin_wale_braids/Crossing_Direction.py +2 -0
- knit_graphs/artin_wale_braids/Loop_Braid_Graph.py +26 -5
- knit_graphs/artin_wale_braids/Wale.py +74 -49
- knit_graphs/artin_wale_braids/Wale_Braid.py +1 -0
- knit_graphs/artin_wale_braids/Wale_Braid_Word.py +9 -8
- knit_graphs/artin_wale_braids/Wale_Group.py +79 -63
- knit_graphs/basic_knit_graph_generators.py +45 -10
- knit_graphs/py.typed +0 -0
- {knit_graphs-0.0.9.dist-info → knit_graphs-0.0.11.dist-info}/METADATA +3 -2
- {knit_graphs-0.0.9.dist-info → knit_graphs-0.0.11.dist-info}/RECORD +20 -19
- {knit_graphs-0.0.9.dist-info → knit_graphs-0.0.11.dist-info}/LICENSE +0 -0
- {knit_graphs-0.0.9.dist-info → knit_graphs-0.0.11.dist-info}/WHEEL +0 -0
docs/source/conf.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
Configuration file for the Sphinx documentation builder.
|
|
3
|
+
=============================================================================
|
|
4
|
+
SPHINX DOCUMENTATION CONFIGURATION
|
|
5
|
+
=============================================================================
|
|
6
|
+
This file configures how Sphinx generates documentation from your Python code.
|
|
7
|
+
For the full list of built-in configuration values, see:
|
|
8
|
+
https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
import os
|
|
@@ -19,17 +19,17 @@ from importlib.metadata import PackageNotFoundError, version
|
|
|
19
19
|
# Add the project root and source directory to Python path so Sphinx can import your modules
|
|
20
20
|
|
|
21
21
|
# Path to your source code (adjust if not using src/ layout)
|
|
22
|
-
sys.path.insert(0, os.path.abspath(
|
|
23
|
-
sys.path.insert(0, os.path.abspath(
|
|
24
|
-
sys.path.insert(0, os.path.abspath(
|
|
22
|
+
sys.path.insert(0, os.path.abspath("..")) # Project root
|
|
23
|
+
sys.path.insert(0, os.path.abspath("../src")) # Source directory
|
|
24
|
+
sys.path.insert(0, os.path.abspath(".")) # Docs directory
|
|
25
25
|
|
|
26
26
|
# =============================================================================
|
|
27
27
|
# PROJECT INFORMATION
|
|
28
28
|
# =============================================================================
|
|
29
29
|
|
|
30
|
-
project =
|
|
31
|
-
copyright = f
|
|
32
|
-
author =
|
|
30
|
+
project = "knit-graphs"
|
|
31
|
+
copyright = f"{datetime.now().year}, Megan Hofmann"
|
|
32
|
+
author = "Megan Hofmann"
|
|
33
33
|
|
|
34
34
|
try:
|
|
35
35
|
# Get version from installed package metadata
|
|
@@ -49,19 +49,17 @@ release = version
|
|
|
49
49
|
# Extensions to enable (these add functionality to Sphinx)
|
|
50
50
|
extensions = [
|
|
51
51
|
# Core Sphinx extensions
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
"sphinx.ext.autodoc", # Generate docs from docstrings
|
|
53
|
+
"sphinx.ext.autosummary", # Generate summary tables automatically
|
|
54
|
+
"sphinx.ext.viewcode", # Add [source] links to documentation
|
|
55
|
+
"sphinx.ext.napoleon", # Support Google/NumPy docstring styles
|
|
56
|
+
"sphinx.ext.intersphinx", # Link to other project docs (e.g., Python docs)
|
|
57
|
+
"sphinx.ext.githubpages", # Publish to GitHub Pages (.nojekyll file)
|
|
58
|
+
"sphinx.ext.todo", # Support TODO items in docs
|
|
59
|
+
"sphinx.ext.coverage", # Check documentation coverage
|
|
60
|
+
"sphinx.ext.doctest", # Test code snippets in documentation
|
|
62
61
|
# Third-party extensions (these need to be installed)
|
|
63
|
-
|
|
64
|
-
'myst_parser', # Support for Markdown files (optional)
|
|
62
|
+
"myst_parser", # Support for Markdown files (optional)
|
|
65
63
|
]
|
|
66
64
|
|
|
67
65
|
# =============================================================================
|
|
@@ -70,19 +68,19 @@ extensions = [
|
|
|
70
68
|
|
|
71
69
|
# File extensions that Sphinx will process
|
|
72
70
|
source_suffix = {
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
".rst": None, # RestructuredText (default)
|
|
72
|
+
".md": "myst_parser", # Markdown (requires myst_parser extension)
|
|
75
73
|
}
|
|
76
74
|
|
|
77
75
|
# The master toctree document (main page)
|
|
78
|
-
master_doc =
|
|
76
|
+
master_doc = "index"
|
|
79
77
|
|
|
80
78
|
# Files and directories to exclude from processing
|
|
81
79
|
exclude_patterns = [
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
"_build", # Build output directory
|
|
81
|
+
"Thumbs.db", # Windows thumbnail cache
|
|
82
|
+
".DS_Store", # macOS metadata
|
|
83
|
+
"**.ipynb_checkpoints", # Jupyter notebook checkpoints
|
|
86
84
|
]
|
|
87
85
|
|
|
88
86
|
# =============================================================================
|
|
@@ -90,31 +88,29 @@ exclude_patterns = [
|
|
|
90
88
|
# =============================================================================
|
|
91
89
|
|
|
92
90
|
# The theme to use for HTML pages
|
|
93
|
-
html_theme =
|
|
91
|
+
html_theme = "sphinx_rtd_theme" # Read the Docs theme (clean, professional)
|
|
94
92
|
|
|
95
93
|
# Directories containing static files (CSS, JS, images)
|
|
96
|
-
html_static_path = [
|
|
94
|
+
html_static_path = ["_static"]
|
|
97
95
|
|
|
98
96
|
|
|
99
97
|
# Theme-specific options
|
|
100
98
|
html_theme_options = {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
'style_nav_header_background': '#2980B9', # Header background color
|
|
107
|
-
|
|
99
|
+
"logo_only": False, # Show project name with logo
|
|
100
|
+
"prev_next_buttons_location": "bottom", # Navigation button placement
|
|
101
|
+
"style_external_links": True, # Style external links differently
|
|
102
|
+
"vcs_pageview_mode": "", # Version control integration
|
|
103
|
+
"style_nav_header_background": "#2980B9", # Header background color
|
|
108
104
|
# Table of contents options
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
105
|
+
"collapse_navigation": True, # Collapse subsections in nav
|
|
106
|
+
"sticky_navigation": True, # Keep navigation visible on scroll
|
|
107
|
+
"navigation_depth": 4, # Maximum navigation depth
|
|
108
|
+
"includehidden": True, # Include hidden toctrees
|
|
109
|
+
"titles_only": False, # Show subsection titles in nav
|
|
114
110
|
}
|
|
115
111
|
|
|
116
112
|
# Additional HTML options
|
|
117
|
-
html_title = f
|
|
113
|
+
html_title = f"{project} Documentation" # Browser window title
|
|
118
114
|
html_short_title = project # Short title for navigation
|
|
119
115
|
|
|
120
116
|
|
|
@@ -136,20 +132,20 @@ html_short_title = project # Short title for navigation
|
|
|
136
132
|
|
|
137
133
|
# Default options for all autodoc directives
|
|
138
134
|
autodoc_default_options = {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
135
|
+
"members": True, # Include all members
|
|
136
|
+
"member-order": "bysource", # Order members as they appear in source
|
|
137
|
+
"special-members": "__init__", # Include __init__ methods
|
|
138
|
+
"undoc-members": True, # Include members without docstrings
|
|
139
|
+
"exclude-members": "__weakref__", # Exclude certain members
|
|
140
|
+
"show-inheritance": True, # Show class inheritance
|
|
141
|
+
"inherited-members": True, # Include inherited methods
|
|
146
142
|
}
|
|
147
143
|
|
|
148
144
|
# How to display class signatures
|
|
149
145
|
autodoc_class_signature = "mixed" # Show __init__ parameters with class
|
|
150
146
|
|
|
151
147
|
# Order of members in documentation
|
|
152
|
-
autodoc_member_order =
|
|
148
|
+
autodoc_member_order = "bysource" # bysource, alphabetical, or groupwise
|
|
153
149
|
|
|
154
150
|
# Mock imports for modules that might not be available during doc building
|
|
155
151
|
# Add any modules that cause import errors during doc building
|
|
@@ -159,6 +155,10 @@ autodoc_mock_imports = [
|
|
|
159
155
|
# 'some_optional_dependency',
|
|
160
156
|
]
|
|
161
157
|
|
|
158
|
+
# Enable type hints in signatures
|
|
159
|
+
autodoc_typehints = "signature" # Show type hints in function signatures
|
|
160
|
+
autodoc_typehints_description_target = "documented" # Where to show type info
|
|
161
|
+
|
|
162
162
|
# =============================================================================
|
|
163
163
|
# AUTOSUMMARY CONFIGURATION
|
|
164
164
|
# =============================================================================
|
|
@@ -193,13 +193,13 @@ napoleon_attr_annotations = True # Include attribute annotations
|
|
|
193
193
|
# Links to external documentation
|
|
194
194
|
|
|
195
195
|
intersphinx_mapping = {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
196
|
+
"python": ("https://docs.python.org/3", None),
|
|
197
|
+
"numpy": ("https://numpy.org/doc/stable/", None),
|
|
198
|
+
"pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None),
|
|
199
|
+
"matplotlib": ("https://matplotlib.org/stable/", None),
|
|
200
|
+
"scipy": ("https://docs.scipy.org/doc/scipy/", None),
|
|
201
|
+
"sklearn": ("https://scikit-learn.org/stable/", None),
|
|
202
|
+
"typing": ("https://typing.readthedocs.io/en/latest/", None),
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
# =============================================================================
|
|
@@ -207,10 +207,8 @@ intersphinx_mapping = {
|
|
|
207
207
|
# =============================================================================
|
|
208
208
|
# Controls how type hints are displayed in documentation
|
|
209
209
|
|
|
210
|
-
|
|
210
|
+
# Note: These settings work with sphinx.ext.autodoc built-in type hint support
|
|
211
211
|
always_document_param_types = True # Always show parameter types
|
|
212
|
-
typehints_document_rtype = True # Document return types
|
|
213
|
-
typehints_use_rtype = True # Use :rtype: directive for return types
|
|
214
212
|
|
|
215
213
|
# =============================================================================
|
|
216
214
|
# TODO EXTENSION CONFIGURATION
|
|
@@ -245,16 +243,17 @@ add_module_names = False # Don't prepend module names to functions
|
|
|
245
243
|
show_authors = False # Don't show author info by default
|
|
246
244
|
|
|
247
245
|
# Syntax highlighting style
|
|
248
|
-
pygments_style =
|
|
246
|
+
pygments_style = "sphinx" # Code highlighting theme
|
|
249
247
|
|
|
250
248
|
# Language for content that doesn't specify a language
|
|
251
|
-
language =
|
|
249
|
+
language = "en"
|
|
252
250
|
|
|
253
251
|
|
|
254
252
|
# =============================================================================
|
|
255
253
|
# CUSTOM FUNCTIONS AND SETUP
|
|
256
254
|
# =============================================================================
|
|
257
255
|
|
|
256
|
+
|
|
258
257
|
def autodoc_skip_member(app, what, name, obj, skip, options):
|
|
259
258
|
"""
|
|
260
259
|
Custom function to control which members are included in documentation.
|
|
@@ -288,15 +287,16 @@ def setup(app):
|
|
|
288
287
|
app: The Sphinx application instance
|
|
289
288
|
"""
|
|
290
289
|
# Connect custom functions to Sphinx events
|
|
291
|
-
app.connect(
|
|
290
|
+
app.connect("autodoc-skip-member", autodoc_skip_member)
|
|
292
291
|
|
|
293
292
|
# Return extension metadata
|
|
294
293
|
return {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
294
|
+
"version": version,
|
|
295
|
+
"parallel_read_safe": True,
|
|
296
|
+
"parallel_write_safe": True,
|
|
298
297
|
}
|
|
299
298
|
|
|
299
|
+
|
|
300
300
|
# =============================================================================
|
|
301
301
|
# CHECKLIST FOR SPHINX SETUP
|
|
302
302
|
# =============================================================================
|
docs/source/index.rst
CHANGED
|
@@ -3,10 +3,6 @@ knit-graphs
|
|
|
3
3
|
|
|
4
4
|
A graph representation of knitted structures where each loop is a node and edges represent yarn and stitch relationships.
|
|
5
5
|
|
|
6
|
-
.. image:: https://img.shields.io/github/workflow/status/mhofmann-Khoury/knit-graphs/CI
|
|
7
|
-
:target: https://github.com/mhofmann-Khoury/knit-graphs/actions
|
|
8
|
-
:alt: Build Status
|
|
9
|
-
|
|
10
6
|
.. image:: https://img.shields.io/pypi/v/knit-graphs
|
|
11
7
|
:target: https://pypi.org/project/knit-graphs/
|
|
12
8
|
:alt: PyPI Version
|
knit_graphs/Course.py
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
This module contains the Course class which represents a horizontal row of loops in a knitting pattern.
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
from __future__ import annotations
|
|
6
7
|
|
|
7
|
-
from
|
|
8
|
+
from collections.abc import Iterator
|
|
9
|
+
from typing import TYPE_CHECKING, cast
|
|
8
10
|
|
|
9
11
|
from knit_graphs.Loop import Loop
|
|
10
12
|
|
knit_graphs/Knit_Graph.py
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
This module contains the main Knit_Graph class which serves as the central data structure for representing knitted fabrics.
|
|
4
4
|
It manages the relationships between loops, yarns, and structural elements like courses and wales.
|
|
5
5
|
"""
|
|
6
|
+
|
|
6
7
|
from __future__ import annotations
|
|
7
8
|
|
|
8
|
-
from
|
|
9
|
+
from collections.abc import Iterator
|
|
10
|
+
from typing import Any, cast
|
|
9
11
|
|
|
10
12
|
from networkx import DiGraph
|
|
11
13
|
|
|
@@ -18,9 +20,6 @@ from knit_graphs.Loop import Loop
|
|
|
18
20
|
from knit_graphs.Pull_Direction import Pull_Direction
|
|
19
21
|
from knit_graphs.Yarn import Yarn
|
|
20
22
|
|
|
21
|
-
# from knit_graphs.artin_wale_braids.Wale import Wale
|
|
22
|
-
# from knit_graphs.artin_wale_braids.Wale_Group import Wale_Group
|
|
23
|
-
|
|
24
23
|
|
|
25
24
|
class Knit_Graph:
|
|
26
25
|
"""A representation of knitted structures as connections between loops on yarns.
|
|
@@ -77,6 +76,42 @@ class Knit_Graph:
|
|
|
77
76
|
if self._last_loop is None or loop > self._last_loop:
|
|
78
77
|
self._last_loop = loop
|
|
79
78
|
|
|
79
|
+
def remove_loop(self, loop: Loop) -> None:
|
|
80
|
+
"""
|
|
81
|
+
Remove the given loop from the knit graph.
|
|
82
|
+
Args:
|
|
83
|
+
loop (Loop): The loop to be removed.
|
|
84
|
+
|
|
85
|
+
Raises:
|
|
86
|
+
KeyError: If the loop is not in the knit graph.
|
|
87
|
+
|
|
88
|
+
"""
|
|
89
|
+
if loop not in self:
|
|
90
|
+
raise KeyError(f"Loop {loop} not on the knit graph")
|
|
91
|
+
self.braid_graph.remove_loop(loop) # remove any crossing associated with this loop.
|
|
92
|
+
# Remove any stitch edges involving this loop.
|
|
93
|
+
loop.remove_parent_loops()
|
|
94
|
+
if self.has_child_loop(loop):
|
|
95
|
+
child_loop = self.get_child_loop(loop)
|
|
96
|
+
assert isinstance(child_loop, Loop)
|
|
97
|
+
child_loop.remove_parent(loop)
|
|
98
|
+
self.stitch_graph.remove_node(loop)
|
|
99
|
+
# Remove loop from any floating positions
|
|
100
|
+
loop.remove_loop_from_front_floats()
|
|
101
|
+
loop.remove_loop_from_back_floats()
|
|
102
|
+
# Remove loop from yarn
|
|
103
|
+
yarn = loop.yarn
|
|
104
|
+
yarn.remove_loop(loop)
|
|
105
|
+
if len(yarn) == 0: # This was the only loop on that yarn
|
|
106
|
+
self.yarns.discard(yarn)
|
|
107
|
+
# Reset last loop
|
|
108
|
+
if loop is self.last_loop:
|
|
109
|
+
if len(self.yarns) == 0: # No loops left
|
|
110
|
+
assert len(self.stitch_graph.nodes) == 0
|
|
111
|
+
self._last_loop = None
|
|
112
|
+
else: # Set to the newest loop formed at the end of any yarns.
|
|
113
|
+
self._last_loop = max(y.last_loop for y in self.yarns if isinstance(y.last_loop, Loop))
|
|
114
|
+
|
|
80
115
|
def add_yarn(self, yarn: Yarn) -> None:
|
|
81
116
|
"""Add a yarn to the graph without adding its loops.
|
|
82
117
|
|
|
@@ -85,9 +120,13 @@ class Knit_Graph:
|
|
|
85
120
|
"""
|
|
86
121
|
self.yarns.add(yarn)
|
|
87
122
|
|
|
88
|
-
def connect_loops(
|
|
89
|
-
|
|
90
|
-
|
|
123
|
+
def connect_loops(
|
|
124
|
+
self,
|
|
125
|
+
parent_loop: Loop,
|
|
126
|
+
child_loop: Loop,
|
|
127
|
+
pull_direction: Pull_Direction = Pull_Direction.BtF,
|
|
128
|
+
stack_position: int | None = None,
|
|
129
|
+
) -> None:
|
|
91
130
|
"""Create a stitch edge by connecting a parent and child loop.
|
|
92
131
|
|
|
93
132
|
Args:
|
|
@@ -106,44 +145,31 @@ class Knit_Graph:
|
|
|
106
145
|
self.stitch_graph.add_edge(parent_loop, child_loop, pull_direction=pull_direction)
|
|
107
146
|
child_loop.add_parent_loop(parent_loop, stack_position)
|
|
108
147
|
|
|
109
|
-
def
|
|
110
|
-
"""Get
|
|
148
|
+
def get_wales_ending_with_loop(self, last_loop: Loop) -> set[Wale]:
|
|
149
|
+
"""Get all wales (vertical columns of stitches) that end at the specified loop.
|
|
111
150
|
|
|
112
151
|
Args:
|
|
113
|
-
|
|
152
|
+
last_loop (Loop): The last loop of the joined set of wales.
|
|
114
153
|
|
|
115
154
|
Returns:
|
|
116
|
-
Wale:
|
|
155
|
+
set[Wale]: The set of wales that end at this loop.
|
|
117
156
|
"""
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
assert isinstance(wale.last_loop, Loop)
|
|
123
|
-
wale.add_loop_to_end(cur_loop, self.get_pull_direction(wale.last_loop, cur_loop))
|
|
124
|
-
return wale
|
|
125
|
-
|
|
126
|
-
def get_wales_ending_with_loop(self, last_loop: Loop) -> list[Wale]:
|
|
127
|
-
"""Get all wales (vertical columns of stitches) that end at the specified loop.
|
|
157
|
+
if len(last_loop.parent_loops) == 0:
|
|
158
|
+
return {Wale(last_loop, self)}
|
|
159
|
+
ancestors = last_loop.ancestor_loops()
|
|
160
|
+
return {Wale(ancestor_loop, self) for ancestor_loop in ancestors}
|
|
128
161
|
|
|
129
|
-
|
|
130
|
-
|
|
162
|
+
def get_terminal_wales(self) -> dict[Loop, list[Wale]]:
|
|
163
|
+
"""
|
|
164
|
+
Get wale groups organized by their terminal loops.
|
|
131
165
|
|
|
132
166
|
Returns:
|
|
133
|
-
list[Wale]:
|
|
167
|
+
dict[Loop, list[Wale]]: Dictionary mapping terminal loops to list of wales that terminate that wale.
|
|
134
168
|
"""
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
wale = Wale(last_loop)
|
|
140
|
-
wale.add_loop_to_beginning(top_stitch_parent, cast(Pull_Direction, self.get_pull_direction(top_stitch_parent, last_loop)))
|
|
141
|
-
cur_loop = top_stitch_parent
|
|
142
|
-
while len(cur_loop.parent_loops) == 1: # stop at split for decrease or start of wale
|
|
143
|
-
cur_loop = cur_loop.parent_loops[0]
|
|
144
|
-
wale.add_loop_to_beginning(cur_loop, cast(Pull_Direction, self.get_pull_direction(cur_loop, cast(Loop, wale.first_loop))))
|
|
145
|
-
wales.append(wale)
|
|
146
|
-
return wales
|
|
169
|
+
wale_groups = {}
|
|
170
|
+
for loop in self.terminal_loops():
|
|
171
|
+
wale_groups[loop] = list(self.get_wales_ending_with_loop(loop))
|
|
172
|
+
return wale_groups
|
|
147
173
|
|
|
148
174
|
def get_courses(self) -> list[Course]:
|
|
149
175
|
"""Get all courses (horizontal rows) in the knit graph in chronological order.
|
|
@@ -164,17 +190,13 @@ class Knit_Graph:
|
|
|
164
190
|
courses.append(course)
|
|
165
191
|
return courses
|
|
166
192
|
|
|
167
|
-
def get_wale_groups(self) ->
|
|
193
|
+
def get_wale_groups(self) -> set[Wale_Group]:
|
|
168
194
|
"""Get wale groups organized by their terminal loops.
|
|
169
195
|
|
|
170
196
|
Returns:
|
|
171
|
-
|
|
197
|
+
set[Wale_Group]: The set of wale-groups that lead to the terminal loops of this graph. Each wale group represents a collection of wales that end at the same terminal loop.
|
|
172
198
|
"""
|
|
173
|
-
|
|
174
|
-
for loop in self:
|
|
175
|
-
if self.is_terminal_loop(loop):
|
|
176
|
-
wale_groups.update({loop: Wale_Group(wale, self) for wale in self.get_wales_ending_with_loop(loop)})
|
|
177
|
-
return wale_groups
|
|
199
|
+
return {Wale_Group(terminal_loop, self) for terminal_loop in self.terminal_loops()}
|
|
178
200
|
|
|
179
201
|
def __contains__(self, item: Loop | tuple[Loop, Loop]) -> bool:
|
|
180
202
|
"""Check if a loop is contained in the knit graph.
|
|
@@ -197,12 +219,18 @@ class Knit_Graph:
|
|
|
197
219
|
"""
|
|
198
220
|
return cast(Iterator[Loop], iter(self.stitch_graph.nodes))
|
|
199
221
|
|
|
222
|
+
def __getitem__(self, item: int) -> Loop:
|
|
223
|
+
loop = next((loop for loop in self if loop.loop_id == item), None)
|
|
224
|
+
if loop is None:
|
|
225
|
+
raise KeyError(f"Loop of id {item} not in knit graph")
|
|
226
|
+
return loop
|
|
227
|
+
|
|
200
228
|
def sorted_loops(self) -> list[Loop]:
|
|
201
229
|
"""
|
|
202
230
|
Returns:
|
|
203
231
|
list[Loop]: The list of loops in the stitch graph sorted from the earliest formed loop to the latest formed loop.
|
|
204
232
|
"""
|
|
205
|
-
return sorted(
|
|
233
|
+
return sorted(self.stitch_graph.nodes)
|
|
206
234
|
|
|
207
235
|
def get_pull_direction(self, parent: Loop, child: Loop) -> Pull_Direction | None:
|
|
208
236
|
"""Get the pull direction of the stitch edge between parent and child loops.
|
|
@@ -218,7 +246,7 @@ class Knit_Graph:
|
|
|
218
246
|
if edge is None:
|
|
219
247
|
return None
|
|
220
248
|
else:
|
|
221
|
-
return cast(Pull_Direction, edge[
|
|
249
|
+
return cast(Pull_Direction, edge["pull_direction"])
|
|
222
250
|
|
|
223
251
|
def get_stitch_edge(self, parent: Loop, child: Loop) -> dict[str, Any] | None:
|
|
224
252
|
"""Get the stitch edge data between two loops.
|
|
@@ -270,3 +298,10 @@ class Knit_Graph:
|
|
|
270
298
|
bool: True if the loop has no child loops and terminates a wale, False otherwise.
|
|
271
299
|
"""
|
|
272
300
|
return not self.has_child_loop(loop)
|
|
301
|
+
|
|
302
|
+
def terminal_loops(self) -> Iterator[Loop]:
|
|
303
|
+
"""
|
|
304
|
+
Returns:
|
|
305
|
+
Iterator[Loop]: An iterator over all terminal loops in the knit graph.
|
|
306
|
+
"""
|
|
307
|
+
return iter(loop for loop in self if self.is_terminal_loop(loop))
|