universal-mcp 0.1.21rc2__py3-none-any.whl → 0.1.22__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.
@@ -40,8 +40,6 @@ def parse_docstring(docstring: str | None) -> dict[str, Any]:
40
40
  current_key: str | None = None
41
41
  current_desc_lines: list[str] = []
42
42
 
43
- # Pattern to capture item key and the start of its description
44
- # Matches "key:" or "key (type):" followed by description
45
43
  key_pattern = re.compile(r"^\s*([\w\.]+)\s*(?:\(.*\))?:\s*(.*)")
46
44
 
47
45
  def finalize_current_item():
@@ -56,12 +54,11 @@ def parse_docstring(docstring: str | None) -> dict[str, Any]:
56
54
  if desc:
57
55
  raises[current_key] = desc
58
56
  elif current_section == "returns":
59
- returns = desc
57
+ if desc:
58
+ returns = desc
60
59
  elif current_section == "tags":
61
- # Tags section content is treated as a comma-separated list
62
- tags.clear() # Clear existing tags in case of multiple tag sections (unlikely but safe)
60
+ tags.clear()
63
61
  tags.extend([tag.strip() for tag in desc.split(",") if tag.strip()])
64
- # 'other' sections are ignored in the final output
65
62
 
66
63
  def check_for_section_header(line: str) -> tuple[bool, str | None, str]:
67
64
  """Checks if a line is a recognized section header."""
@@ -77,21 +74,17 @@ def parse_docstring(docstring: str | None) -> dict[str, Any]:
77
74
  section_type = "raises"
78
75
  elif stripped_lower in ("tags:",):
79
76
  section_type = "tags"
80
- # Allow "Raises Description:" or "Tags content:"
81
77
  elif stripped_lower.startswith(("raises ", "errors ", "exceptions ")):
82
78
  section_type = "raises"
83
- # Capture content after header word and potential colon/space
84
- parts = re.split(r"[:\s]+", line.strip(), maxsplit=1) # B034: Use keyword maxsplit
79
+ parts = re.split(r"[:\s]+", line.strip(), maxsplit=1)
85
80
  if len(parts) > 1:
86
81
  header_content = parts[1].strip()
87
82
  elif stripped_lower.startswith(("tags",)):
88
83
  section_type = "tags"
89
- # Capture content after header word and potential colon/space
90
- parts = re.split(r"[:\s]+", line.strip(), maxsplit=1) # B034: Use keyword maxsplit
84
+ parts = re.split(r"[:\s]+", line.strip(), maxsplit=1)
91
85
  if len(parts) > 1:
92
86
  header_content = parts[1].strip()
93
87
 
94
- # Identify other known sections, but don't store their content
95
88
  elif stripped_lower.endswith(":") and stripped_lower[:-1] in (
96
89
  "attributes",
97
90
  "see also",
@@ -112,38 +105,22 @@ def parse_docstring(docstring: str | None) -> dict[str, Any]:
112
105
  for line in lines:
113
106
  stripped_line = line.strip()
114
107
  original_indentation = len(line) - len(line.lstrip(" "))
115
-
116
108
  is_new_section_header, new_section_type_this_line, header_content_this_line = check_for_section_header(line)
117
-
118
109
  should_finalize_previous = False
119
110
 
120
- # --- Summary Handling ---
121
111
  if in_summary:
122
112
  if not stripped_line or is_new_section_header:
123
- # Empty line or section header marks the end of the summary
124
113
  in_summary = False
125
114
  summary = " ".join(summary_lines).strip()
126
- summary_lines = [] # Clear summary_lines after finalizing summary
115
+ summary_lines = []
127
116
 
128
117
  if not stripped_line:
129
- # If the line was just empty, continue to the next line
130
- # The new_section_header check will happen on the next iteration if it exists
131
118
  continue
132
- # If it was a header, fall through to section handling below
133
119
 
134
120
  else:
135
- # Still in summary, append line
136
121
  summary_lines.append(stripped_line)
137
- continue # Process next line
138
-
139
- # --- Section and Item Handling ---
122
+ continue
140
123
 
141
- # Decide if the previous item/section block should be finalized BEFORE processing the current line
142
- # Finalize if:
143
- # 1. A new section header is encountered.
144
- # 2. An empty line is encountered AFTER we've started collecting content for an item or section.
145
- # 3. In 'args' or 'raises', we encounter a line that looks like a new key: value pair, or a non-indented line.
146
- # 4. In 'returns', 'tags', or 'other', we encounter a non-indented line after collecting content.
147
124
  if (
148
125
  is_new_section_header
149
126
  or (not stripped_line and (current_desc_lines or current_key is not None))
@@ -160,20 +137,16 @@ def parse_docstring(docstring: str | None) -> dict[str, Any]:
160
137
  )
161
138
  ):
