# Buggy code
def main():
    command_allowed_param_map = dict(
        cleanup=(),
        createcachetable=(
            "cache_table",
            "database",
        ),
        flush=("database",),
        loaddata=(
            "database",
            "fixtures",
        ),
        syncdb=("database",),
        test=(
            "failfast",
            "testrunner",
            "liveserver",
            "apps",
        ),
        validate=(),
        migrate=(
            "apps",
            "skip",
            "merge",
            "database",
        ),
        collectstatic=(
            "clear",
            "link",
        ),
    )

    command_required_param_map = dict(
        loaddata=("fixtures",),
    )

    # forces --noinput on every command that needs it
    noinput_commands = (
        "flush",
        "syncdb",
        "migrate",
        "test",
        "collectstatic",
    )

    # These params are allowed for certain commands only
    specific_params = (
        "apps",
        "clear",
        "database",
        "failfast",
        "fixtures",
        "liveserver",
        "testrunner",
    )

    # These params are automatically added to the command if present
    general_params = (
        "settings",
        "pythonpath",
        "database",
    )
    specific_boolean_params = ("clear", "failfast", "skip", "merge", "link")
    end_of_command_params = ("apps", "cache_table", "fixtures")

    module = AnsibleModule(
        argument_spec=dict(
            command=dict(default=None, required=True),
            app_path=dict(default=None, required=True),
            settings=dict(default=None, required=False),
            pythonpath=dict(default=None, required=False, aliases=["python_path"]),
            virtualenv=dict(default=None, required=False, aliases=["virtual_env"]),
            apps=dict(default=None, required=False),
            cache_table=dict(default=None, required=False),
            clear=dict(default=None, required=False, type="bool"),
            database=dict(default=None, required=False),
            failfast=dict(
                default="no", required=False, type="bool", aliases=["fail_fast"]
            ),
            fixtures=dict(default=None, required=False),
            liveserver=dict(default=None, required=False, aliases=["live_server"]),
            testrunner=dict(default=None, required=False, aliases=["test_runner"]),
            skip=dict(default=None, required=False, type="bool"),
            merge=dict(default=None, required=False, type="bool"),
            link=dict(default=None, required=False, type="bool"),
        ),
    )

    command = module.params["command"]
    app_path = os.path.expanduser(module.params["app_path"])
    virtualenv = module.params["virtualenv"]

    for param in specific_params:
        value = module.params[param]
        if param in specific_boolean_params:
            value = module.boolean(value)
        if value and param not in command_allowed_param_map[command]:
            module.fail_json(
                msg="%s param is incompatible with command=%s" % (param, command)
            )

    for param in command_required_param_map.get(command, ()):
        if not module.params[param]:
            module.fail_json(
                msg="%s param is required for command=%s" % (param, command)
            )

    _ensure_virtualenv(module)

    cmd = "./manage.py %s" % (command,)

    if command in noinput_commands:
        cmd = "%s --noinput" % cmd

    for param in general_params:
        if module.params[param]:
            cmd = "%s --%s=%s" % (cmd, param, module.params[param])

    for param in specific_boolean_params:
        if module.boolean(module.params[param]):
            cmd = "%s --%s" % (cmd, param)

    # these params always get tacked on the end of the command
    for param in end_of_command_params:
        if module.params[param]:
            cmd = "%s %s" % (cmd, module.params[param])

    rc, out, err = module.run_command(cmd, cwd=os.path.expanduser(app_path))
    if rc != 0:
        if command == "createcachetable" and "table" in err and "already exists" in err:
            out = "Already exists."
        else:
            if "Unknown command:" in err:
                _fail(module, cmd, err, "Unknown django command: %s" % command)
            _fail(module, cmd, out, err, path=os.environ["PATH"], syspath=sys.path)

    changed = False

    lines = out.split("\n")
    filt = globals().get(command + "_filter_output", None)
    if filt:
        filtered_output = filter(filt, lines)
        if len(filtered_output):
            changed = filtered_output

    module.exit_json(
        changed=changed,
        out=out,
        cmd=cmd,
        app_path=app_path,
        virtualenv=virtualenv,
        settings=module.params["settings"],
        pythonpath=module.params["pythonpath"],
    )


