Skip to content

Commit 0716aee

Browse files
ChaffelsonCopilot
andauthored
Feature/port scheduling and magic entity resolution (#398)
* Add get_port and schedule_port functions - Add get_port(identifier, identifier_type) for retrieving ports by ID or name - Add schedule_port(port, scheduled) following schedule_processor pattern - Register PortEntity in config.py for filter_obj support - Add comprehensive tests for both functions * fix(canvas): Set controller name in initial creation request Previously create_controller() set the name in a separate update call after creation, but returned the stale object from the initial call. This caused component.name to show the type name instead of the custom name. Now sets name directly in the ControllerServiceDTO during creation, matching the pattern used by create_processor(). Also defaults to short type name if no name provided (e.g., 'JsonTreeReader'). * WIP: Add scheduling state consolidation utilities Utilities implemented in nipyapi/utils.py: - resolve_schedule_state(): Standardized bool/string to state normalization - resolve_entity(): Entity resolution accepting ID, name, or object (to be used in next phase) Scheduling functions consolidated in canvas.py: - schedule_processor: Uses resolve_schedule_state() - schedule_port: Uses resolve_schedule_state() - schedule_controller: Uses resolve_schedule_state(), now accepts string states ('ENABLED', 'DISABLED') in addition to bool - schedule_all_controllers: Same extension - schedule_components: Now accepts string states ('RUNNING', 'STOPPED') Breaking change: Invalid scheduled values now raise ValueError instead of AssertionError. This is a more appropriate exception type. Tests expanded for new string state acceptance in controller scheduling. All 660 tests pass. * feat: Add resolve_entity utility for consistent entity resolution across modules - Add resolve_entity() and resolve_schedule_state() utilities in utils.py - Refactor 17 canvas.py functions to accept object, ID, or name - Refactor 9 versioning.py functions with consistent entity resolution - Refactor 5 parameters.py functions with consistent entity resolution - Add schedule_port() and get_port() functions to canvas.py - Add greedy parameter to get_controller() - Remove deprecated get_variable_registry/update_variable_registry - Consolidate verification request pattern with _run_verification_request helper - Make location optional in create_process_group and create_funnel - Add PortEntity to registered_filters in config.py - Optimize fix_state_flow fixture to module scope - Update tests for new ValueError exceptions and expanded functionality Closes #396 * Add Raises sections to entity resolution function docstrings * docs: Clarify test comment about ValueError from resolve_entity validation (#399) * Initial plan * docs: Clarify test comment about ValueError from resolve_entity validation Co-authored-by: Chaffelson <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: Chaffelson <[email protected]> --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Chaffelson <[email protected]>
1 parent c4127de commit 0716aee

File tree

10 files changed

+1642
-434
lines changed

10 files changed

+1642
-434
lines changed

nipyapi/canvas.py

Lines changed: 586 additions & 346 deletions
Large diffs are not rendered by default.

nipyapi/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"UserEntity": {"identity": ["component", "identity"], "id": ["id"]},
7070
"TemplateEntity": {"id": ["id"], "name": ["template", "name"]},
7171
"ControllerServiceEntity": {"id": ["id"], "name": ["component", "name"]},
72+
"PortEntity": {"id": ["id"], "name": ["status", "name"]},
7273
"ParameterContextEntity": {"id": ["id"], "name": ["component", "name"]},
7374
"ReportingTaskEntity": {"id": ["id"], "name": ["component", "name"]},
7475
# Git-based Flow Registry types (GitHub, GitLab, Bitbucket, Azure DevOps)

nipyapi/parameters.py

Lines changed: 95 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -178,19 +178,34 @@ def _update_complete(context_id, request_id):
178178
return get_parameter_context(context.id, identifier_type="id")
179179

180180

181-
def delete_parameter_context(context, refresh=True):
181+
def delete_parameter_context(context, refresh=True, greedy=True, identifier_type="auto"):
182182
"""
183183
Removes a Parameter Context
184184
185185
Args:
186-
context (ParameterContextEntity): Parameter Context to be deleted
186+
context (ParameterContextEntity or str): Parameter Context to be deleted,
187+
as a ParameterContextEntity object, context ID, or context name.
187188
refresh (bool): Whether to refresh the Context before Deletion
189+
greedy (bool): For name lookup, True for partial match, False for exact.
190+
identifier_type (str): How to interpret string identifier:
191+
"auto" (default) detects UUID vs name, "id" or "name" to force.
188192
189193
Returns:
190194
:class:`~nipyapi.nifi.models.ParameterContextEntity`: The removed Parameter Context
195+
196+
Raises:
197+
TypeError: If context is not a string or ParameterContextEntity.
198+
ValueError: If parameter context not found or multiple matches found.
191199
"""
192200
enforce_min_ver("1.10.0")
193-
assert isinstance(context, nipyapi.nifi.ParameterContextEntity)
201+
context = nipyapi.utils.resolve_entity(
202+
context,
203+
get_parameter_context,
204+
nipyapi.nifi.ParameterContextEntity,
205+
strict=True,
206+
greedy=greedy,
207+
identifier_type=identifier_type,
208+
)
194209
handle = nipyapi.nifi.ParameterContextsApi()
195210
if refresh:
196211
context = handle.get_parameter_context(context.id)
@@ -218,51 +233,102 @@ def prepare_parameter(name, value, description=None, sensitive=False):
218233
return out
219234

220235

221-
def delete_parameter_from_context(context, parameter_name):
236+
def delete_parameter_from_context(context, parameter_name, greedy=True, identifier_type="auto"):
222237
"""
223238
Delete a specific Parameter from a Parameter Context
239+
224240
Args:
225-
context (ParameterContextEntity): The Parameter Context to Update
241+
context (ParameterContextEntity or str): The Parameter Context to Update,
242+
as a ParameterContextEntity object, context ID, or context name.
226243
parameter_name (str): The Parameter to delete
244+
greedy (bool): For name lookup, True for partial match, False for exact.
245+
identifier_type (str): How to interpret string identifier:
246+
"auto" (default) detects UUID vs name, "id" or "name" to force.
227247
228248
Returns:
229249
:class:`~nipyapi.nifi.models.ParameterContextEntity`: The updated Parameter Context
250+
251+
Raises:
252+
TypeError: If context is not a string or ParameterContextEntity.
253+
ValueError: If parameter context not found or multiple matches found.
230254
"""
231255
enforce_min_ver("1.10.0")
256+
context = nipyapi.utils.resolve_entity(
257+
context,
258+
get_parameter_context,
259+
nipyapi.nifi.ParameterContextEntity,
260+
strict=True,
261+
greedy=greedy,
262+
identifier_type=identifier_type,
263+
)
232264
context.component.parameters = [ParameterEntity(parameter=ParameterDTO(name=parameter_name))]
233265
return update_parameter_context(context=context)
234266

235267

236-
def upsert_parameter_to_context(context, parameter):
268+
def upsert_parameter_to_context(context, parameter, greedy=True, identifier_type="auto"):
237269
"""
238270
Insert or Update Parameter within a Parameter Context
239271
240272
Args:
241-
context (ParameterContextEntity): The Parameter Context to Modify
242-
parameter(ParameterEntity): The ParameterEntity to insert or update
273+
context (ParameterContextEntity or str): The Parameter Context to Modify,
274+
as a ParameterContextEntity object, context ID, or context name.
275+
parameter (ParameterEntity): The ParameterEntity to insert or update
276+
greedy (bool): For name lookup, True for partial match, False for exact.
277+
identifier_type (str): How to interpret string identifier:
278+
"auto" (default) detects UUID vs name, "id" or "name" to force.
243279
244280
Returns:
245281
:class:`~nipyapi.nifi.models.ParameterContextEntity`: The updated Parameter Context
282+
283+
Raises:
284+
TypeError: If context is not a string or ParameterContextEntity.
285+
ValueError: If parameter context not found or multiple matches found.
246286
"""
247287
enforce_min_ver("1.10.0")
288+
context = nipyapi.utils.resolve_entity(
289+
context,
290+
get_parameter_context,
291+
nipyapi.nifi.ParameterContextEntity,
292+
strict=True,
293+
greedy=greedy,
294+
identifier_type=identifier_type,
295+
)
248296
context.component.parameters = [parameter]
249297
return update_parameter_context(context=context)
250298

251299

252-
def assign_context_to_process_group(pg, context_id, cascade=False):
300+
def assign_context_to_process_group(
301+
pg, context_id, cascade=False, greedy=True, identifier_type="auto"
302+
):
253303
"""
254304
Assigns a given Parameter Context to a specific Process Group
255305
Optionally cascades down to direct children Process Groups
256306
257307
Args:
258-
pg (ProcessGroupEntity): The Process Group to target
308+
pg (ProcessGroupEntity or str): The Process Group to target,
309+
as a ProcessGroupEntity object, process group ID, or name.
259310
context_id (str): The ID of the Parameter Context
260311
cascade (bool): Cascade Parameter Context down to child Process Groups?
312+
greedy (bool): For name lookup, True for partial match, False for exact.
313+
identifier_type (str): How to interpret string identifier:
314+
"auto" (default) detects UUID vs name, "id" or "name" to force.
261315
262316
Returns:
263317
:class:`~nipyapi.nifi.models.ProcessGroupEntity`: The updated Process Group
318+
319+
Raises:
320+
TypeError: If pg is not a string or ProcessGroupEntity.
321+
ValueError: If process group not found or multiple matches found.
264322
"""
265323
assert isinstance(context_id, str)
324+
pg = nipyapi.utils.resolve_entity(
325+
pg,
326+
nipyapi.canvas.get_process_group,
327+
nipyapi.nifi.ProcessGroupEntity,
328+
strict=True,
329+
greedy=greedy,
330+
identifier_type=identifier_type,
331+
)
266332
if cascade:
267333
# Update the specified Process Group & all children
268334
child_pgs = nipyapi.canvas.list_all_process_groups(pg_id=pg.id)
@@ -275,16 +341,32 @@ def assign_context_to_process_group(pg, context_id, cascade=False):
275341
)
276342

