サイトマネージャからユーティリティの登録を抹消する

供給するインターフェースやイベントリスナやユーティリティの登録の抹消に関して、Zope は全てサポートしていない。ここではユーティリティの登録の抹消について言及する。
これは zope.schema.interfaces.IField から導出されたインターフェースを供給するオブジェクト (以下フィールド) を拡張し、その定義を ZODB に格納するモジュールの作成の成果である。
まず、フィールドを作成するファクトリを動的に登録するには次のようになる。ファクトリをユーティリティとして登録することになる。

from zope.component.interfaces import IFactory
# field_factory は zope.component.interfaces.IFactory を供給し、当該のフィールドオブジェクトを生成するファクトリ
zope.component.provideUtility(field_factory, IFactory, field_id)

この内部では次のような動作が行われている。

  • zope.component.provideUtility
    • zope.component.site.GlobalSiteManager.provideUtility
      • zope.interface.adapter.AdapterRegistry.register
        • zope.interface.adapter.AdapterRegistry._null._adaptTo
          • zope.interface.adapter.AdapterRegistry._null.adapters にキー (False, (), field_id, IFactory, ) で 値 field_factory で登録。
      • zope.interface.adapter.AdapterRegistry.subscribe
        • zope.interface.adapter.AdapterRegistry._null._subscriptionAdaptTo
          • zope.interface.adapter.AdapterRegistry._null.adapters にキー (True, (), '', IFactory, ) で 値 field_factory のタプルで登録。
    • zope.component.site.GlobalSiteManager._registrations にキー (IFactory, field_id, ) で 値 zope.component.site.UtilityRegistration(IFactory, field_id, field_factory, '') を登録。

以上より、動的にユーティリティの登録を抹消するには次のようなコードとなる。

def unregister(field_factory, sitemanager):
	def detect(value):
		return value == field_factory

	for key, value in sitemanager.utilities._null.adapters.items():
		subscription, with, name, specification = key
		if specification == IFactory and detect(value):
			del sitemanager.utilities._null.adapters[key]

	key = (True, (), '', IFactory, )
	newvalue = ()
	for factory in sitemanager.utilities._null.adapters.get(key, ()):
		if not detect(factory):
			newvalue += (factory, )
	sitemanager.utilities._null.adapters[key] = newvalue

	sitemanager.utilities._null.changed()

	if hasattr(sitemanager, '_registrations'):
		for key, value in sitemanager._registrations.items():
			if key[0] == IFactory and type(value) == zope.component.site.UtilityRegistration and detect(value.component):
				del sitemanager._registrations[key]

#LocalSiteManager
unregister(field_factory, zope.component.getSiteManager(root))
#GlobalSiteManager
unregister(field_factory, zope.component.getGlobalSiteManager())