在 buildbot master.cfg 文件的上下文中,如何使用本机模块基于字符串实例化 class
In the context of a buildbot master.cfg file, how do I instantiate a class based on a string using native modules
有现货 python,我可以执行以下操作,根据包含其名称的字符串实例化 class:
#!/usr/bin/env python2.7
import sys
class Foo(object): pass
cls = getattr(sys.modules[__name__], 'Foo')
instance = cls()
print repr(instance)
输出如下:
ahammond@af6119›~⁑ ./test.py
<__main__.Foo object at 0x1095b0a10>
我想在 buildbot master.cfg 文件中做一些类似的事情,但是下面的(简化)
class BaseBuild(object): pass
class BuildStashToSrpmsToRpmsToDepot(BaseBuild):
def init(name, build_type):
self.name = name
def setup():
pass # actually does stuff here, but...
for build_name, build_options in config['builds'].iteritems():
cls = getattr(sys.modules[__name__], build_options['build_type'])
build = cls(name=build_name, **build_options)
build.setup()
生产
2015-03-11 18:39:24-0700 [-] error while parsing config file:
Traceback (most recent call last):
File "/opt/buildbot_virtualenv/lib/python2.7/site-packages/twisted/internet/defer.py", line 577, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File "/opt/buildbot_virtualenv/lib/python2.7/site- packages/twisted/internet/defer.py", line 1155, in gotResult
_inlineCallbacks(r, g, deferred)
File "/opt/buildbot_virtualenv/lib/python2.7/site-packages/twisted/internet/defer.py", line 1099, in _inlineCallbacks
result = g.send(result)
File "/opt/buildbot_git/master/buildbot/master.py", line 189, in startService
self.configFileName)
--- <exception caught here> ---
File "/opt/buildbot_git/master/buildbot/config.py", line 156, in loadConfig
exec f in localDict
File "/home/buildbot/master.cfg", line 208, in <module>
cls = getattr(sys.modules[__name__], build_options['build_type'])
exceptions.AttributeError: 'module' object has no attribute 'BuildStashToSrpmsToRpmsToDepot'
2015-03-11 18:39:24-0700 [-] Configuration Errors:
2015-03-11 18:39:24-0700 [-] error while parsing config file: 'module' object has no attribute 'BuildStashToSrpmsToRpmsToDepot' (traceback in logfile)
换句话说,我想我真正想问的是加载新 master.cfg
时使用的临时模块是什么,我如何引用它?
我目前正在使用 { 'class name': class_object } 的字典映射,但我更喜欢更原生的东西。
你的问题是:当 运行 buildbot 时,你的 dunder 名称(__ name __ 没有空格...)当 buildbot exec 你的配置是 buildbot.config,这就是为什么 'module object has no attribute...'.
我想你可以做任何你想做的事,使 build_options 字典的值成为 class 本身,而不是具有 class 名称的字符串。像这样:
class BaseBuild(object): pass
class BuildStashToSrpmsToRpmsToDepot(BaseBuild):
def init(name, build_type):
self.name = name
def setup():
pass # actually does stuff here, but...
# here the dict goes with key/class not key/class name
build_options = {'build_type': BuildStashToSrpmsToRpmsToDepot}
for build_name, build_options in config['builds'].iteritems():
cls = build_options['build_type']
build = cls(name=build_name, **build_options)
build.setup()
以防万一,这就是 buildbot exec master.cfg(模块 buildbot.config)的方式:
# ...
# execute the config file
localDict = {
'basedir': os.path.expanduser(basedir),
'__file__': os.path.abspath(filename),
}
# from here on out we can batch errors together for the user's
# convenience
global _errors
_errors = errors = ConfigErrors()
old_sys_path = sys.path[:]
sys.path.append(basedir)
try:
try:
exec f in localDict
except ConfigErrors, e:
for err in e.errors:
error(err)
raise errors
except:
log.err(failure.Failure(), 'error while parsing config file:')
error("error while parsing config file: %s (traceback in logfile)" % (sys.exc_info()[1],),)
raise errors
finally:
f.close()
sys.path[:] = old_sys_path
_errors = None
# ...
好的,那么问题来了:
cls = getattr(sys.modules[__name__], build_options['build_type'])
这不起作用,因为 exec
使得 __name__
具有值 "__builtin__"
。但是,您可以使用 globals()
获取当前全局变量:
cls = globals()[build_options['build_type']]
例如,如果我将以下代码添加到一个全新的 master.cfg
文件(由 buildbot create-master master
自动创建的文件,从 master.cfg.sample
重命名):
# Load the configuration from somewhere.
import json
config = json.load(open("./config.json"))
class BaseBuild(object):
pass
class Something(BaseBuild):
def __init__(self, name, build_type):
self.name = name
def setup(self):
print self.name, "something setup called"
class SomethingElse(BaseBuild):
def __init__(self, name, build_type):
self.name = name
def setup(self):
print self.name, "something else setup called"
for build_name, build_options in config['builds'].iteritems():
cls = globals()[build_options['build_type']]
build = cls(name=build_name, **build_options)
build.setup()
然后我在与 master.cfg
相同的目录中创建以下 config.json
文件:
{
"builds": {
"one": {
"build_type": "Something"
},
"two": {
"build_type": "SomethingElse"
}
}
}
然后当我 运行 buildbot start master
时,我会在日志中得到这些行:
2015-03-13 12:11:05-0400 [-] two something else setup called
2015-03-13 12:11:05-0400 [-] one something setup called
有现货 python,我可以执行以下操作,根据包含其名称的字符串实例化 class:
#!/usr/bin/env python2.7
import sys
class Foo(object): pass
cls = getattr(sys.modules[__name__], 'Foo')
instance = cls()
print repr(instance)
输出如下:
ahammond@af6119›~⁑ ./test.py
<__main__.Foo object at 0x1095b0a10>
我想在 buildbot master.cfg 文件中做一些类似的事情,但是下面的(简化)
class BaseBuild(object): pass
class BuildStashToSrpmsToRpmsToDepot(BaseBuild):
def init(name, build_type):
self.name = name
def setup():
pass # actually does stuff here, but...
for build_name, build_options in config['builds'].iteritems():
cls = getattr(sys.modules[__name__], build_options['build_type'])
build = cls(name=build_name, **build_options)
build.setup()
生产
2015-03-11 18:39:24-0700 [-] error while parsing config file:
Traceback (most recent call last):
File "/opt/buildbot_virtualenv/lib/python2.7/site-packages/twisted/internet/defer.py", line 577, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File "/opt/buildbot_virtualenv/lib/python2.7/site- packages/twisted/internet/defer.py", line 1155, in gotResult
_inlineCallbacks(r, g, deferred)
File "/opt/buildbot_virtualenv/lib/python2.7/site-packages/twisted/internet/defer.py", line 1099, in _inlineCallbacks
result = g.send(result)
File "/opt/buildbot_git/master/buildbot/master.py", line 189, in startService
self.configFileName)
--- <exception caught here> ---
File "/opt/buildbot_git/master/buildbot/config.py", line 156, in loadConfig
exec f in localDict
File "/home/buildbot/master.cfg", line 208, in <module>
cls = getattr(sys.modules[__name__], build_options['build_type'])
exceptions.AttributeError: 'module' object has no attribute 'BuildStashToSrpmsToRpmsToDepot'
2015-03-11 18:39:24-0700 [-] Configuration Errors:
2015-03-11 18:39:24-0700 [-] error while parsing config file: 'module' object has no attribute 'BuildStashToSrpmsToRpmsToDepot' (traceback in logfile)
换句话说,我想我真正想问的是加载新 master.cfg
时使用的临时模块是什么,我如何引用它?
我目前正在使用 { 'class name': class_object } 的字典映射,但我更喜欢更原生的东西。
你的问题是:当 运行 buildbot 时,你的 dunder 名称(__ name __ 没有空格...)当 buildbot exec 你的配置是 buildbot.config,这就是为什么 'module object has no attribute...'.
我想你可以做任何你想做的事,使 build_options 字典的值成为 class 本身,而不是具有 class 名称的字符串。像这样:
class BaseBuild(object): pass
class BuildStashToSrpmsToRpmsToDepot(BaseBuild):
def init(name, build_type):
self.name = name
def setup():
pass # actually does stuff here, but...
# here the dict goes with key/class not key/class name
build_options = {'build_type': BuildStashToSrpmsToRpmsToDepot}
for build_name, build_options in config['builds'].iteritems():
cls = build_options['build_type']
build = cls(name=build_name, **build_options)
build.setup()
以防万一,这就是 buildbot exec master.cfg(模块 buildbot.config)的方式:
# ...
# execute the config file
localDict = {
'basedir': os.path.expanduser(basedir),
'__file__': os.path.abspath(filename),
}
# from here on out we can batch errors together for the user's
# convenience
global _errors
_errors = errors = ConfigErrors()
old_sys_path = sys.path[:]
sys.path.append(basedir)
try:
try:
exec f in localDict
except ConfigErrors, e:
for err in e.errors:
error(err)
raise errors
except:
log.err(failure.Failure(), 'error while parsing config file:')
error("error while parsing config file: %s (traceback in logfile)" % (sys.exc_info()[1],),)
raise errors
finally:
f.close()
sys.path[:] = old_sys_path
_errors = None
# ...
好的,那么问题来了:
cls = getattr(sys.modules[__name__], build_options['build_type'])
这不起作用,因为 exec
使得 __name__
具有值 "__builtin__"
。但是,您可以使用 globals()
获取当前全局变量:
cls = globals()[build_options['build_type']]
例如,如果我将以下代码添加到一个全新的 master.cfg
文件(由 buildbot create-master master
自动创建的文件,从 master.cfg.sample
重命名):
# Load the configuration from somewhere.
import json
config = json.load(open("./config.json"))
class BaseBuild(object):
pass
class Something(BaseBuild):
def __init__(self, name, build_type):
self.name = name
def setup(self):
print self.name, "something setup called"
class SomethingElse(BaseBuild):
def __init__(self, name, build_type):
self.name = name
def setup(self):
print self.name, "something else setup called"
for build_name, build_options in config['builds'].iteritems():
cls = globals()[build_options['build_type']]
build = cls(name=build_name, **build_options)
build.setup()
然后我在与 master.cfg
相同的目录中创建以下 config.json
文件:
{
"builds": {
"one": {
"build_type": "Something"
},
"two": {
"build_type": "SomethingElse"
}
}
}
然后当我 运行 buildbot start master
时,我会在日志中得到这些行:
2015-03-13 12:11:05-0400 [-] two something else setup called
2015-03-13 12:11:05-0400 [-] one something setup called