def resolve_ptr( near_endpoint: s_obj.Object, pointer_name: str, *, upcoming_intersections: Sequence[s_types.Type] = (), far_endpoints: Iterable[s_obj.Object] = (), direction: s_pointers.PointerDirection = ( s_pointers.PointerDirection.Outbound), source_context: Optional[parsing.ParserContext] = None, track_ref: Optional[Union[qlast.Base, Literal[False]]], ctx: context.ContextLevel, ) -> s_pointers.Pointer: if not isinstance(near_endpoint, s_sources.Source): # Reference to a property on non-object msg = 'invalid property reference on a primitive type expression' raise errors.InvalidReferenceError(msg, context=source_context) ptr: Optional[s_pointers.Pointer] = None if direction is s_pointers.PointerDirection.Outbound: ptr = near_endpoint.maybe_get_ptr( ctx.env.schema, s_name.UnqualName(pointer_name), ) if ptr is not None: ref = ptr.get_nearest_non_derived_parent(ctx.env.schema) if track_ref is not False: ctx.env.add_schema_ref(ref, track_ref) else: ptrs = near_endpoint.getrptrs(ctx.env.schema, pointer_name, sources=far_endpoints) if ptrs: if track_ref is not False: # If this reverse pointer access is followed by # intersections, we filter out any pointers that # couldn't be picked up by the intersections. This avoids # creating spurious dependencies when reverse # links are used in schemas. dep_ptrs = { ptr for ptr in ptrs if (src := ptr.get_source(ctx.env.schema)) and all( src.issubclass(ctx.env.schema, typ) or any( dsrc.issubclass(ctx.env.schema, typ) for dsrc in src.descendants(ctx.env.schema)) for typ in upcoming_intersections) } for p in dep_ptrs: ctx.env.add_schema_ref( p.get_nearest_non_derived_parent(ctx.env.schema), track_ref) opaque = not far_endpoints ctx.env.schema, ptr = s_pointers.get_or_create_union_pointer( ctx.env.schema, ptrname=s_name.UnqualName(pointer_name), source=near_endpoint, direction=direction, components=ptrs, opaque=opaque, modname=ctx.derived_target_module, ) if ptr is not None: return ptr if isinstance(near_endpoint, s_links.Link): vname = near_endpoint.get_verbosename(ctx.env.schema, with_parent=True) msg = f'{vname} has no property {pointer_name!r}' elif direction == s_pointers.PointerDirection.Outbound: msg = (f'{near_endpoint.get_verbosename(ctx.env.schema)} ' f'has no link or property {pointer_name!r}') else: nep_name = near_endpoint.get_displayname(ctx.env.schema) path = f'{nep_name}.{direction}{pointer_name}' msg = f'{path!r} does not resolve to any known path' err = errors.InvalidReferenceError(msg, context=source_context) if direction is s_pointers.PointerDirection.Outbound: near_enpoint_pointers = near_endpoint.get_pointers(ctx.env.schema) s_utils.enrich_schema_lookup_error( err, s_name.UnqualName(pointer_name), modaliases=ctx.modaliases, item_type=s_pointers.Pointer, collection=near_enpoint_pointers.objects(ctx.env.schema), schema=ctx.env.schema, ) raise err
def resolve_ptr( near_endpoint: s_obj.Object, pointer_name: str, *, far_endpoints: Iterable[s_obj.Object] = (), direction: s_pointers.PointerDirection = ( s_pointers.PointerDirection.Outbound ), source_context: Optional[parsing.ParserContext] = None, track_ref: Optional[Union[qlast.Base, Literal[False]]], ctx: context.ContextLevel, ) -> s_pointers.Pointer: if not isinstance(near_endpoint, s_sources.Source): # Reference to a property on non-object msg = 'invalid property reference on a primitive type expression' raise errors.InvalidReferenceError(msg, context=source_context) ptr: Optional[s_pointers.Pointer] = None if direction is s_pointers.PointerDirection.Outbound: ptr = near_endpoint.maybe_get_ptr( ctx.env.schema, s_name.UnqualName(pointer_name), ) if ptr is not None: ref = ptr.get_nearest_non_derived_parent(ctx.env.schema) if track_ref is not False: ctx.env.add_schema_ref(ref, track_ref) else: ptrs = near_endpoint.getrptrs(ctx.env.schema, pointer_name, sources=far_endpoints) if ptrs: if track_ref is not False: for p in ptrs: ctx.env.add_schema_ref( p.get_nearest_non_derived_parent(ctx.env.schema), track_ref) opaque = not far_endpoints ctx.env.schema, ptr = s_pointers.get_or_create_union_pointer( ctx.env.schema, ptrname=s_name.UnqualName(pointer_name), source=near_endpoint, direction=direction, components=ptrs, opaque=opaque, modname=ctx.derived_target_module, ) if ptr is not None: return ptr if isinstance(near_endpoint, s_links.Link): vname = near_endpoint.get_verbosename(ctx.env.schema, with_parent=True) msg = f'{vname} has no property {pointer_name!r}' elif direction == s_pointers.PointerDirection.Outbound: msg = (f'{near_endpoint.get_verbosename(ctx.env.schema)} ' f'has no link or property {pointer_name!r}') else: nep_name = near_endpoint.get_displayname(ctx.env.schema) path = f'{nep_name}.{direction}{pointer_name}' msg = f'{path!r} does not resolve to any known path' err = errors.InvalidReferenceError(msg, context=source_context) if direction is s_pointers.PointerDirection.Outbound: near_enpoint_pointers = near_endpoint.get_pointers(ctx.env.schema) s_utils.enrich_schema_lookup_error( err, s_name.UnqualName(pointer_name), modaliases=ctx.modaliases, item_type=s_pointers.Pointer, collection=near_enpoint_pointers.objects(ctx.env.schema), schema=ctx.env.schema, ) raise err