277343

278-
def remove_context_from_process_group(pg):
344+
def remove_context_from_process_group(pg, greedy=True, identifier_type="auto"):
279345
"""
280346
Clears any Parameter Context from the given Process Group
281347
282348
Args:
283-
pg (ProcessGroupEntity): The Process Group to target
349+
pg (ProcessGroupEntity or str): The Process Group to target,
350+
as a ProcessGroupEntity object, process group ID, or name.
351+
greedy (bool): For name lookup, True for partial match, False for exact.
352+
identifier_type (str): How to interpret string identifier:
353+
"auto" (default) detects UUID vs name, "id" or "name" to force.
284354
285355
Returns:
286356
:class:`~nipyapi.nifi.models.ProcessGroupEntity`: The updated Process Group
287-
"""
357+
358+
Raises:
359+
TypeError: If pg is not a string or ProcessGroupEntity.
360+
ValueError: If process group not found or multiple matches found.
361+
"""
362+
pg = nipyapi.utils.resolve_entity(
363+
pg,
364+
nipyapi.canvas.get_process_group,
365+
nipyapi.nifi.ProcessGroupEntity,
366+
strict=True,
367+
greedy=greedy,
368+
identifier_type=identifier_type,
369+
)
288370
return nipyapi.canvas.update_process_group(pg=pg, update={"parameter_context": {"id": None}})
289371

290372

0 commit comments

Comments
 (0)