pi-revit 0.2.14 → 0.2.16

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,37 @@ Format follows [Keep a Changelog](https://keepachangelog.com/); version headers
7
7
  Every published version gets an entry with **Added** / **Changed** / **Fixed** sections
8
8
  describing what the user will notice — not internal refactors.
9
9
 
10
+ ## [0.2.16] - 2026-08-21
11
+
12
+ ### Fixed
13
+ - `search_api_docs`: an accessor-spelling query combined with `kind: "method"` — e.g.
14
+ `Element.get_Parameter(BuiltInParameter)` filtered to methods — returned "no matches",
15
+ because the accessor rewrite found the documented member but the kind filter rejected it:
16
+ a C# `get_X`/`set_X` accessor is a method to the caller, while the XML documents the
17
+ underlying member as a property or indexer. For accessor-rewritten candidates the
18
+ `method` filter now also admits properties, and the result note says so. Found by an
19
+ agent under a stress test that filtered its doc query to methods. Two benchmark probes
20
+ added (the widening plus a real-method control).
21
+
22
+ Requires redeploying the Revit add-in (`scripts\deploy.ps1` with Revit closed, then
23
+ restart Revit).
24
+
25
+ ## [0.2.15] - 2026-08-21
26
+
27
+ ### Fixed
28
+ - `set_parameters`: the "parameter not found" error now mentions that display names are
29
+ localized and points to the language-independent BuiltInParameter enum name — the same
30
+ guidance `get_element_details` and `get_elements` already give. Previously it only
31
+ suggested the type-parameter cause, which sent the caller down the wrong path in
32
+ non-English UIs.
33
+ - `get_elements`: the "filter parameter not found on any probed element" warning now
34
+ appears only when the query returned zero matches — that is where it distinguishes
35
+ "unknown parameter name" from "no matching elements". Next to real matches it was noise
36
+ (an unscoped query's probe window can simply miss the elements that carry the parameter).
37
+
38
+ Requires redeploying the Revit add-in (`scripts\deploy.ps1` with Revit closed, then
39
+ restart Revit).
40
+
10
41
  ## [0.2.14] - 2026-08-21
11
42
 
12
43
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-revit",
3
- "version": "0.2.14",
3
+ "version": "0.2.16",
4
4
  "description": "Native Pi connector for Autodesk Revit. Run npx.cmd -y pi-revit for the full Windows install.",
5
5
  "author": "Ahmad Altahlawi",
6
6
  "license": "MIT",
@@ -31,8 +31,10 @@ else:
31
31
  XML_PATH = candidates[-1]
32
32
 
33
33
  LAT = []
34
- def search(query, max_results=10):
35
- body = json.dumps({"query": query, "max_results": max_results}).encode("utf-8")
34
+ def search(query, max_results=10, kind=None):
35
+ args = {"query": query, "max_results": max_results}
36
+ if kind: args["kind"] = kind
37
+ body = json.dumps(args).encode("utf-8")
36
38
  url = f"{BASE}/tools/search_api_docs/execute?token={TOKEN}&timeout_ms=60000"
37
39
  req = urllib.request.Request(url, data=body, headers={"content-type": "application/json"}, method="POST")
38
40
  t0 = time.perf_counter()
@@ -180,8 +182,8 @@ R["B signature+spacing"] = B
180
182
 
181
183
  # --------------------------------------------------------- C: complex syntax shapes
182
184
  C = {"cases": []}
183
- def probe(label, q, expect_nonzero=True):
184
- try: matches, total = search(q)
185
+ def probe(label, q, expect_nonzero=True, kind=None):
186
+ try: matches, total = search(q, kind=kind)
185
187
  except Exception as e:
186
188
  C["cases"].append((label, q, f"ERROR {e}")); return
187
189
  ok = (total > 0) if expect_nonzero else (total == 0)
@@ -213,6 +215,9 @@ probe("factory honesty control", "Document.Create.Banana", expect_nonzero=False)
213
215
  probe("accessor indexer", "Element.get_Parameter(BuiltInParameter")
214
216
  probe("accessor property", "Element.get_BoundingBox(View")
215
217
  probe("literal get_ member", "LocationCurve.get_ElementsAtJoin")
218
+ # 0.2.16: kind=method on an accessor query admits the documented property
219
+ probe("accessor with kind=method", "Element.get_Parameter(BuiltInParameter", kind="method")
220
+ probe("kind=method control (real method)", "Wall.Create(Document, Curve", kind="method")
216
221
  print("C done", flush=True)
217
222
  R["C complex-syntax"] = C
218
223
 
@@ -147,7 +147,10 @@ namespace RevitBridge.Tools
147
147
  string scope = DescribeScope(categoryInput, classInput, inActiveView);
148
148
 
149
149
  if (countOnly && postPredicate is null)
150
- return CountResult(scope, CreateCollector().GetElementCount(), filterWarnings);
150
+ {
151
+ int quickCount = CreateCollector().GetElementCount();
152
+ return CountResult(scope, quickCount, quickCount > 0 ? Array.Empty<string>() : filterWarnings);
153
+ }
151
154
 
152
155
  var rows = countOnly ? null : new List<Dictionary<string, object?>>(Math.Min(limit, 256));
153
156
  int total = 0;
@@ -160,6 +163,12 @@ namespace RevitBridge.Tools
160
163
  total++;
161
164
  }
162
165
 
166
+ // A found match proves the query worked: the not-found-on-probes warning is
167
+ // load-bearing only next to a zero, where it distinguishes 'unknown parameter
168
+ // name' from 'no matching elements'. Beside real matches it is just noise.
169
+ if (total > 0)
170
+ filterWarnings = Array.Empty<string>();
171
+
163
172
  if (rows is null)
164
173
  return CountResult(scope, total, filterWarnings);
165
174
 
@@ -142,17 +142,17 @@ namespace RevitBridge.Tools
142
142
  // member, before giving up. Deterministic rewrites of an exact idiom — never
143
143
  // applied unless the literal 'document.create.' / 'application.create.' prefix
144
144
  // is present, so ordinary names like Wall.Create are untouched.
145
- var candidates = new List<(string Query, string? Note)> { (q, null) };
145
+ var candidates = new List<(string Query, string? Note, bool AccessorRewrite)> { (q, null, false) };
146
146
  foreach (string factory in new[] { "document.create.", "application.create." })
147
147
  {
148
148
  if (!q.StartsWith(factory, StringComparison.Ordinal))
149
149
  continue;
150
150
  string owner = factory[..(factory.IndexOf('.') + 1)]; // "document."
151
151
  string rest = q[factory.Length..];
152
- candidates.Add((owner + rest, $"'{owner}Create.*' is the Creation factory — matched as '{owner}{rest}'."));
152
+ candidates.Add((owner + rest, $"'{owner}Create.*' is the Creation factory — matched as '{owner}{rest}'.", false));
153
153
  string bareMember = rest.Split('(')[0];
154
154
  if (bareMember.Length > 0)
155
- candidates.Add((bareMember, $"'{owner}Create.{bareMember}' is a Creation-factory call; its docs live on the factory class (e.g. ItemFactoryBase) — matched by member name '{bareMember}'."));
155
+ candidates.Add((bareMember, $"'{owner}Create.{bareMember}' is a Creation-factory call; its docs live on the factory class (e.g. ItemFactoryBase) — matched by member name '{bareMember}'.", false));
156
156
  }
157
157
 
158
158
  // C# spells property and indexer accessors 'get_X'/'set_X' (element.get_Parameter(...),
@@ -166,26 +166,33 @@ namespace RevitBridge.Tools
166
166
  if (accessor.StartsWith("get_", StringComparison.Ordinal) || accessor.StartsWith("set_", StringComparison.Ordinal))
167
167
  accessor = accessor["get_".Length..];
168
168
  if (accessor != q)
169
- candidates.Add((accessor, "'get_X' / 'set_X' is the C# accessor spelling of property or indexer 'X'; matched without the prefix."));
169
+ candidates.Add((accessor, "'get_X' / 'set_X' is the C# accessor spelling of property or indexer 'X'; matched without the prefix.", true));
170
170
  }
