For the glossary:
- distribution
In some operating systems, the kernel of the OS is produced by one organization but this is combined with other necessary tools by a second organization. This second organization is called a distribution.
- native string
Python2 and Python3 have different types for unadorned string literals and many strings operations. In Python2, these are byte strings. In Python3, these are text strings.
Note
In very old code, modules would specify that a parameter was a boolean by listing something like this in the argument_spec
:
- module = AnsibleModule(
- argument_spec=dict(
return_status=dict(choices=BOOLEANS),
),
)
This pattern is not very flexible and can cause issues in cornercases. It should no longer be used. Switch to using the type field instead:
module = AnsibleModule( argument_spec=dict( return_status=dict(type='bool'), ), )
Core team members, should we change get_all_subclasses() to return a set/frozenset? Right now, it returns a list and elements could be repeated
Core team members, do we want to change this API? Instead of returning an instantiated class, return the class and make the caller instantiate it. Doing that will mean we don't have to pass in *args
and **kwargs
.
These globals are not for use by other code. Documenting here for people who need to modify basic.py
.
Analogs to these are either in six or one of the ansible.module_utils.pycompatXY modules:
Deprecated New Way to Achieve this ---------- -----------------------imap ansible.module_utils.six.moves.map basestring ansible.module_utils.six.string_types or (ansible.module_utils.six.text_type, ansible.module_utils.six.binary_type) unicode ansible.module_utils.six.text_type or (ansible.module_utils._text.to_native, ansible.module_utils._text.to_text) [@]_ bytes ansible.module_utils.six.binary_type or (ansible.module_utils._text.to_bytes, ansible.module_utils._text.to_native) [@]_ iteritems ansible.module_utils.six.iteritems reduce ansible.module_utils.six.moves import reduce NUMBERTYPES ansible.module_utils.six.integer_types + (float,) [+]_ NoneType ansible.module_utils.pycompat27.NoneType ## Need to move Sequence ansible.module_utils.pycompat24.Sequence ## Need to move Mapping ansible.module_utils.pycompat24.Mapping ## Need to move SEQUENCETYPE ansible.module_utils.pycompat27.SEQUENCETYPE ## Need to move json ansible.module_utils.pycompat24.json ## Need to move literal_eval ansible.module_utils.pycompat24.literal_eval get_exception ansible.module_utils.pycompat24.get_exception
- if not isinstance(variable, basestring):
# Get the string representation of the object variable = str(variable)
- if not isinstance(variable, unicode):
# Make sure a string is unicode for the API we're calling variable = unicode(variable, 'utf-'8')
Those should be replaced with code like this:
if not isinstance(variable, (six.binary_type, six.text_type)): # Get the string representation of the object variable = to_native(variable, errors='surrogate_or_strict') if not isinstance(variable, six.text_type): # Make sure a string is the platform's text type (unicode on py2, str on py3) variable = to_text(variable, 'utf-8')
For converting between text and bytes use
ansible.module_utils._text.to_text
andansible.module_utils._text.to_bytes
:# Original: text_string = unicode("Toshio wrote this", encoding='utf-8') byte_string = bytes(u"Toshio wrote this", 'utf-8') # New: text_string = to_text("Toshio wrote this", errors='surrogate_or_strict') byte_string = to_bytes(u"Toshio wrote this", errors='surrogate_or_strict')
For converting between an unknown object and its string representation (for instance, for printing an informational error message), use the
nonstring
argument to to_text and `to_bytes`:# Original: text_msg = u'Error: Can not process: %s' % unicode({'An object': 'value'}, encoding='utf-8') byte_msg = 'Error: Can not process: %s' % bytes({'An object': 'value'}, 'utf-8') # New: text_msg = u'Error: Can not process: %s' % to_text({'An object': 'value'}, nonstring='simplerepr') byte_msg = to_bytes('Error: Can not process: %s' % to_native({'An object': 'value'}, nonstring='simplerepr')) # byte_msg is different because the original was not safe on python3
For testing whether a value is a text or byte string:
# Original: if isinstance('string', unicode): pass if isinstance('string', bytes): pass # New: if isinstance('string', text_type): pass if isinstance('string', binary_type): pass # Old code: from ansible.module_utils.basic import NUMBERTYPES if isinstance(obj, NUMBERTYPES): return str(obj) from ansible.module_utils.six import integer_types # New code: if isinstance(obj, integer_types + (float,)): return str(obj)
Move the deprecated values that belong in pycompatXY into those files.
Ansible Core Team -- do we want to make an ansible.module_utils.json with this and other json-related functions? (Or put this into a pycompat* as it's only for python-2.4 which doesn't have the stdlib json library)?
Rename these to have a leading underscore to mark them as private
If we switch to inline documentation, attributes are documented like this:
#: All the values that parameter parsing converts to True
BOOLEANS_TRUE = ['yes', 'on', '1', 'true', 'True', 1, True]
#: All the values that parameter parsing converts to False
BOOLEANS_FALSE = ['no', 'off', '0', 'false', 'False', 0, False]
This list of functions needs to be further documented
Move to _text
heading. Should we make text.converters
for what's there currently and text.formatters
for these?
Version 2 of AnsibleModule should contain functionality that sets up a Module similar to how GUI frameworks have an App
class that sets up an Application environment. Parameter parsing and registering how to exit from the Module seem like things which are AnsibleModule responsibilities.
- Entrypoint for current AnsibleModules
- Going to need a new AnsibleModule
- Going to split most methods out of it
- New focus should be
- parameter handling.
- return values?
- log_sanitization?
- Initialization is all about handling parameters
Same categories as for the functions. Many of these will need to be ported from being methods to being functions.
===> hashing
I like returning the class better. I would say that load_platform_subclass() needs to be split into a method that finds matching classes, and possibly a method that instantiates the found classes.
The facts code ended up doing something similar to avoid
the metaclass bits it was using. The facts code is mostly in https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/facts/collector.py#L166 and https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/facts/collector.py#L46 .
That approach also doesn't require all of the platform impls to be subclasses of the same type. Doesn't require any type checking at all for that matter, though it does expect a certain interface ala duck typing.
The Collector.platform_match() allows FactCollector subclasses[1] define how they 'match' a platform. Though all current cases use the base version. That also lets Collector classes decide if they are a platform match based on local criteria (for ex, match on 'Linux' if python3, but on python2 match on 'Generic' without involving setup). The collector.platformat_match() gets to decide
[1] or any class that provides the same interface