ovanes
ovanes

Reputation: 5673

PyYAML replace dash in keys with underscore

I would like to map directly some configuration parameters from YAML into Python argument names. Just wondering if there is a way without writing extra-code (to modify keys afterwards) to let YAML parser replace dash '-' in a key with an underscore '_'.

some-parameter: xyz
some-other-parameter: 123

Should become when parsed with PyYAML (or may be other lib) a dictionary with values:

{'some_parameter': 'xyz', 'some_other_parameter': 123}

Than I can pass the dictionary to a function as named parameters:

foo(**parsed_data)

I know I can iterate through the keys afterwards and modify their values, but I don't want to do that :)

Upvotes: 3

Views: 4615

Answers (3)

Farhan Haider
Farhan Haider

Reputation: 1724

Well, If you parse the YAML file as a python dictionary, you can use the following code to convert all dash (inside all nested dictionaries and arrays) with dash.

def hyphen_to_underscore(dictionary):
"""
Takes an Array or dictionary and replace all the hyphen('-') in any of its keys with a underscore('_')
:param dictionary:
:return: the same object with all hyphens replaced by underscore
"""
# By default return the same object
final_dict = dictionary

# for Array perform this method on every object
if type(dictionary) is type([]):
    final_dict = []
    for item in dictionary:
        final_dict.append(hyphen_to_underscore(item))

# for dictionary traverse all the keys and replace hyphen with underscore
elif type(dictionary) is type({}):
    final_dict = {}
    for k, v in dictionary.items():
        # If there is a sub dictionary or an array perform this method of it recursively
        if type(dictionary[k]) is type({}) or type(dictionary[k]) is type([]):
            value = hyphen_to_underscore(v)
            final_dict[k.replace('-', '_')] = value
        else:
            final_dict[k.replace('-', '_')] = v

return final_dict

Here is a sample usage

customer_information = {
"first-name":"Farhan",
"last-name":"Haider",
"address":[{
    "address-line-1": "Blue Mall",
    "address-line-2": None,
    "address-type": "Work"
},{
    "address-line-1": "DHA",
    "address-line-2": "24-H",
    "address-type": "Home"
}],
"driver_license":{
    "number": "209384092834",
    "state-region": "AB"
}
}

print(hyphen_to_underscore(customer_information))
# {'first_name': 'Farhan', 'last_name': 'Haider', 'address': [{'address_line_1': 'Blue Mall', 'address_line_2': None, 'address_type': 'Work'}, {'address_line_1': 'DHA', 'address_line_2': '24-H', 'address_type': 'Home'}], 'driver_license': {'number': '209384092834', 'state_region': 'AB'}}

Upvotes: 0

ovanes
ovanes

Reputation: 5673

I think I found a solution: There is a package which is called yconf: https://pypi.python.org/pypi/yconf

I can map there values and work with it using the well-known argparse-interface:

config.yml

logging:
  log-level: debug

Argparse like definition:

parser.add_argument("--log-level", dest="logging.log-level")

Upvotes: 0

larsks
larsks

Reputation: 312098

At least for your stated case, you don't need to transform the keys. Given:

import pprint

def foo(**kwargs):
    print 'KWARGS:', pprint.pformat(kwargs)

If you set:

values = {
    'some-parameter': 'xyz',
    'some-other-parameter': 123,
}

And then call:

foo(**values)

You get:

KWARGS: {'some-other-parameter': 123, 'some-parameter': 'xyz'}

If you goal is is actually to call a function like this:

def foo(some_parameter=None, some_other_parameter=None):
    pass

Then sure, you would need to map the key names. But you could just do this:

foo(**dict((k.replace('-','_'),v) for k,v in values.items()))

Upvotes: 4

Related Questions