162
139
  should_finalize_previous = True
163
- elif current_section in ["args", "raises"] and current_key is not None:
164
- # Inside args/raises, processing an item (current_key is set)
165
- pass # Logic moved to the combined if statement
166
- elif current_section in ["returns", "tags", "other"] and current_desc_lines:
167
- # Inside returns/tags/other, collecting description lines
168
- pass # Logic moved to the combined if statement
169
-
170
- # If finalizing the previous item/section
140
+ elif (
141
+ current_section in ["args", "raises"]
142
+ and current_key is not None
143
+ or current_section in ["returns", "tags", "other"]
144
+ and current_desc_lines
145
+ ):
146
+ pass
147
+
171
148
  if should_finalize_previous:
172
149
  finalize_current_item()
173
- # Reset state after finalizing the previous item/section block
174
- # If it was a new section header, reset everything
175
- # If it was an end-of-item/block signal within a section, reset key and description lines
176
- # (The condition for resetting key here is complex but matches the original logic)
177
150
  if is_new_section_header or (
178
151
  current_section in ["args", "raises"]
179
152
  and current_key is not None
@@ -181,49 +154,30 @@ def parse_docstring(docstring: str | None) -> dict[str, Any]:
181
154
  and (not stripped_line or original_indentation == 0)
182
155
  ):
183
156
  current_key = None
184
- current_desc_lines = [] # Always clear description lines
157
+ current_desc_lines = []
185
158
 
186
- # --- Process the current line ---
187
-
188
- # If the current line is a section header
189
159
  if is_new_section_header:
190
160
  current_section = new_section_type_this_line
191
161
  if header_content_this_line:
192
- # Add content immediately following the header on the same line
193
162
  current_desc_lines.append(header_content_this_line)
194
- continue # Move to the next line, header is processed
163
+ continue
195
164
 
196
- # If the line is empty, and not a section header (handled above), skip it
197
165
  if not stripped_line:
198
166
  continue
199
167
 
200
- # If we are inside a section, process the line's content
201
168
  if current_section == "args" or current_section == "raises":
202
169
  match = key_pattern.match(line)
203
170
  if match:
204
- # Found a new key: value item within args/raises
205
171
  current_key = match.group(1)
206
- current_desc_lines = [match.group(2).strip()] # Start new description
172
+ current_desc_lines = [match.group(2).strip()]
207
173
  elif current_key is not None:
208
- # Not a new key, but processing an existing item - append to description
209
174
  current_desc_lines.append(stripped_line)
210
- # Lines that don't match key_pattern and occur when current_key is None
211
- # within args/raises are effectively ignored by this block, which seems
212
- # consistent with needing a key: description format.
213
175
 
214
176
  elif current_section in ["returns", "tags", "other"]:
215
- # In these sections, all non-empty, non-header lines are description lines
216
177
  current_desc_lines.append(stripped_line)
217
178
 
218
- # --- Finalization after loop ---
219
- # Finalize any pending item/section block that was being collected
220
179
  finalize_current_item()
221
180
 
222
- # If the docstring only had a summary (no empty line or section header)
223
- # ensure the summary is captured. This check is technically redundant
224
- # because summary is finalized upon hitting the first empty line or header,
225
- # or falls through to the final finalize call if neither occurs.
226
- # Keeping it for clarity, though the logic flow should cover it.
227
181
  if in_summary:
228
182
  summary = " ".join(summary_lines).strip()
229
183