getowner need now an option

This commit is contained in:
Emmanuel Garette 2013-08-24 22:32:54 +02:00
parent 4c27cb586d
commit e4c129efc5
10 changed files with 106 additions and 98 deletions

View file

@ -94,6 +94,7 @@ def test_make_dict():
assert d == {"s1.a": True, "int": 43}
d2 = config.make_dict(flatten=True)
assert d2 == {'a': True, 'int': 43}
raises(ValueError, 'd2 = config.make_dict(withvalue="3")')
def test_find_in_config():

View file

@ -141,15 +141,15 @@ def test_freeze_get_multi():
def test_force_store_value():
descr = make_description_freeze()
conf = Config(descr)
assert conf.getowner('wantref') == 'default'
assert conf.getowner(conf.unwrap_from_path('wantref')) == 'default'
conf.wantref
assert conf.getowner('wantref') == 'user'
assert conf.getowner(conf.unwrap_from_path('wantref')) == 'user'
def test_force_store_value_ro():
descr = make_description_freeze()
conf = Config(descr)
conf.read_only()
assert conf.getowner('wantref') == 'default'
assert conf.getowner(conf.unwrap_from_path('wantref')) == 'default'
conf.wantref
assert conf.getowner('wantref') == 'user'
assert conf.getowner(conf.unwrap_from_path('wantref')) == 'user'

View file

@ -71,7 +71,7 @@ def test_mandatory_none():
descr = make_description()
config = Config(descr)
config.str1 = None
assert config.getowner('str1') == 'user'
assert config.getowner(config.unwrap_from_path('str1')) == 'user'
config.read_only()
prop = []
try:
@ -85,7 +85,7 @@ def test_mandatory_empty():
descr = make_description()
config = Config(descr)
config.str1 = ''
assert config.getowner('str1') == 'user'
assert config.getowner(config.unwrap_from_path('str1')) == 'user'
config.read_only()
prop = []
try:
@ -100,7 +100,7 @@ def test_mandatory_multi_none():
config = Config(descr)
config.str3 = [None]
config.read_only()
assert config.getowner('str3') == 'user'
assert config.getowner(config.unwrap_from_path('str3')) == 'user'
prop = []
try:
config.str3
@ -110,7 +110,7 @@ def test_mandatory_multi_none():
config.read_write()
config.str3 = ['yes', None]
config.read_only()
assert config.getowner('str3') == 'user'
assert config.getowner(config.unwrap_from_path('str3')) == 'user'
prop = []
try:
config.str3
@ -124,7 +124,7 @@ def test_mandatory_multi_empty():
config = Config(descr)
config.str3 = ['']
config.read_only()
assert config.getowner('str3') == 'user'
assert config.getowner(config.unwrap_from_path('str3')) == 'user'
prop = []
try:
config.str3
@ -134,7 +134,7 @@ def test_mandatory_multi_empty():
config.read_write()
config.str3 = ['yes', '']
config.read_only()
assert config.getowner('str3') == 'user'
assert config.getowner(config.unwrap_from_path('str3')) == 'user'
prop = []
try:
config.str3

View file

