flock-core 0.4.0b33__py3-none-any.whl → 0.4.0b34__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.

Potentially problematic release.


This version of flock-core might be problematic. Click here for more details.

@@ -2,46 +2,37 @@ import re
2
2
 
3
3
 
4
4
  def split_top_level(spec: str) -> list[str]:
5
- """Split *spec* on commas that are truly between fields (i.e. that
6
- are **not** inside brackets, braces, parentheses, string literals,
7
- or the free-form description).
8
-
9
- Strategy
10
- --------
11
- 1. Single pass, char-by-char.
12
- 2. Track • nesting depth for (), [], {}
13
- • whether we are inside a quoted string
14
- 3. Consider a comma a separator *only* if depth == 0, we are not
15
- inside quotes **and** the text that follows matches
16
- `optional-ws + identifier + optional-ws + ':'`
17
- which can only be the start of the next field.
18
- """
5
+ """Return raw field strings, split on *top-level* commas."""
19
6
  fields: list[str] = []
20
7
  start = 0
21
8
  depth = 0
22
9
  quote_char: str | None = None
23
10
  i = 0
24
- ident_re = re.compile(r"[A-Za-z_]\w*") # cheap Python identifier
11
+ ident_re = re.compile(r"[A-Za-z_]\w*") # cheap identifier
25
12
 
26
13
  while i < len(spec):
27
14
  ch = spec[i]
28
15
 
29
- # ---------------- string handling ----------------
16
+ # ---------- string handling ----------
30
17
  if quote_char:
18
+ if ch == "\\":
19
+ i += 2 # skip escaped char
20
+ continue
31
21
  if ch == quote_char:
32
22
  quote_char = None
33
23
  i += 1
34
24
  continue
35
25
 
36
26
  if ch in {"'", '"'}:
37
- # treat as string delimiter only in places regular Python would
38
27
  prev = spec[i - 1] if i else " "
39
- if depth or prev.isspace() or prev in "=([{,:": # likely a quote
28
+ if (
29
+ depth or prev.isspace() or prev in "=([{,:"
30
+ ): # looks like a quote
40
31
  quote_char = ch
41
32
  i += 1
42
33
  continue
43
34
 
44
- # ---------------- bracket / brace / paren ----------------
35
+ # ---------- bracket / brace / paren ----------
45
36
  if ch in "([{":
46
37
  depth += 1
47
38
  i += 1
@@ -51,23 +42,28 @@ def split_top_level(spec: str) -> list[str]:
51
42
  i += 1
52
43
  continue
53
44
 
54
- # ---------------- field separators ----------------
45
+ # ---------- field separators ----------
55
46
  if ch == "," and depth == 0:
56
47
  j = i + 1
57
48
  while j < len(spec) and spec[j].isspace():
58
49
  j += 1
59
- if j < len(spec):
60
- id_match = ident_re.match(spec, j)
61
- if id_match:
62
- k = id_match.end()
63
- while k < len(spec) and spec[k].isspace():
64
- k += 1
65
- if k < len(spec) and spec[k] == ":":
66
- # confirmed: the comma ends the current field
67
- fields.append(spec[start:i].strip())
68
- start = i + 1
69
- i += 1
70
- continue
50
+ if j >= len(spec): # comma at end – split
51
+ fields.append(spec[start:i].strip())
52
+ start = i + 1
53
+ i += 1
54
+ continue
55
+
56
+ id_match = ident_re.match(spec, j)
57
+ if id_match:
58
+ k = id_match.end()
59
+ while k < len(spec) and spec[k].isspace():
60
+ k += 1
61
+ if k >= len(spec) or spec[k] in {":", "|", ","}:
62
+ # confirmed: comma separates two fields
63
+ fields.append(spec[start:i].strip())
64
+ start = i + 1
65
+ i += 1
66
+ continue
71
67
 
72
68
  i += 1
73
69
 
@@ -76,21 +72,29 @@ def split_top_level(spec: str) -> list[str]:
76
72
 
77
73
 
78
74
  def parse_schema(spec: str) -> list[tuple[str, str, str]]:
79
- """Turn the raw *spec* into List[(name, python_type, description)]."""
75
+ """Turn *spec* into a list of (name, python_type, description)."""
80
76
  result: list[tuple[str, str, str]] = []
81
77
 
82
78
  for field in split_top_level(spec):
83
- if ":" not in field:
84
- raise ValueError(f"Malformed field (missing ':'): {field!r}")
79
+ name = ""
80
+ type_str = "str" # default type
81
+ description = ""
85
82
 
86
- name_part, rest = field.split(":", 1)
87
- name = name_part.strip()
88
-
89
- type_part, _, desc_part = rest.partition("|")
90
- type_str = type_part.strip()
83
+ name_part, _, desc_part = field.partition("|")
91
84
  description = desc_part.strip()
