# Buggy code
def downloaded(name, artifact, target_dir="/tmp", target_file=None):
    """
    Ensures that the artifact from artifactory exists at given location. If it doesn't exist, then
    it will be downloaded. It it already exists then the checksum of existing file is checked against checksum
    in artifactory. If it is different then the step will fail.

    artifact
        Details of the artifact to be downloaded from artifactory. Various options are:

        - artifactory_url: URL of the artifactory instance
        - repository: Repository in artifactory
        - artifact_id: Artifact ID
        - group_id: Group ID
        - packaging: Packaging
        - classifier: Classifier
          .. versionadded:: 2015.8.0
        - version: Version
            One of the following:
            - Version to download
            - ``latest`` - Download the latest release of this artifact
            - ``latest_snapshot`` - Download the latest snapshot for this artifact

        - username: Artifactory username
          .. versionadded:: 2015.8.0
        - password: Artifactory password
          .. versionadded:: 2015.8.0

    target_dir
        Directory where the artifact should be downloaded. By default it is downloaded to /tmp directory.

    target_file
        Target file to download artifact to. By default file name is resolved by artifactory.

    An example to download an artifact to a specific file:

    .. code-block:: yaml

        jboss_module_downloaded:
          artifactory.downloaded:
           - artifact:
               artifactory_url: http://artifactory.intranet.example.com/artifactory
               repository: 'libs-release-local'
               artifact_id: 'module'
               group_id: 'com.company.module'
               packaging: 'jar'
               classifier: 'sources'
               version: '1.0'
           - target_file: /opt/jboss7/modules/com/company/lib/module.jar

    Download artifact to the folder (automatically resolves file name):

    .. code-block:: yaml

        jboss_module_downloaded:
          artifactory.downloaded:
           - artifact:
                artifactory_url: http://artifactory.intranet.example.com/artifactory
                repository: 'libs-release-local'
                artifact_id: 'module'
                group_id: 'com.company.module'
                packaging: 'jar'
                classifier: 'sources'
                version: '1.0'
           - target_dir: /opt/jboss7/modules/com/company/lib

    """
    log.debug(
        " ======================== STATE: artifactory.downloaded (name: %s) ", name
    )
    ret = {"name": name, "result": True, "changes": {}, "comment": ""}

    try:
        fetch_result = __fetch_from_artifactory(artifact, target_dir, target_file)
        log.debug("fetch_result=%s", str(fetch_result))

        ret["result"] = fetch_result["status"]
        ret["comment"] = fetch_result["comment"]
        ret["changes"] = fetch_result["changes"]
        log.debug("ret=%s", str(ret))

        return ret
    except Exception as exc:
        ret["result"] = False
        ret["comment"] = exc
        return ret


# Traceback (TypeError)
.. versionadded:: 2015.5.0

This function will call :mod:`state.highstate
<salt.modules.state.highstate>` or :mod:`state.sls
<salt.modules.state.sls>` based on the arguments passed to this function.
It exists as a more intuitive way of applying states.

.. rubric:: APPLYING ALL STATES CONFIGURED IN TOP.SLS (A.K.A. :ref:`HIGHSTATE <running-highstate>`)

To apply all configured states, simply run ``state.apply``:

.. code-block:: bash

salt '*' state.apply

The following additional arguments are also accepted when applying all
states configured in top.sls:

test
Run states in test-only (dry-run) mode

pillar
Custom Pillar values, passed as a dictionary of key-value pairs

.. code-block:: bash

salt '*' state.apply test pillar='{"foo": "bar"}'

.. note::
Values passed this way will override Pillar values set via
``pillar_roots`` or an external Pillar source.

queue : False
Instead of failing immediately when another state run is in progress,
queue the new state run to begin running once the other has finished.

This option starts a new thread for each queued state run, so use this
option sparingly.

localconfig
Optionally, instead of using the minion config, load minion opts from
the file specified by this argument, and then merge them with the
options from the minion config. This functionality allows for specific
states to be run with their own custom minion configuration, including
different pillars, file_roots, etc.

.. code-block:: bash

salt '*' state.apply localconfig=/path/to/minion.yml


.. rubric:: APPLYING INDIVIDUAL SLS FILES (A.K.A. :py:func:`STATE.SLS <salt.modules.state.sls>`)

To apply individual SLS files, pass them as a comma-separated list:

.. code-block:: bash

# Run the states configured in salt://test.sls (or salt://test/init.sls)
salt '*' state.apply test
# Run the states configured in salt://test.sls (or salt://test/init.sls)
# and salt://pkgs.sls (or salt://pkgs/init.sls).
salt '*' state.apply test,pkgs

The following additional arguments are also accepted when applying
individual SLS files:

test
Run states in test-only (dry-run) mode

pillar
Custom Pillar values, passed as a dictionary of key-value pairs

.. code-block:: bash

salt '*' state.apply test pillar='{"foo": "bar"}'

.. note::
Values passed this way will override Pillar values set via
``pillar_roots`` or an external Pillar source.

queue : False
Instead of failing immediately when another state run is in progress,
queue the new state run to begin running once the other has finished.

This option starts a new thread for each queued state run, so use this
option sparingly.

concurrent : False
Execute state runs concurrently instead of serially

.. warning::

This flag is potentially dangerous. It is designed for use when
multiple state runs can safely be run at the same time. Do *not*
use this flag for performance optimization.