@ -31,69 +31,69 @@ def test_none():
meta = make_description()
conf1, conf2 = meta._impl_children
assert conf1.od1.i3 is conf2.od1.i3 is None
assert conf1.getowner('od1.i3') is conf2.getowner('od1.i3') is owners.default
assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.default
meta.od1.i3 = 3
assert conf1.od1.i3 == conf2.od1.i3 == 3
assert conf1.getowner('od1.i3') is conf2.getowner('od1.i3') is owners.meta
assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.meta
meta.od1.i3 = 3
conf1.od1.i3 = 2
assert conf1.od1.i3 == 2
assert conf2.od1.i3 == 3
assert conf1.getowner('od1.i3') is owners.user
assert conf2.getowner('od1.i3') is owners.meta
assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is owners.user
assert conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.meta
meta.od1.i3 = 4
assert conf1.od1.i3 == 2
assert conf2.od1.i3 == 4
assert conf1.getowner('od1.i3') is owners.user
assert conf2.getowner('od1.i3') is owners.meta
assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is owners.user
assert conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.meta
del(meta.od1.i3)
assert conf1.od1.i3 == 2
assert conf2.od1.i3 is None
assert conf1.getowner('od1.i3') is owners.user
assert conf2.getowner('od1.i3') is owners.default
assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is owners.user
assert conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.default
del(conf1.od1.i3)
assert conf1.od1.i3 is conf2.od1.i3 is None
assert conf1.getowner('od1.i3') is conf2.getowner('od1.i3') is owners.default
assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.default
def test_default():
meta = make_description()
conf1, conf2 = meta._impl_children
assert conf1.od1.i2 == conf2.od1.i2 == 1
assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.default
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default
meta.od1.i2 = 3
assert conf1.od1.i2 == conf2.od1.i2 == 3
assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.meta
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta
meta.od1.i2 = 3
conf1.od1.i2 = 2
assert conf1.od1.i2 == 2
assert conf2.od1.i2 == 3
assert conf1.getowner('od1.i2') is owners.user
assert conf2.getowner('od1.i2') is owners.meta
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user
assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta
meta.od1.i2 = 4
assert conf1.od1.i2 == 2
assert conf2.od1.i2 == 4
assert conf1.getowner('od1.i2') is owners.user
assert conf2.getowner('od1.i2') is owners.meta
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user
assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta
del(meta.od1.i2)
assert conf1.od1.i2 == 2
assert conf2.od1.i2 == 1
assert conf1.getowner('od1.i2') is owners.user
assert conf2.getowner('od1.i2') is owners.default
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user
assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default
del(conf1.od1.i2)
assert conf1.od1.i2 == conf2.od1.i2 == 1
assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.default
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default
def test_contexts():
meta = make_description()
conf1, conf2 = meta._impl_children
assert conf1.od1.i2 == conf2.od1.i2 == 1
assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.default
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default
meta.set_contexts('od1.i2', 6)
assert meta.od1.i2 == 1
assert conf1.od1.i2 == conf2.od1.i2 == 6
assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.user
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.user
def test_find():
@ -110,32 +110,32 @@ def test_meta_meta():
meta2.cfgimpl_get_settings().setowner(owners.meta)
conf1, conf2 = meta1._impl_children
assert conf1.od1.i2 == conf2.od1.i2 == 1
assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.default
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default
meta2.od1.i2 = 3
assert conf1.od1.i2 == conf2.od1.i2 == 3
assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.meta
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta
meta2.od1.i2 = 3
conf1.od1.i2 = 2
assert conf1.od1.i2 == 2
assert conf2.od1.i2 == 3
assert conf1.getowner('od1.i2') is owners.user
assert conf2.getowner('od1.i2') is owners.meta
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user
assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta
meta2.od1.i2 = 4
assert conf1.od1.i2 == 2
assert conf2.od1.i2 == 4
assert conf1.getowner('od1.i2') is owners.user
assert conf2.getowner('od1.i2') is owners.meta
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user
assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta
del(meta2.od1.i2)
assert conf1.od1.i2 == 2
assert conf2.od1.i2 == 1
assert conf1.getowner('od1.i2') is owners.user
assert conf2.getowner('od1.i2') is owners.default
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user
assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default
del(conf1.od1.i2)
assert conf1.od1.i2 == conf2.od1.i2 == 1
assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.default
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default
meta1.od1.i2 = 6
assert conf1.od1.i2 == conf2.od1.i2 == 6
assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.meta
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta
def test_meta_meta_set():
@ -145,7 +145,7 @@ def test_meta_meta_set():
conf1, conf2 = meta1._impl_children
meta2.set_contexts('od1.i1', 7)
assert conf1.od1.i1 == conf2.od1.i1 == 7
assert conf1.getowner('od1.i1') is conf2.getowner('od1.i1') is owners.user
assert conf1.getowner(conf1.unwrap_from_path('od1.i1')) is conf2.getowner(conf2.unwrap_from_path('od1.i1')) is owners.user
assert [conf1, conf2] == meta2.find_first_contexts(byname='i1', byvalue=7)
conf1.od1.i1 = 8
assert [conf2] == meta2.find_first_contexts(byname='i1', byvalue=7)
@ -164,7 +164,7 @@ def test_not_meta():
conf1, conf2 = meta._impl_children
meta.set_contexts('od1.i1', 7)
assert conf1.od1.i1 == conf2.od1.i1 == 7
assert conf1.getowner('od1.i1') is conf2.getowner('od1.i1') is owners.user
assert conf1.getowner(conf1.unwrap_from_path('od1.i1')) is conf2.getowner(conf2.unwrap_from_path('od1.i1')) is owners.user
def test_meta_path():