# Traceback (nTypeError)
TASK [web : Run Django database migrations] ************************************
task path: /www/destination_lighting/statbid/statbid_reports/provision/roles/web/tasks/setup_django_app.yaml:17
Using module file /usr/local/lib/python3.5/site-packages/ansible/modules/core/web_infrastructure/django_manage.py
<52.23.172.64> ESTABLISH SSH CONNECTION FOR USER: ubuntu
<52.23.172.64> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ubuntu -o ConnectTimeout=10 -o ControlPath=/Users/s_mart/.ansible/cp/ansible-ssh-%h-%p-%r 52.23.172.64 '/bin/sh -c '"'"'( umask 77 &amp;&amp; mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1481417097.078755-197789425370261 `" &amp;&amp; echo ansible-tmp-1481417097.078755-197789425370261="` echo $HOME/.ansible/tmp/ansible-tmp-1481417097.078755-197789425370261 `" ) &amp;&amp; sleep 0'"'"''
<52.23.172.64> PUT /var/folders/56/5bxrcpk151lcfnmhmkrw8hhr0000gn/T/tmp7jarn1ax TO /home/ubuntu/.ansible/tmp/ansible-tmp-1481417097.078755-197789425370261/django_manage.py
<52.23.172.64> SSH: EXEC sftp -b - -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ubuntu -o ConnectTimeout=10 -o ControlPath=/Users/s_mart/.ansible/cp/ansible-ssh-%h-%p-%r '[52.23.172.64]'
<52.23.172.64> ESTABLISH SSH CONNECTION FOR USER: ubuntu
<52.23.172.64> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ubuntu -o ConnectTimeout=10 -o ControlPath=/Users/s_mart/.ansible/cp/ansible-ssh-%h-%p-%r 52.23.172.64 '/bin/sh -c '"'"'chmod u+x /home/ubuntu/.ansible/tmp/ansible-tmp-1481417097.078755-197789425370261/ /home/ubuntu/.ansible/tmp/ansible-tmp-1481417097.078755-197789425370261/django_manage.py &amp;&amp; sleep 0'"'"''
<52.23.172.64> ESTABLISH SSH CONNECTION FOR USER: ubuntu
<52.23.172.64> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ubuntu -o ConnectTimeout=10 -o ControlPath=/Users/s_mart/.ansible/cp/ansible-ssh-%h-%p-%r -tt 52.23.172.64 '/bin/sh -c '"'"'sudo -H -S -n -u root /bin/sh -c '"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-nrzkwtmwdsqullygmnrvdeiolkuemuln; DATABASE_NAME=statbid_report STATIC_ROOT=/webapps/statbid_report/static/ DATABASE_USER=statbid_report DATABASE_PORT=5432 DJANGO_SECRET_KEY='"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'akr2icmg1n8%z^3fe3c+)5d0(t^cy-2_25rrl35a7@!scna^1#'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"' MEDIA_ROOT=/webapps/statbid_report/media/ DJANGO_SETTINGS_MODULE=reports_app.settings DATABASE_PASSWORD=Slngv5riYqKe DATABASE_HOST=localhost /usr/bin/python3.5 /home/ubuntu/.ansible/tmp/ansible-tmp-1481417097.078755-197789425370261/django_manage.py; rm -rf "/home/ubuntu/.ansible/tmp/ansible-tmp-1481417097.078755-197789425370261/" > /dev/null 2>&amp;1'"'"'"'"'"'"'"'"' &amp;&amp; sleep 0'"'"''
fatal: [52.23.172.64]: FAILED! => {
"changed": false,
"failed": true,
"invocation": {
"module_name": "django_manage"
},
"module_stderr": "OpenSSH_7.2p2, LibreSSL 2.4.1\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug1: /etc/ssh/ssh_config line 20: Applying options for *\r\ndebug1: auto-mux: Trying existing master\r\ndebug2: fd 3 setting O_NONBLOCK\r\ndebug2: mux_client_hello_exchange: master version 4\r\ndebug3: mux_client_forwards: request forwardings: 0 local, 0 remote\r\ndebug3: mux_client_request_session: entering\r\ndebug3: mux_client_request_alive: entering\r\ndebug3: mux_client_request_alive: done pid = 13037\r\ndebug3: mux_client_request_session: session request sent\r\ndebug1: mux_client_request_session: master session id: 2\r\ndebug3: mux_client_read_packet: read header failed: Broken pipe\r\ndebug2: Received exit status from master 0\r\nShared connection to 52.23.172.64 closed.\r\n",
"module_stdout": "Traceback (most recent call last):\r\n  File \"/tmp/ansible_0a7fqdpo/ansible_module_django_manage.py\", line 287, in <module>\r\n    main()\r\n  File \"/tmp/ansible_0a7fqdpo/ansible_module_django_manage.py\", line 278, in main\r\n    if len(filtered_output):\r\nTypeError: object of type 'filter' has no len()\r\n",
"msg": "MODULE FAILURE"
}

