Search code examples
pythonyamlhasattr

using yaml.safe_load and hasattr


I have the following code that reads from a yaml file and needs to know if the property "ethernets" exists in it. I use "ethernets1" below to see how the code behaves when the property does not exist.

#!/usr/bin/python

import yaml
import simplejson as json

NETPLAN = "/etc/netplan/01-network-manager-all.yaml"

# get netplan file
with open(NETPLAN, "r") as stream:
    try:
        netplan_config = yaml.safe_load(stream)
        print("netplan_config = " + json.dumps(netplan_config))
        stream.close()
    except yaml.YAMLError as e:
        print(f"error = {str(e)}")

# test 1
if hasattr(netplan_config["network"], "ethernets"):
    print("mark1")
else:
    print("mark2")

# test 2
if netplan_config["network"]["ethernets"]:
    print("mark3")
else:
    print("mark4")

# test 3
if netplan_config["network"]["ethernets1"]:
    print("mark5")
else:
    print("mark6")

# test 4
try:
    if netplan_config["network"]["ethernets1"]:
        print("mark7")
except KeyError:
    print("mark8")

The output is:

mark2
mark3
error thrown: KeyError: 'ethernets1'

The problem is that "mark1" is not printed. I cannot use the test 2 method because it throws an error if it does not exist. I do not understand why hasattr does not work on netplan_config.

YAML file for reference:

network:
  ethernets:
    eth0:
      addresses:
      - 192.168.4.31/22
      dhcp4: false
      dhcp6: false
      match:
        macaddress: 24:4b:fe:e2:1c:4a
      nameservers:
        addresses:
        - 8.8.8.8
        - 8.8.4.4
      routes:
      - to: default
        via: 192.168.4.1
      set-name: eth0
  renderer: NetworkManager
  version: 2

Edit: I guess I could use test4 (it works), but I would rather use hasattr as it is cleaner.


Solution

  • YAML mappings are loaded as Python dicts (unless you tag the mapping and provide an appropriate loader for the tag), so testing on an attribute is not going to work.

    What you need to do is test if a key in the dict:

    if "ethernets" in netplan_config["network"]:
        print('mark1')
    

    or use just catch the KeyError:

    try:
        eths = netplan_config["network"]["ethernets"]
        print('mark1')
    except KeyError:
        print('mark2')
    

    which I would use if you are going to use eths part