View file

@ -52,9 +52,9 @@ def test_consistency_default_diff():
raises(ValueError, "c.a = 1")
c.a = 2
c.b = 3
assert c.getowner('a') is owners.user
assert c.getowner(a) is owners.user
raises(ValueError, "del(c.a)")
assert c.getowner('a') is owners.user
assert c.getowner(a) is owners.user
def test_consistency_ip_netmask():

View file

@ -34,9 +34,9 @@ def test_default_owner():
descr = OptionDescription('tiramisu', '', [gcdummy])
cfg = Config(descr)
assert cfg.dummy is False
assert cfg.getowner('dummy') == 'default'
assert cfg.getowner(gcdummy) == 'default'
cfg.dummy = True
assert cfg.getowner('dummy') == owners.user
assert cfg.getowner(gcdummy) == owners.user
def test_add_owner():
@ -44,11 +44,11 @@ def test_add_owner():
descr = OptionDescription('tiramisu', '', [gcdummy])
cfg = Config(descr)
assert cfg.dummy is False
assert cfg.getowner('dummy') == 'default'
assert cfg.getowner(gcdummy) == 'default'
owners.add_owner("gen_config")
cfg.cfgimpl_get_settings().setowner(owners.gen_config)
cfg.dummy = True
assert cfg.getowner('dummy') == owners.gen_config
assert cfg.getowner(gcdummy) == owners.gen_config
def test_owner_is_not_a_string():
@ -56,11 +56,11 @@ def test_owner_is_not_a_string():
descr = OptionDescription('tiramisu', '', [gcdummy])
cfg = Config(descr)
assert cfg.dummy is False
assert cfg.getowner('dummy') == owners.default
assert cfg.getowner('dummy') == 'default'
assert isinstance(cfg.getowner('dummy'), owners.Owner)
assert cfg.getowner(gcdummy) == owners.default
assert cfg.getowner(gcdummy) == 'default'
assert isinstance(cfg.getowner(gcdummy), owners.Owner)
cfg.dummy = True
assert cfg.getowner('dummy') == 'user'
assert cfg.getowner(gcdummy) == 'user'
def test_setowner_without_valid_owner():
@ -68,5 +68,5 @@ def test_setowner_without_valid_owner():
descr = OptionDescription('tiramisu', '', [gcdummy])
cfg = Config(descr)
assert cfg.dummy is False
assert cfg.getowner('dummy') == 'default'
assert cfg.getowner(gcdummy) == 'default'
raises(TypeError, "cfg.cfgimpl_get_settings().setowner('gen_config')")

View file

@ -56,10 +56,10 @@ def test_reset():
config = Config(descr)
config.string = "foo"
assert config.string == "foo"
assert config.getowner('string') == owners.user
assert config.getowner(s) == owners.user
del(config.string)
assert config.string == 'string'
assert config.getowner('string') == owners.default
assert config.getowner(s) == owners.default
def test_reset_with_multi():
@ -69,13 +69,13 @@ def test_reset_with_multi():
# config.string = []
del(config.string)
assert config.string == ["string"]
assert config.getowner('string') == 'default'
assert config.getowner(s) == 'default'
config.string = ["eggs", "spam", "foo"]
assert config.getowner('string') == 'user'
assert config.getowner(s) == 'user'
config.string = []
del(config.string)
# assert config.string == ["string"]
assert config.getowner('string') == 'default'
assert config.getowner(s) == 'default'
raises(ValueError, "config.string = None")
@ -121,10 +121,10 @@ def test_access_with_multi_default():
s = StrOption("string", "", default=["string"], multi=True)
descr = OptionDescription("options", "", [s])
config = Config(descr)
assert config.getowner('string') == 'default'
assert config.getowner(s) == 'default'
config.string = ["foo", "bar"]
assert config.string == ["foo", "bar"]
assert config.getowner('string') == 'user'
assert config.getowner(s) == 'user'
def test_multi_with_requires():

View file

@ -63,13 +63,17 @@ def test_make_dict_filter():
descr = make_description()
config = Config(descr)
config.read_write()
result = {'general.numero_etab': None, 'general.nombre_interfaces': 1,
'general.serveur_ntp': [], 'general.mode_conteneur_actif': False,
'general.time_zone': 'Paris', 'general.nom_machine': 'eoleng',
'general.activer_proxy_client': False}
subresult = {'numero_etab': None, 'nombre_interfaces': 1,
'serveur_ntp': [], 'mode_conteneur_actif': False,
'time_zone': 'Paris', 'nom_machine': 'eoleng',
'activer_proxy_client': False}
result = {}
for key, value in subresult.items():
result['general.' + key] = value
assert config.creole.make_dict(withoption='numero_etab') == result
raises(AttributeError, "config.creole.make_dict(withoption='numero_etab', withvalue='toto')")
assert config.creole.make_dict(withoption='numero_etab', withvalue=None) == result
assert config.creole.general.make_dict(withoption='numero_etab') == subresult
def test_get_group_type():
@ -168,14 +172,14 @@ def test_values_with_master_and_slaves():
cfg.read_write()
owner = cfg.cfgimpl_get_settings().getowner()
assert interface1.impl_get_group_type() == groups.master
assert cfg.getowner("ip_admin_eth0.ip_admin_eth0") == owners.default
assert cfg.getowner("ip_admin_eth0.netmask_admin_eth0") == owners.default
assert cfg.getowner(ip_admin_eth0) == owners.default
assert cfg.getowner(netmask_admin_eth0) == owners.default
assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
assert cfg.ip_admin_eth0.ip_admin_eth0 == ["192.168.230.145"]
assert cfg.ip_admin_eth0.netmask_admin_eth0 == [None]
assert cfg.getowner("ip_admin_eth0.ip_admin_eth0") == owner
assert cfg.getowner("ip_admin_eth0.netmask_admin_eth0") == owners.default
assert cfg.getowner(ip_admin_eth0) == owner
assert cfg.getowner(netmask_admin_eth0) == owners.default
def test_reset_values_with_master_and_slaves():
@ -188,14 +192,14 @@ def test_reset_values_with_master_and_slaves():
cfg.read_write()
owner = cfg.cfgimpl_get_settings().getowner()
assert interface1.impl_get_group_type() == groups.master
assert cfg.getowner("ip_admin_eth0.ip_admin_eth0") == owners.default
assert cfg.getowner("ip_admin_eth0.netmask_admin_eth0") == owners.default
assert cfg.getowner(ip_admin_eth0) == owners.default
assert cfg.getowner(netmask_admin_eth0) == owners.default
cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
assert cfg.getowner("ip_admin_eth0.ip_admin_eth0") == owner
assert cfg.getowner("ip_admin_eth0.netmask_admin_eth0") == owners.default
assert cfg.getowner(ip_admin_eth0) == owner
assert cfg.getowner(netmask_admin_eth0) == owners.default
del(cfg.ip_admin_eth0.ip_admin_eth0)
assert cfg.getowner("ip_admin_eth0.ip_admin_eth0") == owners.default
assert cfg.getowner("ip_admin_eth0.netmask_admin_eth0") == owners.default
assert cfg.getowner(ip_admin_eth0) == owners.default
assert cfg.getowner(netmask_admin_eth0) == owners.default
assert cfg.ip_admin_eth0.ip_admin_eth0 == []
assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
@ -254,14 +258,14 @@ def test_values_with_master_owner():
cfg = Config(maconfig)
cfg.read_write()
owner = cfg.cfgimpl_get_settings().getowner()
assert cfg.getowner("ip_admin_eth0.ip_admin_eth0") == owners.default
assert cfg.getowner("ip_admin_eth0.netmask_admin_eth0") == owners.default
assert cfg.getowner(ip_admin_eth0) == owners.default
assert cfg.getowner(netmask_admin_eth0) == owners.default
cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
assert cfg.getowner("ip_admin_eth0.ip_admin_eth0") == owner
assert cfg.getowner("ip_admin_eth0.netmask_admin_eth0") == owners.default
assert cfg.getowner(ip_admin_eth0) == owner
assert cfg.getowner(netmask_admin_eth0) == owners.default
cfg.ip_admin_eth0.ip_admin_eth0.pop(0)
assert cfg.getowner("ip_admin_eth0.ip_admin_eth0") == owner
assert cfg.getowner("ip_admin_eth0.netmask_admin_eth0") == owners.default
assert cfg.getowner(ip_admin_eth0) == owner
assert cfg.getowner(netmask_admin_eth0) == owners.default
def test_values_with_master_disabled():
@ -303,10 +307,10 @@ def test_multi_insert():
c = Config(od)
c.read_write()
assert c.var == ['ok']
assert c.getowner("var") == owners.default
assert c.getowner(var) == owners.default
c.var.insert(0, 'nok')
assert c.var == ['nok', 'ok']
assert c.getowner("var") != owners.default
assert c.getowner(var) != owners.default
def test_multi_insert_master():
@ -327,10 +331,10 @@ def test_multi_sort():
c = Config(od)
c.read_write()
assert c.var == ['ok', 'nok']
assert c.getowner("var") == owners.default
assert c.getowner(var) == owners.default
c.var.sort()
assert c.var == ['nok', 'ok']
assert c.getowner("var") != owners.default
assert c.getowner(var) != owners.default
def test_multi_sort_master():
@ -351,10 +355,10 @@ def test_multi_reverse():
c = Config(od)
c.read_write()
assert c.var == ['ok', 'nok']
assert c.getowner("var") == owners.default
assert c.getowner(var) == owners.default
c.var.reverse()
assert c.var == ['nok', 'ok']
assert c.getowner("var") != owners.default
assert c.getowner(var) != owners.default
def test_multi_reverse_master():
@ -375,10 +379,10 @@ def test_multi_extend():
c = Config(od)
c.read_write()
assert c.var == ['ok', 'nok']
assert c.getowner("var") == owners.default
assert c.getowner(var) == owners.default
c.var.extend(['pok'])
assert c.var == ['ok', 'nok', 'pok']
assert c.getowner("var") != owners.default
assert c.getowner(var) != owners.default
def test_multi_extend_master():

