Skip to content

feat(gfql): add public Plottable.schema accessor for typed-schema introspection #1632

@lmeyerov

Description

@lmeyerov

Background

PR #1457 landed public typed-schema (graphistry.schema.NodeType / EdgeType / GraphSchema / EdgeTopology, bind(schema=...), local gfql_validate()). The bound schema is stored on Plottable._gfql_schema (private attribute, set via bind(schema=...)).

There is no public accessor. Consumers (AI synthesizers, graphistrygpt, schema-aware tooling, debugging code) must reach for getattr(g, "_gfql_schema", None) against a private attribute. This is a P0 ergonomics gap surfaced by the AI-synthesizer user-testing exercise.

Goal

Add a public read-only accessor for bound GraphSchema so consumers can introspect without touching private attributes.

Scope

  • Add Plottable.schema (or Plottable.get_schema() — pick whichever fits existing conventions) as a read-only property returning the bound GraphSchema or None if no schema is bound.
  • Add Plottable.has_schema() -> bool as a convenience predicate.
  • Re-export via top-level graphistry namespace if appropriate per the existing accessor patterns.
  • Document the new accessor; mark experimental per #1457's experimental marking.
  • Anchored regression tests: bound → returns schema; unbound → returns None; has_schema returns matching bool.

Non-scope

  • No changes to bind(schema=...) behavior or internal storage.
  • No schema mutation API (read-only accessor only).
  • No inference (separate #1338 lane).
  • No pretty-printing (separate follow-on issue).

Suggested signature

class Plottable:
    @property
    def schema(self) -> Optional[GraphSchema]:
        """Read-only access to bound GraphSchema (or None if unbound).
        
        Experimental per #1457.
        """
        return getattr(self, "_gfql_schema", None)
    
    def has_schema(self) -> bool:
        """True if a GraphSchema is bound on this Plottable."""
        return self._gfql_schema is not None

Acceptance

  • g.schema returns the bound GraphSchema instance (or None)
  • g.has_schema() returns matching bool
  • Public docs reflect the accessor
  • Anchored tests cover bound + unbound cases
  • Experimental marking preserved
  • Compiler-plan surface touched: no

Cross-refs

  • Landed in #1457 / #1337
  • Surfaced by AI-synthesizer user-testing 2026-05-25 (P0 finding)
  • Coordination: pygraphistry2/'s #1338 inference work; this accessor returns whatever schema is bound (declared or inferred)
  • Metaissue: #1058, #1046
  • Downstream consumer: graphistrygpt/'s plugins/graphistry/tool.py needs this to retire _chain_contains_radial_layout-style brittle string-matching code

Effort

Small (~30 prod LOC). Drop-in fit for any paused pygraphistry lane.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions