Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port v2 to use the C version of pyyaml instead of pure python #10605

Merged
merged 3 commits into from
Apr 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 18 additions & 4 deletions v2/ansible/parsing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from ansible.parsing.vault import VaultLib
from ansible.parsing.splitter import unquote
from ansible.parsing.yaml.loader import AnsibleLoader
from ansible.parsing.yaml.objects import AnsibleBaseYAMLObject
from ansible.parsing.yaml.objects import AnsibleBaseYAMLObject, AnsibleUnicode
from ansible.utils.path import unfrackpath

class DataLoader():
Expand Down Expand Up @@ -70,13 +70,27 @@ def load(self, data, file_name='<string>', show_content=True):
# we first try to load this data as JSON
return json.loads(data)
except:
# if loading JSON failed for any reason, we go ahead
# and try to parse it as YAML instead

if isinstance(data, AnsibleUnicode):
# The PyYAML's libyaml bindings use PyUnicode_CheckExact so
# they are unable to cope with our subclass.
# Unwrap and re-wrap the unicode so we can keep track of line
# numbers
new_data = unicode(data)
else:
new_data = data
try:
# if loading JSON failed for any reason, we go ahead
# and try to parse it as YAML instead
return self._safe_load(data, file_name=file_name)
new_data = self._safe_load(new_data, file_name=file_name)
except YAMLError as yaml_exc:
self._handle_error(yaml_exc, file_name, show_content)

if isinstance(data, AnsibleUnicode):
new_data = AnsibleUnicode(new_data)
new_data.ansible_pos = data.ansible_pos
return new_data

def load_from_file(self, file_name):
''' Loads data from a file, which can contain either JSON or YAML. '''

Expand Down
36 changes: 17 additions & 19 deletions v2/ansible/parsing/yaml/constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
__metaclass__ = type

from yaml.constructor import Constructor
from ansible.utils.unicode import to_unicode
from ansible.parsing.yaml.objects import AnsibleMapping, AnsibleUnicode

class AnsibleConstructor(Constructor):
Expand All @@ -33,38 +32,37 @@ def construct_yaml_map(self, node):
yield data
value = self.construct_mapping(node)
data.update(value)
data.ansible_pos = value.ansible_pos
data.ansible_pos = self._node_position_info(node)

def construct_mapping(self, node, deep=False):
ret = AnsibleMapping(super(Constructor, self).construct_mapping(node, deep))

# in some cases, we may have pre-read the data and then
# passed it to the load() call for YAML, in which case we
# want to override the default datasource (which would be
# '<string>') to the actual filename we read in
if self._ansible_file_name:
data_source = self._ansible_file_name
else:
data_source = node.__datasource__
ret.ansible_pos = (data_source, node.__line__, node.__column__)
ret.ansible_pos = self._node_position_info(node)

return ret

def construct_yaml_str(self, node):
# Override the default string handling function
# to always return unicode objects
value = self.construct_scalar(node)
value = to_unicode(value)
ret = AnsibleUnicode(self.construct_scalar(node))
ret = AnsibleUnicode(value)

if self._ansible_file_name:
data_source = self._ansible_file_name
else:
data_source = node.__datasource__
ret.ansible_pos = (data_source, node.__line__, node.__column__)
ret.ansible_pos = self._node_position_info(node)

return ret

def _node_position_info(self, node):
# the line number where the previous token has ended (plus empty lines)
column = node.start_mark.column + 1
line = node.start_mark.line + 1

# in some cases, we may have pre-read the data and then
# passed it to the load() call for YAML, in which case we
# want to override the default datasource (which would be
# '<string>') to the actual filename we read in
datasource = self._ansible_file_name or node.start_mark.name

return (datasource, line, column)

AnsibleConstructor.add_constructor(
u'tag:yaml.org,2002:map',
AnsibleConstructor.construct_yaml_map)
Expand Down
38 changes: 26 additions & 12 deletions v2/ansible/parsing/yaml/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,34 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

from yaml.reader import Reader
from yaml.scanner import Scanner
from yaml.parser import Parser
try:
from _yaml import CParser, CEmitter
HAVE_PYYAML_C = True
except ImportError:
HAVE_PYYAML_C = False

from yaml.resolver import Resolver

from ansible.parsing.yaml.composer import AnsibleComposer
from ansible.parsing.yaml.constructor import AnsibleConstructor

class AnsibleLoader(Reader, Scanner, Parser, AnsibleComposer, AnsibleConstructor, Resolver):
def __init__(self, stream, file_name=None):
Reader.__init__(self, stream)
Scanner.__init__(self)
Parser.__init__(self)
AnsibleComposer.__init__(self)
AnsibleConstructor.__init__(self, file_name=file_name)
Resolver.__init__(self)
if HAVE_PYYAML_C:
class AnsibleLoader(CParser, AnsibleConstructor, Resolver):
def __init__(self, stream, file_name=None):
CParser.__init__(self, stream)
AnsibleConstructor.__init__(self, file_name=file_name)
Resolver.__init__(self)
else:
from yaml.reader import Reader
from yaml.scanner import Scanner
from yaml.parser import Parser

from ansible.parsing.yaml.composer import AnsibleComposer

class AnsibleLoader(Reader, Scanner, Parser, AnsibleComposer, AnsibleConstructor, Resolver):
def __init__(self, stream, file_name=None):
Reader.__init__(self, stream)
Scanner.__init__(self)
Parser.__init__(self)
AnsibleComposer.__init__(self)
AnsibleConstructor.__init__(self, file_name=file_name)
Resolver.__init__(self)
13 changes: 8 additions & 5 deletions v2/bin/ansible-playbook
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#!/usr/bin/env python
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import os
import stat
Expand All @@ -19,7 +21,8 @@ from ansible.utils.vault import read_vault_file
from ansible.vars import VariableManager

# Implement an ansible.utils.warning() function later
warning = getattr(__builtins__, 'print')
def warning(*args, **kwargs):
print(*args, **kwargs)

#---------------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -134,12 +137,12 @@ if __name__ == "__main__":
#display(" ", log_only=True)
try:
sys.exit(main(sys.argv[1:]))
except AnsibleError, e:
except AnsibleError as e:
#display("ERROR: %s" % e, color='red', stderr=True)
print e
print(e)
sys.exit(1)
except KeyboardInterrupt, ke:
except KeyboardInterrupt:
#display("ERROR: interrupted", color='red', stderr=True)
print "keyboard interrupt"
print("keyboard interrupt")
sys.exit(1)