View file

@ -1,3 +1,4 @@
# coding: utf-8
import autopath
from tiramisu.option import BoolOption, StrOption, SymLinkOption, \
@ -84,11 +85,11 @@ def test_symlink_owner():
descr = OptionDescription("opt", "",
[linkopt, OptionDescription("s1", "", [boolopt])])
config = Config(descr)
assert config.getowner('s1.b') == owners.default
assert config.getowner('c') == owners.default
assert config.getowner(boolopt) == owners.default
assert config.getowner(linkopt) == owners.default
config.c = True
assert config.getowner('s1.b') != owners.default
assert config.getowner('c') != owners.default
assert config.getowner(boolopt) != owners.default
assert config.getowner(linkopt) != owners.default
def test_symlink_get_information():
@ -112,7 +113,7 @@ def test_symlink_master():
def test_symlink_slaves():
a = StrOption('a', "", multi=True)
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
ip_admin_eth0 = StrOption('ip_admin_eth0', u"ip réseau autorisé", multi=True)
netmask_admin_eth0 = SymLinkOption('netmask_admin_eth0', a)
interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
raises(ValueError, 'interface1.impl_set_group_type(groups.master)')

View file

@ -484,11 +484,13 @@ class CommonConfig(SubConfig):
"read write is a global config's setting, see `settings.py`"
self.cfgimpl_get_settings().read_write()
def getowner(self, path):
def getowner(self, opt):
"""convenience method to retrieve an option's owner
from the config itself
"""
opt = self.cfgimpl_get_description().impl_get_opt_by_path(path)
if not isinstance(opt, Option) and not isinstance(opt, SymLinkOption):
raise TypeError(_('opt in getowner must be an option not {0}'
'').format(type(opt)))
return self.cfgimpl_get_values().getowner(opt)
def unwrap_from_path(self, path, force_permissive=False):
@ -552,7 +554,7 @@ class MetaConfig(CommonConfig):
if meta:
for child in children:
if not isinstance(child, CommonConfig):
raise ValueError(_("metaconfig's children "
raise TypeError(_("metaconfig's children "
"must be config, not {0}"
).format(type(child)))
if self._impl_descr is None: