knit-graphs 0.0.10__py3-none-any.whl → 0.0.12__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 +64 -41
- knit_graphs/Knit_Graph.py +70 -162
- knit_graphs/Knit_Graph_Visualizer.py +386 -185
- knit_graphs/Loop.py +124 -117
- knit_graphs/Pull_Direction.py +5 -2
- knit_graphs/Yarn.py +257 -219
- knit_graphs/artin_wale_braids/Crossing_Direction.py +2 -0
- knit_graphs/artin_wale_braids/Loop_Braid_Graph.py +47 -56
- knit_graphs/artin_wale_braids/Wale.py +67 -79
- knit_graphs/artin_wale_braids/Wale_Braid.py +8 -2
- knit_graphs/artin_wale_braids/Wale_Braid_Word.py +45 -31
- knit_graphs/artin_wale_braids/Wale_Group.py +53 -43
- knit_graphs/basic_knit_graph_generators.py +96 -140
- knit_graphs/directed_loop_graph.py +454 -0
- knit_graphs/knit_graph_builder.py +187 -0
- knit_graphs/knit_graph_errors/__init__.py +0 -0
- knit_graphs/knit_graph_errors/knit_graph_error.py +30 -0
- knit_graphs/py.typed +0 -0
- {knit_graphs-0.0.10.dist-info → knit_graphs-0.0.12.dist-info}/METADATA +3 -2
- {knit_graphs-0.0.10.dist-info → knit_graphs-0.0.12.dist-info}/RECORD +24 -19
- {knit_graphs-0.0.10.dist-info → knit_graphs-0.0.12.dist-info}/LICENSE +0 -0
- {knit_graphs-0.0.10.dist-info → knit_graphs-0.0.12.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,35 +2,48 @@
|
|
|
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, Sequence
|
|
9
|
+
from typing import TYPE_CHECKING, Generic, TypeVar, overload
|
|
8
10
|
|
|
9
11
|
from knit_graphs.Loop import Loop
|
|
10
12
|
|
|
11
13
|
if TYPE_CHECKING:
|
|
12
14
|
from knit_graphs.Knit_Graph import Knit_Graph
|
|
13
15
|
|
|
16
|
+
LoopT = TypeVar("LoopT", bound=Loop)
|
|
17
|
+
|
|
14
18
|
|
|
15
|
-
class Course:
|
|
19
|
+
class Course(Sequence[LoopT], Generic[LoopT]):
|
|
16
20
|
"""Course object for organizing loops into knitting rows.
|
|
17
21
|
|
|
18
22
|
A Course represents a horizontal row of loops in a knitting pattern.
|
|
19
23
|
It maintains an ordered list of loops and provides methods for analyzing the structure and relationships between courses in the knitted fabric.
|
|
20
24
|
"""
|
|
21
25
|
|
|
22
|
-
def __init__(self, knit_graph: Knit_Graph) -> None:
|
|
26
|
+
def __init__(self, course_number: int, knit_graph: Knit_Graph[LoopT]) -> None:
|
|
23
27
|
"""Initialize an empty course associated with a knit graph.
|
|
24
28
|
|
|
25
29
|
Args:
|
|
26
30
|
knit_graph (Knit_Graph): The knit graph that this course belongs to.
|
|
27
31
|
"""
|
|
28
|
-
self.
|
|
29
|
-
self.
|
|
30
|
-
self.
|
|
32
|
+
self._course_number: int = course_number
|
|
33
|
+
self._knit_graph: Knit_Graph[LoopT] = knit_graph
|
|
34
|
+
self._loops_in_order: list[LoopT] = []
|
|
35
|
+
self._loop_set: set[LoopT] = set()
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def course_number(self) -> int:
|
|
39
|
+
"""
|
|
40
|
+
Returns:
|
|
41
|
+
int: The course number of the course.
|
|
42
|
+
"""
|
|
43
|
+
return self._course_number
|
|
31
44
|
|
|
32
45
|
@property
|
|
33
|
-
def loops_in_order(self) -> list[
|
|
46
|
+
def loops_in_order(self) -> list[LoopT]:
|
|
34
47
|
"""
|
|
35
48
|
Returns:
|
|
36
49
|
list[Loop]: The list of loops in this course.
|
|
@@ -38,22 +51,34 @@ class Course:
|
|
|
38
51
|
return self._loops_in_order
|
|
39
52
|
|
|
40
53
|
@property
|
|
41
|
-
def
|
|
54
|
+
def loop_ids_in_course(self) -> list[int]:
|
|
55
|
+
"""
|
|
56
|
+
Returns:
|
|
57
|
+
list[int]: The loop ids in the course in the order the occur in the course.
|
|
58
|
+
"""
|
|
59
|
+
return [l.loop_id for l in self.loops_in_order]
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def knit_graph(self) -> Knit_Graph[LoopT]:
|
|
42
63
|
"""
|
|
43
64
|
Returns:
|
|
44
65
|
Knit_Graph: The knit graph that this course belongs to.
|
|
45
66
|
"""
|
|
46
67
|
return self._knit_graph
|
|
47
68
|
|
|
48
|
-
def add_loop(self, loop:
|
|
69
|
+
def add_loop(self, loop: LoopT, index: int | None = None) -> None:
|
|
49
70
|
"""Add a loop to the course at the specified index or at the end.
|
|
50
71
|
|
|
51
72
|
Args:
|
|
52
73
|
loop (Loop): The loop to add to this course.
|
|
53
74
|
index (int | None, optional): The index position to insert the loop at. If None, appends to the end.
|
|
75
|
+
|
|
76
|
+
Raises:
|
|
77
|
+
ValueError: If the loop is a parent to any loops already in the course.
|
|
54
78
|
"""
|
|
55
79
|
for parent_loop in loop.parent_loops:
|
|
56
|
-
|
|
80
|
+
if parent_loop in self:
|
|
81
|
+
raise ValueError(f"{loop} has parent {parent_loop}, cannot be added to same course")
|
|
57
82
|
self._loop_set.add(loop)
|
|
58
83
|
if index is None:
|
|
59
84
|
self.loops_in_order.append(loop)
|
|
@@ -66,7 +91,7 @@ class Course:
|
|
|
66
91
|
Returns:
|
|
67
92
|
bool: True if the course has at least one yarn over (loop with no parent loops) to start new wales.
|
|
68
93
|
"""
|
|
69
|
-
return any(not loop.has_parent_loops
|
|
94
|
+
return any(not loop.has_parent_loops for loop in self)
|
|
70
95
|
|
|
71
96
|
def has_decrease(self) -> bool:
|
|
72
97
|
"""Check if this course contains any decrease stitches that merge wales.
|
|
@@ -76,18 +101,7 @@ class Course:
|
|
|
76
101
|
"""
|
|
77
102
|
return any(len(loop.parent_loops) > 1 for loop in self)
|
|
78
103
|
|
|
79
|
-
def
|
|
80
|
-
"""Get loop(s) at the specified index or slice.
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
index (int | slice): The index or slice to retrieve from the course.
|
|
84
|
-
|
|
85
|
-
Returns:
|
|
86
|
-
Loop | list[Loop]: The loop at the specified index, or list of loops for a slice.
|
|
87
|
-
"""
|
|
88
|
-
return self.loops_in_order[index]
|
|
89
|
-
|
|
90
|
-
def in_round_with(self, next_course: Course) -> bool:
|
|
104
|
+
def in_round_with(self, next_course: Course[LoopT]) -> bool:
|
|
91
105
|
"""Check if the next course connects to this course in a circular pattern.
|
|
92
106
|
|
|
93
107
|
This method determines if the courses are connected in the round (circular knitting) by checking if the next course starts at the beginning of this course.
|
|
@@ -98,14 +112,14 @@ class Course:
|
|
|
98
112
|
Returns:
|
|
99
113
|
bool: True if the next course starts at the beginning of this course, indicating circular knitting.
|
|
100
114
|
"""
|
|
101
|
-
next_start
|
|
115
|
+
next_start = next_course[0]
|
|
102
116
|
i = 1
|
|
103
|
-
while not next_start.has_parent_loops
|
|
104
|
-
next_start =
|
|
117
|
+
while not next_start.has_parent_loops:
|
|
118
|
+
next_start = next_course[i]
|
|
105
119
|
i += 1
|
|
106
120
|
return self[0] in next_start.parent_loops
|
|
107
121
|
|
|
108
|
-
def in_row_with(self, next_course: Course) -> bool:
|
|
122
|
+
def in_row_with(self, next_course: Course[LoopT]) -> bool:
|
|
109
123
|
"""Check if the next course connects to this course in a flat/row pattern.
|
|
110
124
|
|
|
111
125
|
This method determines if the courses are connected in flat knitting (back and forth) by checking if the next course starts at the end of this course.
|
|
@@ -116,39 +130,48 @@ class Course:
|
|
|
116
130
|
Returns:
|
|
117
131
|
bool: True if the next course starts at the end of this course, indicating flat/row knitting.
|
|
118
132
|
"""
|
|
119
|
-
next_start:
|
|
133
|
+
next_start: LoopT = next_course[0]
|
|
120
134
|
i = 1
|
|
121
|
-
while not next_start.has_parent_loops
|
|
122
|
-
next_start =
|
|
135
|
+
while not next_start.has_parent_loops:
|
|
136
|
+
next_start = next_course[i]
|
|
123
137
|
i += 1
|
|
124
138
|
return self[-1] in next_start.parent_loops
|
|
125
139
|
|
|
126
|
-
def __contains__(self, loop:
|
|
140
|
+
def __contains__(self, loop: object) -> bool:
|
|
127
141
|
"""Check if a loop is contained in this course.
|
|
128
142
|
|
|
129
143
|
Args:
|
|
130
|
-
loop (
|
|
144
|
+
loop (LoopT): The loop to check for membership in this course.
|
|
131
145
|
|
|
132
146
|
Returns:
|
|
133
147
|
bool: True if the loop is in this course, False otherwise.
|
|
134
148
|
"""
|
|
135
149
|
return loop in self._loop_set
|
|
136
150
|
|
|
137
|
-
|
|
138
|
-
|
|
151
|
+
@overload
|
|
152
|
+
def __getitem__(self, index: int) -> LoopT: ...
|
|
153
|
+
|
|
154
|
+
@overload
|
|
155
|
+
def __getitem__(self, index: slice) -> list[LoopT]: ...
|
|
156
|
+
|
|
157
|
+
def __getitem__(self, index: int | slice) -> LoopT | list[LoopT]:
|
|
158
|
+
"""Get loop(s) at the specified index or slice.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
index (int | slice): The index or slice to retrieve from the course.
|
|
139
162
|
|
|
140
163
|
Returns:
|
|
141
|
-
|
|
164
|
+
Loop | list[Loop]: The loop at the specified index, or list of loops for a slice.
|
|
142
165
|
"""
|
|
143
|
-
return
|
|
166
|
+
return self.loops_in_order[index]
|
|
144
167
|
|
|
145
|
-
def
|
|
146
|
-
"""Iterate over loops in this course in
|
|
168
|
+
def __iter__(self) -> Iterator[LoopT]:
|
|
169
|
+
"""Iterate over loops in this course in order.
|
|
147
170
|
|
|
148
171
|
Returns:
|
|
149
|
-
Iterator[Loop]: An iterator over the loops in this course in
|
|
172
|
+
Iterator[Loop]: An iterator over the loops in this course in their natural order.
|
|
150
173
|
"""
|
|
151
|
-
return
|
|
174
|
+
return iter(self.loops_in_order)
|
|
152
175
|
|
|
153
176
|
def __len__(self) -> int:
|
|
154
177
|
"""Get the number of loops in this course.
|
|
@@ -164,7 +187,7 @@ class Course:
|
|
|
164
187
|
Returns:
|
|
165
188
|
str: String representation showing the ordered list of loops.
|
|
166
189
|
"""
|
|
167
|
-
return
|
|
190
|
+
return f"Course {self.course_number}: {self.loops_in_order}"
|
|
168
191
|
|
|
169
192
|
def __repr__(self) -> str:
|
|
170
193
|
"""Get string representation of this course for debugging.
|