# Fixed code
def main():
    command_allowed_param_map = dict(
        cleanup=(),
        createcachetable=(
            "cache_table",
            "database",
        ),
        flush=("database",),
        loaddata=(
            "database",
            "fixtures",
        ),
        syncdb=("database",),
        test=(
            "failfast",
            "testrunner",
            "liveserver",
            "apps",
        ),
        validate=(),
        migrate=(
            "apps",
            "skip",
            "merge",
            "database",
        ),
        collectstatic=(
            "clear",
            "link",
        ),
    )

    command_required_param_map = dict(
        loaddata=("fixtures",),
    )

    # forces --noinput on every command that needs it
    noinput_commands = (
        "flush",
        "syncdb",
        "migrate",
        "test",
        "collectstatic",
    )

    # These params are allowed for certain commands only
    specific_params = (
        "apps",
        "clear",
        "database",
        "failfast",
        "fixtures",
        "liveserver",
        "testrunner",
    )

    # These params are automatically added to the command if present
    general_params = (
        "settings",
        "pythonpath",
        "database",
    )
    specific_boolean_params = ("clear", "failfast", "skip", "merge", "link")
    end_of_command_params = ("apps", "cache_table", "fixtures")

    module = AnsibleModule(
        argument_spec=dict(
            command=dict(default=None, required=True),
            app_path=dict(default=None, required=True),
            settings=dict(default=None, required=False),
            pythonpath=dict(default=None, required=False, aliases=["python_path"]),
            virtualenv=dict(default=None, required=False, aliases=["virtual_env"]),
            apps=dict(default=None, required=False),
            cache_table=dict(default=None, required=False),
            clear=dict(default=None, required=False, type="bool"),
            database=dict(default=None, required=False),
            failfast=dict(
                default="no", required=False, type="bool", aliases=["fail_fast"]
            ),
            fixtures=dict(default=None, required=False),
            liveserver=dict(default=None, required=False, aliases=["live_server"]),
            testrunner=dict(default=None, required=False, aliases=["test_runner"]),
            skip=dict(default=None, required=False, type="bool"),
            merge=dict(default=None, required=False, type="bool"),
            link=dict(default=None, required=False, type="bool"),
        ),
    )

    command = module.params["command"]
    app_path = os.path.expanduser(module.params["app_path"])
    virtualenv = module.params["virtualenv"]

    for param in specific_params:
        value = module.params[param]
        if param in specific_boolean_params:
            value = module.boolean(value)
        if value and param not in command_allowed_param_map[command]:
            module.fail_json(
                msg="%s param is incompatible with command=%s" % (param, command)
            )

    for param in command_required_param_map.get(command, ()):
        if not module.params[param]:
            module.fail_json(
                msg="%s param is required for command=%s" % (param, command)
            )

    _ensure_virtualenv(module)

    cmd = "./manage.py %s" % (command,)

    if command in noinput_commands:
        cmd = "%s --noinput" % cmd

    for param in general_params:
        if module.params[param]:
            cmd = "%s --%s=%s" % (cmd, param, module.params[param])

    for param in specific_boolean_params:
        if module.boolean(module.params[param]):
            cmd = "%s --%s" % (cmd, param)

    # these params always get tacked on the end of the command
    for param in end_of_command_params:
        if module.params[param]:
            cmd = "%s %s" % (cmd, module.params[param])

    rc, out, err = module.run_command(cmd, cwd=os.path.expanduser(app_path))
    if rc != 0:
        if command == "createcachetable" and "table" in err and "already exists" in err:
            out = "Already exists."
        else:
            if "Unknown command:" in err:
                _fail(module, cmd, err, "Unknown django command: %s" % command)
            _fail(module, cmd, out, err, path=os.environ["PATH"], syspath=sys.path)

    changed = False

    lines = out.split("\n")
    filt = globals().get(command + "_filter_output", None)
    if filt:
        filtered_output = list(filter(filt, lines))
        if len(filtered_output):
            changed = filtered_output

    module.exit_json(
        changed=changed,
        out=out,
        cmd=cmd,
        app_path=app_path,
        virtualenv=virtualenv,
        settings=module.params["settings"],
        pythonpath=module.params["pythonpath"],
    )