diff --git a/parser/object_model.py b/parser/object_model.py index 56dccd8..fbe7611 100644 --- a/parser/object_model.py +++ b/parser/object_model.py @@ -212,9 +212,19 @@ def _ooname(fn_name: str, cls: str) -> str: def _oo_excluded(fn: dict, role: str) -> bool: """True for functions classified to a class that are internal machinery, - not user OO methods: aggregate transition helpers, and comparators with no - SQL function (qsort / bound / min / max sort helpers).""" + not user OO methods: functions the catalog marks internal (the ``_p`` peeks, + the bbox / skiplist plumbing, ``*_in`` / ``*_out``), aggregate transition + helpers, and comparators with no SQL function (qsort / bound / min / max sort + helpers). + + The internal-API check is the load-bearing one for a binding that generates + its object layer from ``classes[*].methods``: without it that list mixes the + public surface with functions a binding cannot call, so every binding would + re-derive the split. The catalog carries ``api`` per function, so the method + carries the exclusion and a binding keeps only ``not m['ooExclude']``.""" name = fn["name"] + if fn.get("api") != "public": + return True if any(name.endswith(s) for s in _OONAME_EXCLUDE_SUFFIXES): return True if role == "predicate" and not fn.get("sqlfn"): diff --git a/tests/test_object_model.py b/tests/test_object_model.py index a8c5683..60dd7aa 100644 --- a/tests/test_object_model.py +++ b/tests/test_object_model.py @@ -156,6 +156,19 @@ def test_classification(self): self.assertIsNone(ftc["add_int_int"]["class"]) self.assertIn("no-prefix-match", ftc["add_int_int"]["reason"]) + def test_internal_api_methods_are_excluded(self): + # A function the catalog marks internal is classified to its class (so + # the reverse index stays complete) but flagged ooExclude, so a binding + # generating from classes[*].methods keeps only the public surface. + idl = attach_object_model({"functions": [ + {"name": "temporal_num_instants", "api": "public"}, + {"name": "temporal_inst_n", "api": "internal"}, + ]}, MODEL, None) + meths = {m["backing"]: m + for m in idl["objectModel"]["classes"]["Temporal"]["methods"]} + self.assertNotIn("ooExclude", meths["temporal_num_instants"]) + self.assertTrue(meths["temporal_inst_n"].get("ooExclude")) + def test_tree_derived(self): om = self._attach(["temporal_merge"])["objectModel"] lat = om["lattice"]