171
171
 
172
- foreach (var (candidate, note) in candidates)
172
+ foreach (var (candidate, note, accessorRewrite) in candidates)
173
173
  {
174
- var (top, total) = RunScoring(index, candidate, kindFilter, maxResults);
174
+ // A C# accessor IS a method to the caller ('element.get_Parameter(...)'), but
175
+ // the XML documents the underlying member as a property/indexer — so an
176
+ // accessor-rewritten candidate lets kind=method admit properties too.
177
+ bool widenKind = accessorRewrite && kindFilter == 'M';
178
+ var (top, total) = RunScoring(index, candidate, kindFilter, maxResults, widenKind);
175
179
  if (total > 0)
176
- return (top, total, note);
180
+ return (top, total, widenKind
181
+ ? note + " The 'method' kind filter also admitted properties here: accessors are documented as properties/indexers."
182
+ : note);
177
183
  }
178
184
  return (new List<ApiMember>(), 0, null);
179
185
  }
180
186
 
181
- private static (List<ApiMember> Top, int Total) RunScoring(DocIndex index, string q, char? kindFilter, int maxResults)
187
+ private static (List<ApiMember> Top, int Total) RunScoring(DocIndex index, string q, char? kindFilter, int maxResults, bool methodKindAdmitsProperties = false)
182
188
  {
183
189
  string[] words = q.Split(WordSeparators, StringSplitOptions.RemoveEmptyEntries);
184
190
 
185
191
  var scored = new List<(ApiMember Member, int Score)>();
186
192
  foreach (var member in index.Members)
187
193
  {
188
- if (kindFilter is { } kind && member.Kind != kind)
194
+ if (kindFilter is { } kind && member.Kind != kind
195
+ && !(methodKindAdmitsProperties && kind == 'M' && member.Kind == 'P'))
189
196
  continue;
190
197
  int score = Score(member, q, words);
191
198
  if (score > 0)
@@ -156,7 +156,7 @@ namespace RevitBridge.Tools
156
156
  {
157
157
  if (nameTarget)
158
158
  return SetElementName(element, update);
159
- throw new InvalidOperationException($"Parameter '{update.ParameterInput}' not found on element {update.ElementId} ('{element.Name}'). Type parameters live on the element type — pass its id instead.");
159
+ throw new InvalidOperationException($"Parameter '{update.ParameterInput}' not found on element {update.ElementId} ('{element.Name}'). Display names are localized in non-English Revit UIs — prefer the language-independent BuiltInParameter enum name (e.g. ALL_MODEL_INSTANCE_COMMENTS; get_element_details reports each parameter's builtInParameter). Type parameters live on the element type — pass the type's id instead.");
160
160
  }
161
161
 
162
162
  if (parameter.IsReadOnly)