我正在尝试使用dir()
命令在Python中打印Object的所有属性。
if self.play:
for props in dir(self.play):
f.write('\n%s:::%s'%(props, getattr(self.play, props)))
但是当我执行这个命令时,我得到了,
AttributeError: su
(f.write(...)
行上没有除追踪之外的其他信息。
所以,我在Play
类中搜索了名为su
的属性,但我根本找不到它。
它对su
的唯一引用就是这样的init方法(只发布相关的行),
class Play(object):
def __init__(self, ds):
self._ds = ds
self.become = ds['su']
Play
未覆盖__dir__()
方法。
那么,为什么我会收到此错误以及如何避免错误?
我正在使用 Python 2.7 ,如果这是相关的,我对Python编程很新,所以请以新手理解的方式回答。
附加堆栈跟踪和Play
类的完整代码。
错误:
Traceback (most recent call last):
File "/usr/local/bin/ansible-playbook", line 5, in <module>
pkg_resources.run_script('ansible==1.9.2', 'ansible-playbook')
File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 528, in run_script
self.require(requires)[0].run_script(script_name, ns)
File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 1394, in run_script
execfile(script_filename, namespace, namespace)
File "/usr/local/lib/python2.7/dist-packages/ansible-1.9.2-py2.7.egg/EGG-INFO/scripts/ansible-playbook", line 324, in <module>
sys.exit(main(sys.argv[1:]))
File "/usr/local/lib/python2.7/dist-packages/ansible-1.9.2-py2.7.egg/EGG-INFO/scripts/ansible-playbook", line 264, in main
pb.run()
File "/usr/local/lib/python2.7/dist-packages/ansible-1.9.2-py2.7.egg/ansible/playbook/__init__.py", line 348, in run
if not self._run_play(play):
File "/usr/local/lib/python2.7/dist-packages/ansible-1.9.2-py2.7.egg/ansible/playbook/__init__.py", line 730, in _run_play
self.callbacks.on_play_start(play.name)
File "/usr/local/lib/python2.7/dist-packages/ansible-1.9.2-py2.7.egg/ansible/callbacks.py", line 720, in on_play_start
call_callback_module('playbook_on_play_start', name)
File "/usr/local/lib/python2.7/dist-packages/ansible-1.9.2-py2.7.egg/ansible/callbacks.py", line 179, in call_callback_module
method(*args, **kwargs)
File "/home/mobins/ansibletemp/callback_plugins/email_reporter.py", line 210, in playbook_on_play_start
self.writeProp(f)
File "/home/mobins/ansibletemp/callback_plugins/email_reporter.py", line 18, in writeProp
f.write('\n%s:::%s'%(props, getattr(self.play, props)))
AttributeError: su
玩类:
class Play(object):
_pb_common = [
'accelerate', 'accelerate_ipv6', 'accelerate_port', 'any_errors_fatal', 'become',
'become_method', 'become_user', 'environment', 'force_handlers', 'gather_facts',
'handlers', 'hosts', 'name', 'no_log', 'remote_user', 'roles', 'serial', 'su',
'su_user', 'sudo', 'sudo_user', 'tags', 'vars', 'vars_files', 'vars_prompt',
'vault_password',
]
__slots__ = _pb_common + [
'_ds', '_handlers', '_play_hosts', '_tasks', 'any_errors_fatal', 'basedir',
'default_vars', 'included_roles', 'max_fail_pct', 'playbook', 'remote_port',
'role_vars', 'transport', 'vars_file_vars',
]
# to catch typos and so forth -- these are userland names
# and don't line up 1:1 with how they are stored
VALID_KEYS = frozenset(_pb_common + [
'connection', 'include', 'max_fail_percentage', 'port', 'post_tasks',
'pre_tasks', 'role_names', 'tasks', 'user',
])
# *************************************************
def __init__(self, playbook, ds, basedir, vault_password=None):
''' constructor loads from a play datastructure '''
for x in ds.keys():
if not x in Play.VALID_KEYS:
raise errors.AnsibleError("%s is not a legal parameter of an Ansible Play" % x)
# allow all playbook keys to be set by --extra-vars
self.vars = ds.get('vars', {})
self.vars_prompt = ds.get('vars_prompt', {})
self.playbook = playbook
self.vars = self._get_vars()
self.vars_file_vars = dict() # these are vars read in from vars_files:
self.role_vars = dict() # these are vars read in from vars/main.yml files in roles
self.basedir = basedir
self.roles = ds.get('roles', None)
self.tags = ds.get('tags', None)
self.vault_password = vault_password
self.environment = ds.get('environment', {})
if self.tags is None:
self.tags = []
elif type(self.tags) in [ str, unicode ]:
self.tags = self.tags.split(",")
elif type(self.tags) != list:
self.tags = []
# make sure we have some special internal variables set, which
# we use later when loading tasks and handlers
load_vars = dict()
load_vars['playbook_dir'] = os.path.abspath(self.basedir)
if self.playbook.inventory.basedir() is not None:
load_vars['inventory_dir'] = self.playbook.inventory.basedir()
if self.playbook.inventory.src() is not None:
load_vars['inventory_file'] = self.playbook.inventory.src()
# We first load the vars files from the datastructure
# so we have the default variables to pass into the roles
self.vars_files = ds.get('vars_files', [])
if not isinstance(self.vars_files, list):
raise errors.AnsibleError('vars_files must be a list')
processed_vars_files = self._update_vars_files_for_host(None)
# now we load the roles into the datastructure
self.included_roles = []
ds = self._load_roles(self.roles, ds)
# and finally re-process the vars files as they may have been updated
# by the included roles, but exclude any which have been processed
self.vars_files = utils.list_difference(ds.get('vars_files', []), processed_vars_files)
if not isinstance(self.vars_files, list):
raise errors.AnsibleError('vars_files must be a list')
self._update_vars_files_for_host(None)
# template everything to be efficient, but do not pre-mature template
# tasks/handlers as they may have inventory scope overrides. We also
# create a set of temporary variables for templating, so we don't
# trample on the existing vars structures
_tasks = ds.pop('tasks', [])
_handlers = ds.pop('handlers', [])
temp_vars = utils.combine_vars(self.vars, self.vars_file_vars)
temp_vars = utils.combine_vars(temp_vars, self.playbook.extra_vars)
try:
ds = template(basedir, ds, temp_vars)
except errors.AnsibleError, e:
utils.warning("non fatal error while trying to template play variables: %s" % (str(e)))
ds['tasks'] = _tasks
ds['handlers'] = _handlers
self._ds = ds
hosts = ds.get('hosts')
if hosts is None:
raise errors.AnsibleError('hosts declaration is required')
elif isinstance(hosts, list):
try:
hosts = ';'.join(hosts)
except TypeError,e:
raise errors.AnsibleError('improper host declaration: %s' % str(e))
self.serial = str(ds.get('serial', 0))
self.hosts = hosts
self.name = ds.get('name', self.hosts)
self._tasks = ds.get('tasks', [])
self._handlers = ds.get('handlers', [])
self.remote_user = ds.get('remote_user', ds.get('user', self.playbook.remote_user))
self.remote_port = ds.get('port', self.playbook.remote_port)
self.transport = ds.get('connection', self.playbook.transport)
self.remote_port = self.remote_port
self.any_errors_fatal = utils.boolean(ds.get('any_errors_fatal', 'false'))
self.accelerate = utils.boolean(ds.get('accelerate', 'false'))
self.accelerate_port = ds.get('accelerate_port', None)
self.accelerate_ipv6 = ds.get('accelerate_ipv6', False)
self.max_fail_pct = int(ds.get('max_fail_percentage', 100))
self.no_log = utils.boolean(ds.get('no_log', 'false'))
self.force_handlers = utils.boolean(ds.get('force_handlers', self.playbook.force_handlers))
# Fail out if user specifies conflicting privelege escalations
if (ds.get('become') or ds.get('become_user')) and (ds.get('sudo') or ds.get('sudo_user')):
raise errors.AnsibleError('sudo params ("become", "become_user") and su params ("sudo", "sudo_user") cannot be used together')
if (ds.get('become') or ds.get('become_user')) and (ds.get('su') or ds.get('su_user')):
raise errors.AnsibleError('sudo params ("become", "become_user") and su params ("su", "su_user") cannot be used together')
if (ds.get('sudo') or ds.get('sudo_user')) and (ds.get('su') or ds.get('su_user')):
raise errors.AnsibleError('sudo params ("sudo", "sudo_user") and su params ("su", "su_user") cannot be used together')
# become settings are inherited and updated normally
self.become = ds.get('become', self.playbook.become)
self.become_method = ds.get('become_method', self.playbook.become_method)
self.become_user = ds.get('become_user', self.playbook.become_user)
# Make sure current play settings are reflected in become fields
if 'sudo' in ds:
self.become=ds['sudo']
self.become_method='sudo'
if 'sudo_user' in ds:
self.become_user=ds['sudo_user']
elif 'su' in ds:
self.become=True
self.become=ds['su']
self.become_method='su'
if 'su_user' in ds:
self.become_user=ds['su_user']
# gather_facts is not a simple boolean, as None means that a 'smart'
# fact gathering mode will be used, so we need to be careful here as
# calling utils.boolean(None) returns False
self.gather_facts = ds.get('gather_facts', None)
if self.gather_facts is not None:
self.gather_facts = utils.boolean(self.gather_facts)
load_vars['role_names'] = ds.get('role_names', [])
self._tasks = self._load_tasks(self._ds.get('tasks', []), load_vars)
self._handlers = self._load_tasks(self._ds.get('handlers', []), load_vars)
# apply any missing tags to role tasks
self._late_merge_role_tags()
# place holder for the discovered hosts to be used in this play
self._play_hosts = None
正如您可能已经猜到的那样,Play
类来自一个名为 ansible 的工具,因为我不太清楚它的代码和它的调用结构,所以我遇到了困难调试时间。
我只是希望这个错误在使用dir()
时很常见,有人会遇到它。但如果情况并非如此,我认为我应该使用其他一些方法,而不是过于担心调试它。
答案 0 :(得分:1)
当您定义__slots__
时,即使您没有为其分配任何值,也会显示属性:
>>> class foo(object):
... __slots__ = 'a', 'b'
...
>>> x = foo()
>>> dir(x)
[..., 'a', 'b']
忽略未设置的简单方法是将其用于getattr()
的默认参数。如果None
是您的任何变量的有效值(可能),那么您可以创建一个特殊的Undefined
类,仅用于显示尚未设置变量:
>>> class Undefined:
... pass
...
>>> for name in dir(x):
... value = getattr(x, name, Undefined) # Default to Undefined
... print name, value
...
__class__ <class '__main__.foo'>
__delattr__ <method-wrapper '__delattr__' of foo object at 0xb6a5e1cc>
__doc__ None
__format__ <built-in method __format__ of foo object at 0xb6a5e1cc>
__getattribute__ <method-wrapper '__getattribute__' of foo object at 0xb6a5e1cc>
__hash__ <method-wrapper '__hash__' of foo object at 0xb6a5e1cc>
__init__ <method-wrapper '__init__' of foo object at 0xb6a5e1cc>
__module__ __main__
__new__ <built-in method __new__ of type object at 0x8335200>
__reduce__ <built-in method __reduce__ of foo object at 0xb6a5e1cc>
__reduce_ex__ <built-in method __reduce_ex__ of foo object at 0xb6a5e1cc>
__repr__ <method-wrapper '__repr__' of foo object at 0xb6a5e1cc>
__setattr__ <method-wrapper '__setattr__' of foo object at 0xb6a5e1cc>
__sizeof__ <built-in method __sizeof__ of foo object at 0xb6a5e1cc>
__slots__ ('a', 'b')
__str__ <method-wrapper '__str__' of foo object at 0xb6a5e1cc>
__subclasshook__ <built-in method __subclasshook__ of type object at 0xb6d9d82c>
a __main__.Undefined
b __main__.Undefined
如果value is Undefined
,您将可以轻松地在循环中进行测试,以忽略任何结果。