85
+ main_part = name_part.strip()
86
+
87
+ if ":" in main_part:
88
+ name, type_candidate = main_part.split(":", 1)
89
+ name = name.strip()
90
+ type_candidate = type_candidate.strip()
91
+ if type_candidate:
92
+ type_str = type_candidate
93
+ else:
94
+ name = main_part # keeps default type
92
95
 
93
- result.append((name, type_str, description))
96
+ if name: # skip broken pieces
97
+ result.append((name, type_str, description))
94
98
 
95
99
  return result
96
100
 
@@ -107,20 +111,101 @@ if __name__ == "__main__":
107
111
  SAMPLE_2 = (
108
112
  "field_with_internal_quotes: Literal['type_A', "
109
113
  '"type_B_with_\'_apostrophe"] | A literal with mixed quotes,'
110
- " another_field: str"
114
+ " another_field :str| A field with a description"
115
+ )
116
+
117
+ SAMPLE_3 = (
118
+ "field_with_internal_quotes: Literal['type_A', "
119
+ '"type_B_with_\'_apostrophe"] | A literal with mixed quotes,'
120
+ " another_field | A field with a description"
121
+ )
122
+
123
+ SAMPLE_4 = "input, query, output"
124
+
125
+ SAMPLE_5 = (
126
+ "name: str | The character's full name,"
127
+ "race: str | The character's fantasy race,"
128
+ "class: Literal['mage','thief'] | The character's profession, which can be either mage or thief,"
129
+ "background: str | A brief backstory for the character"
130
+ )
131
+
132
+ SAMPLE_6 = (
133
+ "summary: str | A short blurb, e.g. key:value pairs that appear in logs"
111
134
  )
135
+ # ➜ [('summary', 'str',
136
+ # 'A short blurb, e.g. key:value pairs that appear in logs')]
112
137
 
113
- print(f"Sample 1: {SAMPLE_1}")
114
- print(f"Sample 2: {SAMPLE_2}")
138
+ SAMPLE_7 = "path: str | The literal string 'C:\\\\Program Files\\\\My,App'"
115
139
 
116
- print("\nSplitting Sample 1:")
117
- split_sample_1 = split_top_level(SAMPLE_1)
118
- print(split_sample_1)
119
- for field in split_sample_1:
120
- print(parse_schema(field))
140
+ # ➜ [('path', 'str',
141
+ # "The literal string 'C:\\Program Files\\My,App'")]
121
142
 
122
- print("\nSplitting Sample 2:")
123
- split_sample_2 = split_top_level(SAMPLE_2)
124
- print(split_sample_2)
125
- for field in split_sample_2:
126
- print(parse_schema(field))
143
+ SAMPLE_8 = (
144
+ "transform: Callable[[int, str], bool] | Function that returns True on success,"
145
+ "retries: int | How many times to retry"
146
+ )
147
+ # ➜ ('transform', 'Callable[[int, str], bool]', 'Function that returns True on success')
148
+ # ('retries', 'int', 'How many times to retry')
149
+
150
+ SAMPLE_9 = (
151
+ r"regex: str | Pattern such as r'^[A-Z\|a-z]+$',"
152
+ "flags: int | re flags to use"
153
+ )
154
+ # ➜ ('regex', 'str', "Pattern such as r'^[A-Z\\|a-z]+$'")
155
+ # ('flags', 'int', 're flags to use')
156
+
157
+ SAMPLE_10 = "id:int, name:str," # note the final comma!
158
+ # ➜ ('id', 'int', '')
159
+ # ('name', 'str', '')
160
+
161
+ SAMPLE_11 = "id:int | Primary key\nname:str | Display name\nactive:bool"
162
+ # ➜ should not work!
163
+
164
+ SAMPLE_12 = (
165
+ 'comment:str | The text "done | failed" goes here,'
166
+ 'status:Literal["done","failed"]'
167
+ )
168
+ # ➜ ('comment', 'str', 'The text "done | failed" goes here')
169
+ # ('status', 'Literal["done","failed"]', '')
170
+
171
+ SAMPLE_13 = "choice: Literal['He said \\'yes\\'', 'no'] | User response"
172
+ # ➜ ('choice', "Literal['He said \\'yes\\'', 'no']", 'User response')
173
+
174
+ SAMPLE_14 = ""
175
+ # ➜ []
176
+
177
+ SAMPLE_15 = "username"
178
+ # ➜ [('username', 'str', '')]
179
+
180
+ SAMPLE_16 = (
181
+ "payload: dict[str, list[dict[str, tuple[int,str]]]] "
182
+ "| Arbitrarily complex structure"
183
+ )
184
+ # ➜ ('payload', 'dict[str, list[dict[str, tuple[int,str]]]]',
185
+ # 'Arbitrarily complex structure')
186
+
187
+ SAMPLE_17 = "münze: str | Deutsche Münzbezeichnung, engl. 'coin'"
188
+ # ➜ [('münze', 'str', "Deutsche Münzbezeichnung, engl. 'coin'")]
189
+
190
+ for title, spec in [
191
+ ("Sample-1", SAMPLE_1),
192
+ ("Sample-2", SAMPLE_2),
193
+ ("Sample-3", SAMPLE_3),
194
+ ("Sample-4", SAMPLE_4),
195
+ ("Sample-5", SAMPLE_5),
196
+ ("Sample-6", SAMPLE_6),
197
+ ("Sample-7", SAMPLE_7),
198
+ ("Sample-8", SAMPLE_8),
199
+ ("Sample-9", SAMPLE_9),
200
+ ("Sample-10", SAMPLE_10),
201
+ ("Sample-11", SAMPLE_11),
202
+ ("Sample-12", SAMPLE_12),
203
+ ("Sample-13", SAMPLE_13),
204
+ ("Sample-14", SAMPLE_14),
205
+ ("Sample-15", SAMPLE_15),
206
+ ("Sample-16", SAMPLE_16),
207
+ ("Sample-17", SAMPLE_17),
208
+ ]:
209
+ print(f"\n{title}")
210
+ for row in parse_schema(spec):
211
+ print(row)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flock-core
3
- Version: 0.4.0b33
3
+ Version: 0.4.0b34
4
4
  Summary: Declarative LLM Orchestration at Scale
5
5
  Author-email: Andre Ratzenberger <andre.ratzenberger@whiteduck.de>
6
6
  License-File: LICENSE
@@ -76,7 +76,7 @@ flock/core/util/file_path_utils.py,sha256=Odf7uU32C-x1KNighbNERSiMtkzW4h8laABIoF
76
76
  flock/core/util/hydrator.py,sha256=QJvCA8F4nkSP5akp3yg0cT6oaajOr1n7sldW5dCs6Lo,10733
77
77
  flock/core/util/input_resolver.py,sha256=KPoPSpklyCoiR2t5r6J6GJHegmPLFZ0YE126VcKBewM,4703
78
78
  flock/core/util/loader.py,sha256=j3q2qem5bFMP2SmMuYjb-ISxsNGNZd1baQmpvAnRUUk,2244
79
- flock/core/util/spliter.py,sha256=qGGbz2UN6v0nATymDzD_G656mWS9dXHrfQoore-lw9M,4027
79
+ flock/core/util/spliter.py,sha256=D-P4u3vdKQFyC4DltpCoX4PExXuOKnE-G5kBG_6H678,6770
80
80
  flock/evaluators/declarative/declarative_evaluator.py,sha256=q3qKHuKrj17mhaoOZuKh2HyVfiDBEEUk1Y1ZrejvggA,6328
81
81
  flock/evaluators/memory/memory_evaluator.py,sha256=ySwz7kcc8suXMJ7gKNSWThW8iOMlE8lUcUzEAHvv8rw,3559
82
82
  flock/evaluators/test/test_case_evaluator.py,sha256=3Emcoty0LOLLBIuPGxSpKphuZC9Fu1DTr1vbGg-hd0Q,1233
@@ -445,8 +445,8 @@ flock/workflow/agent_execution_activity.py,sha256=Gy6FtuVAjf0NiUXmC3syS2eJpNQF4R
445
445
  flock/workflow/flock_workflow.py,sha256=iSUF_soFvWar0ffpkzE4irkDZRx0p4HnwmEBi_Ne2sY,9666
446
446
  flock/workflow/temporal_config.py,sha256=3_8O7SDEjMsSMXsWJBfnb6XTp0TFaz39uyzSlMTSF_I,3988
447
447
  flock/workflow/temporal_setup.py,sha256=YIHnSBntzOchHfMSh8hoLeNXrz3B1UbR14YrR6soM7A,1606
448
- flock_core-0.4.0b33.dist-info/METADATA,sha256=F55blOoGy7L3heUhWO4SE0TTHMj1fhARNB0WRI_vDQM,17125
449
- flock_core-0.4.0b33.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
450
- flock_core-0.4.0b33.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
451
- flock_core-0.4.0b33.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
452
- flock_core-0.4.0b33.dist-info/RECORD,,
448
+ flock_core-0.4.0b34.dist-info/METADATA,sha256=xImOi53HupDqDi8RpnOjZfkS_rbLJQ6j_CrwoIR7RPA,17125
449
+ flock_core-0.4.0b34.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
450
+ flock_core-0.4.0b34.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
451
+ flock_core-0.4.0b34.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
452
+ flock_core-0.4.0b34.dist-info/RECORD,,