Two latent inefficiencies in object_has_atom_transp() (modules/pymol/appkit_inspector.py:234), both found while diagnosing the "opens but won't rotate" report fixed in #270.
#270 stops this running twice a second, so it is no longer a responsiveness bug — but the scan is still needlessly expensive every time the cache is invalidated (i.e. after every command), so it's worth fixing on its own.
1. The rep gate runs after the scan it is supposed to avoid
def object_has_atom_transp(obj):
"""... The count_atoms probe runs only when an override exists (cheap short-circuit)."""
summ = transp_summary(obj) # <-- full per-atom cmd.iterate, unconditional
for rep, setting in REP_TRANSP.items():
entry = summ.get(setting)
if entry and entry[2]:
if cmd.count_atoms('(%s) & rep %s' % (obj, rep)) > 0:
return True
return False
The docstring's "cheap short-circuit" only guards the count_atoms probe. transp_summary() — the per-atom cmd.iterate over the whole object (appkit_inspector.py:191) — runs unconditionally, even for an object showing only lines, where no rep in REP_TRANSP can be transparent and the answer is always False.
Inverting it (probe which of the ~3 transparency-capable reps are actually shown, then scan only those settings — or skip the scan entirely when none are) is cheap: a per-rep count_atoms is a C++ selector pass over one object, measured at ~0.3 ms against ~38 ms for the Python per-atom scan.
It would also shrink the scan itself. The iterate expression is built from all of TRANSP_SETTINGS:
expr = '_visit((%s))' % ', '.join('s.%s' % s for s in TRANSP_SETTINGS)
Narrowing it to the settings whose rep is shown drops the per-atom namespace lookups from 4 to 2 for a cartoon-only object. That matters because each lookup that misses goes through a raised and string-formatted AttributeError in PyMOL's iterate namespace — PyErr_Format/PyUnicode_FromFormatV were the hot leaves in the profile in #270.
2. Disabled objects are scanned
poll_panel() computes has_transp for every object in public_objects, enabled or not. Hiding objects to make a heavy session manageable therefore doesn't help. Measured on the 12-object / 79,568-atom session from #270, with 10 of 12 objects disabled:
poll_panel, all enabled : 381 ms
poll_panel, 10 of 12 hidden : 393 ms <- no improvement
A disabled object's row is still drawn in the panel, so its badge is arguably still wanted — but it can't change while hidden, so at minimum it shouldn't be rescanned on every invalidation.
Suggested fix
Compute the shown-rep set first; skip transp_summary() entirely when no transparency-capable rep is active, and pass it the narrowed setting list otherwise. Keep the #219 non-molecular guard and the #256 group behaviour intact — testing/tests/test_appkit_objpanel_poll.py covers both.
Two latent inefficiencies in
object_has_atom_transp()(modules/pymol/appkit_inspector.py:234), both found while diagnosing the "opens but won't rotate" report fixed in #270.#270 stops this running twice a second, so it is no longer a responsiveness bug — but the scan is still needlessly expensive every time the cache is invalidated (i.e. after every command), so it's worth fixing on its own.
1. The rep gate runs after the scan it is supposed to avoid
The docstring's "cheap short-circuit" only guards the
count_atomsprobe.transp_summary()— the per-atomcmd.iterateover the whole object (appkit_inspector.py:191) — runs unconditionally, even for an object showing onlylines, where no rep inREP_TRANSPcan be transparent and the answer is alwaysFalse.Inverting it (probe which of the ~3 transparency-capable reps are actually shown, then scan only those settings — or skip the scan entirely when none are) is cheap: a per-rep
count_atomsis a C++ selector pass over one object, measured at ~0.3 ms against ~38 ms for the Python per-atom scan.It would also shrink the scan itself. The iterate expression is built from all of
TRANSP_SETTINGS:Narrowing it to the settings whose rep is shown drops the per-atom namespace lookups from 4 to 2 for a cartoon-only object. That matters because each lookup that misses goes through a raised and string-formatted
AttributeErrorin PyMOL's iterate namespace —PyErr_Format/PyUnicode_FromFormatVwere the hot leaves in the profile in #270.2. Disabled objects are scanned
poll_panel()computeshas_transpfor every object inpublic_objects, enabled or not. Hiding objects to make a heavy session manageable therefore doesn't help. Measured on the 12-object / 79,568-atom session from #270, with 10 of 12 objects disabled:A disabled object's row is still drawn in the panel, so its badge is arguably still wanted — but it can't change while hidden, so at minimum it shouldn't be rescanned on every invalidation.
Suggested fix
Compute the shown-rep set first; skip
transp_summary()entirely when no transparency-capable rep is active, and pass it the narrowed setting list otherwise. Keep the#219non-molecular guard and the#256group behaviour intact —testing/tests/test_appkit_objpanel_poll.pycovers both.