saltenv : None
Specify a salt fileserver environment to be used when applying states

.. versionchanged:: 0.17.0
Argument name changed from ``env`` to ``saltenv``

.. versionchanged:: 2014.7.0
If no saltenv is specified, the minion config will be checked for a
``saltenv`` parameter and if found, it will be used. If none is
found, ``base`` will be used. In prior releases, the minion config
was not checked and ``base`` would always be assumed when the
saltenv was not explicitly set.

pillarenv
Specify a Pillar environment to be used when applying states. By
default, all Pillar environments will be merged together and used.

localconfig
Optionally, instead of using the minion config, load minion opts from
the file specified by this argument, and then merge them with the
options from the minion config. This functionality allows for specific
states to be run with their own custom minion configuration, including
different pillars, file_roots, etc.

.. code-block:: bash

salt '*' state.apply test localconfig=/path/to/minion.yml

Traceback (most recent call last):
File "/usr/lib/python2.6/site-packages/salt/minion.py", line 1332, in _thread_return
return_data = executor.execute()
File "/usr/lib/python2.6/site-packages/salt/executors/direct_call.py", line 28, in execute
return self.func(*self.args, **self.kwargs)
File "/usr/lib/python2.6/site-packages/salt/modules/state.py", line 455, in apply_
return sls(mods, **kwargs)
File "/usr/lib/python2.6/site-packages/salt/modules/state.py", line 954, in sls
serial.dump(ret, fp_)
File "/usr/lib/python2.6/site-packages/salt/payload.py", line 226, in dump
fn_.write(self.dumps(msg))
File "/usr/lib/python2.6/site-packages/salt/payload.py", line 141, in dumps
return msgpack.dumps(msg)
File "/usr/lib64/python2.6/site-packages/msgpack/__init__.py", line 47, in packb
return Packer(**kwargs).pack(o)
File "msgpack/_packer.pyx", line 223, in msgpack._packer.Packer.pack (msgpack/_packer.cpp:223)
File "msgpack/_packer.pyx", line 225, in msgpack._packer.Packer.pack (msgpack/_packer.cpp:225)
File "msgpack/_packer.pyx", line 184, in msgpack._packer.Packer._pack (msgpack/_packer.cpp:184)
File "msgpack/_packer.pyx", line 184, in msgpack._packer.Packer._pack (msgpack/_packer.cpp:184)
File "msgpack/_packer.pyx", line 220, in msgpack._packer.Packer._pack (msgpack/_packer.cpp:220)
TypeError: can't serialize URLError(error(110, 'Connection timed out'),)

# Fixed code
def downloaded(name, artifact, target_dir="/tmp", target_file=None):
    """
    Ensures that the artifact from artifactory exists at given location. If it doesn't exist, then
    it will be downloaded. It it already exists then the checksum of existing file is checked against checksum
    in artifactory. If it is different then the step will fail.

    artifact
        Details of the artifact to be downloaded from artifactory. Various options are:

        - artifactory_url: URL of the artifactory instance
        - repository: Repository in artifactory
        - artifact_id: Artifact ID
        - group_id: Group ID
        - packaging: Packaging
        - classifier: Classifier
          .. versionadded:: 2015.8.0
        - version: Version
            One of the following:
            - Version to download
            - ``latest`` - Download the latest release of this artifact
            - ``latest_snapshot`` - Download the latest snapshot for this artifact

        - username: Artifactory username
          .. versionadded:: 2015.8.0
        - password: Artifactory password
          .. versionadded:: 2015.8.0

    target_dir
        Directory where the artifact should be downloaded. By default it is downloaded to /tmp directory.

    target_file
        Target file to download artifact to. By default file name is resolved by artifactory.

    An example to download an artifact to a specific file:

    .. code-block:: yaml

        jboss_module_downloaded:
          artifactory.downloaded:
           - artifact:
               artifactory_url: http://artifactory.intranet.example.com/artifactory
               repository: 'libs-release-local'
               artifact_id: 'module'
               group_id: 'com.company.module'
               packaging: 'jar'
               classifier: 'sources'
               version: '1.0'
           - target_file: /opt/jboss7/modules/com/company/lib/module.jar

    Download artifact to the folder (automatically resolves file name):

    .. code-block:: yaml

        jboss_module_downloaded:
          artifactory.downloaded:
           - artifact:
                artifactory_url: http://artifactory.intranet.example.com/artifactory
                repository: 'libs-release-local'
                artifact_id: 'module'
                group_id: 'com.company.module'
                packaging: 'jar'
                classifier: 'sources'
                version: '1.0'
           - target_dir: /opt/jboss7/modules/com/company/lib

    """
    log.debug(
        " ======================== STATE: artifactory.downloaded (name: %s) ", name
    )
    ret = {"name": name, "result": True, "changes": {}, "comment": ""}

    try:
        fetch_result = __fetch_from_artifactory(artifact, target_dir, target_file)
    except Exception as exc:
        ret["result"] = False
        ret["comment"] = str(exc)
        return ret

    log.debug("fetch_result=%s", str(fetch_result))

    ret["result"] = fetch_result["status"]
    ret["comment"] = fetch_result["comment"]
    ret["changes"] = fetch_result["changes"]
    log.debug("ret=%s", str(ret))

    return ret