# Buggy code
def create_apache_identifier(name):
    """
    By convention if a module is loaded via name, it appears in apache2ctl -M as
    name_module.

    Some modules don't follow this convention and we use replacements for those."""

    # a2enmod name replacement to apache2ctl -M names
    text_workarounds = [
        ("shib2", "mod_shib"),
        ("evasive", "evasive20_module"),
    ]

    # re expressions to extract subparts of names
    re_workarounds = [
        ("php", r"^(php\d)\."),
    ]

    for a2enmod_spelling, module_name in text_workarounds:
        if a2enmod_spelling in name:
            return module_name

    for search, reexpr in re_workarounds:
        if search in name:
            rematch = re.search(reexpr, name)
            return rematch.group(1) + "_module"

    return name + "_module"


# Traceback (nAttributeError)
Using module file /usr/local/lib/python2.7/dist-packages/ansible/modules/web_infrastructure/apache2_module.py
<1.2.3.4> ESTABLISH SSH CONNECTION FOR USER: ansible
<1.2.3.4> SSH: EXEC ssh -o ControlMaster=auto -o ControlPersist=60s -o Port=22 -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ansible -o ConnectTimeout=60 -o 'ControlPath=~/.ssh/ansible-ssh-%h-%p-%r' 1.2.3.4 '/bin/sh -c '"'"'( umask 77 &amp;&amp; mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1506328589.49-122064381956952 `" &amp;&amp; echo ansible-tmp-1506328589.49-122064381956952="` echo $HOME/.ansible/tmp/ansible-tmp-1506328589.49-122064381956952 `" ) &amp;&amp; sleep 0'"'"''
<1.2.3.4> (0, 'ansible-tmp-1506328589.49-122064381956952=/home/ansible/.ansible/tmp/ansible-tmp-1506328589.49-122064381956952\n', '')
<1.2.3.4> PUT /tmp/tmpP42OZP TO /home/ansible/.ansible/tmp/ansible-tmp-1506328589.49-122064381956952/apache2_module.py
<1.2.3.4> SSH: EXEC sftp -b - -o ControlMaster=auto -o ControlPersist=60s -o Port=22 -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ansible -o ConnectTimeout=60 -o 'ControlPath=~/.ssh/ansible-ssh-%h-%p-%r' '[1.2.3.4]'
<1.2.3.4> (0, 'sftp> put /tmp/tmpP42OZP /home/ansible/.ansible/tmp/ansible-tmp-1506328589.49-122064381956952/apache2_module.py\n', '')
<1.2.3.4> ESTABLISH SSH CONNECTION FOR USER: ansible
<1.2.3.4> SSH: EXEC ssh -o ControlMaster=auto -o ControlPersist=60s -o Port=22 -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ansible -o ConnectTimeout=60 -o 'ControlPath=~/.ssh/ansible-ssh-%h-%p-%r' 1.2.3.4 '/bin/sh -c '"'"'chmod u+x /home/ansible/.ansible/tmp/ansible-tmp-1506328589.49-122064381956952/ /home/ansible/.ansible/tmp/ansible-tmp-1506328589.49-122064381956952/apache2_module.py &amp;&amp; sleep 0'"'"''
<1.2.3.4> (0, '', '')
<1.2.3.4> ESTABLISH SSH CONNECTION FOR USER: ansible
<1.2.3.4> SSH: EXEC ssh -o ControlMaster=auto -o ControlPersist=60s -o Port=22 -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ansible -o ConnectTimeout=60 -o 'ControlPath=~/.ssh/ansible-ssh-%h-%p-%r' -tt 1.2.3.4 '/bin/sh -c '"'"'sudo -H -S  -p "[sudo via ansible, key=gbfxlqwavpoyetsyizstcudrknzonvlx] password: " -u root /bin/sh -c '"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-gbfxlqwavpoyetsyizstcudrknzonvlx; /usr/bin/python /home/ansible/.ansible/tmp/ansible-tmp-1506328589.49-122064381956952/apache2_module.py; rm -rf "/home/ansible/.ansible/tmp/ansible-tmp-1506328589.49-122064381956952/" > /dev/null 2>&amp;1'"'"'"'"'"'"'"'"' &amp;&amp; sleep 0'"'"''
<1.2.3.4> (0, '\r\nTraceback (most recent call last):\r\n  File "/tmp/ansible_m43APd/ansible_module_apache2_module.py", line 238, in <module>\r\n    main()\r\n  File "/tmp/ansible_m43APd/ansible_module_apache2_module.py", line 233, in main\r\n    _set_state(module, module.params[\'state\'])\r\n  File "/tmp/ansible_m43APd/ansible_module_apache2_module.py", line 184, in _set_state\r\n    if _module_is_enabled(module) != want_enabled:\r\n  File "/tmp/ansible_m43APd/ansible_module_apache2_module.py", line 141, in _module_is_enabled\r\n    searchstring = \' \' + create_apache_identifier(name)\r\n  File "/tmp/ansible_m43APd/ansible_module_apache2_module.py", line 170, in create_apache_identifier\r\n    return rematch.group(1) + \'_module\'\r\nAttributeError: \'NoneType\' object has no attribute \'group\'\r\n', 'Shared connection to 1.2.3.4 closed.\r\n')
failed: [test-host] (item=php5) => {
"changed": false,
"failed": true,
"item": "php5",
"module_stderr": "Shared connection to 1.2.3.4 closed.\r\n",
"module_stdout": "\r\nTraceback (most recent call last):\r\n  File \"/tmp/ansible_m43APd/ansible_module_apache2_module.py\", line 238, in <module>\r\n    main()\r\n  File \"/tmp/ansible_m43APd/ansible_module_apache2_module.py\", line 233, in main\r\n    _set_state(module, module.params['state'])\r\n  File \"/tmp/ansible_m43APd/ansible_module_apache2_module.py\", line 184, in _set_state\r\n    if _module_is_enabled(module) != want_enabled:\r\n  File \"/tmp/ansible_m43APd/ansible_module_apache2_module.py\", line 141, in _module_is_enabled\r\n    searchstring = ' ' + create_apache_identifier(name)\r\n  File \"/tmp/ansible_m43APd/ansible_module_apache2_module.py\", line 170, in create_apache_identifier\r\n    return rematch.group(1) + '_module'\r\nAttributeError: 'NoneType' object has no attribute 'group'\r\n",
"msg": "MODULE FAILURE",
"rc": 0
}

# Fixed code
def create_apache_identifier(name):
    """
    By convention if a module is loaded via name, it appears in apache2ctl -M as
    name_module.

    Some modules don't follow this convention and we use replacements for those."""

    # a2enmod name replacement to apache2ctl -M names
    text_workarounds = [
        ("shib2", "mod_shib"),
        ("evasive", "evasive20_module"),
    ]

    # re expressions to extract subparts of names
    re_workarounds = [
        ("php", r"^(php\d)\."),
    ]

    for a2enmod_spelling, module_name in text_workarounds:
        if a2enmod_spelling in name:
            return module_name

    for search, reexpr in re_workarounds:
        if search in name:
            try:
                rematch = re.search(reexpr, name)
                return rematch.group(1) + "_module"
            except AttributeError:
                pass

    return name + "_module"