diff --git a/CHANGES.rst b/CHANGES.rst
index 0c78ae9..b39c53d 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,7 +1,8 @@
 0.7.7 (unreleased)
 ------------------
 
-- Nothing changed yet.
+- Add support for Parquet format in ``UNLOAD`` command
+  (`Issue #187 <https://github.com/sqlalchemy-redshift/sqlalchemy-redshift/issues/187>`_)
 
 
 0.7.6 (2020-01-17)
diff --git a/sqlalchemy_redshift/commands.py b/sqlalchemy_redshift/commands.py
index 583fe85..5fd65e4 100644
--- a/sqlalchemy_redshift/commands.py
+++ b/sqlalchemy_redshift/commands.py
@@ -1,8 +1,11 @@
-import collections
 import enum
 import numbers
 import re
 import warnings
+try:
+    from collections.abc import Iterable
+except ImportError:
+    from collections import Iterable
 
 import sqlalchemy as sa
 from sqlalchemy import exc as sa_exc
@@ -307,8 +310,20 @@ def visit_unload_from_select(element, compiler, **kw):
         if el.delimiter is not None or el.fixed_width is not None:
             raise ValueError(
                 'CSV format cannot be used with delimiter or fixed_width')
+    elif el.format == Format.parquet:
+        format_ = 'FORMAT AS {}'.format(el.format.value)
+        if any((
+            el.delimiter, el.fixed_width, el.add_quotes, el.escape, el.null,
+            el.header, el.gzip
+        )):
+            raise ValueError(
+                "Parquet format can't be used with `delimiter`, `fixed_width`,"
+                ' `add_quotes`, `escape`, `null`, `header`, or `gzip`.'
+            )
     else:
-        raise ValueError('Only CSV format is currently supported')
+        raise ValueError(
+            'Only CSV and Parquet formats are currently supported.'
+        )
 
     qs = template.format(
         manifest='MANIFEST' if el.manifest else '',
@@ -581,7 +596,7 @@ class CopyCommand(_ExecutableClause):
 
         table = None
         columns = []
-        if isinstance(to, collections.Iterable):
+        if isinstance(to, Iterable):
             for column in to:
                 if table is not None and table != column.table:
                     raise ValueError(

UNLOAD now supports Parquet
As of December 2019 Redshift [now supports](https://aws.amazon.com/about-aws/whats-new/2019/12/announcing-amazon-redshift-data-lake-export/) the Parquet format in the `UNLOAD` command. Currently the implementation of `UNLOAD` throws an exception if it receives anything but CSV for the export format. We need to allow Parquet now as well.
diff --git a/tests/test_unload_from_select.py b/tests/test_unload_from_select.py
index a8d4ddd..96d0724 100644
--- a/tests/test_unload_from_select.py
+++ b/tests/test_unload_from_select.py
@@ -1,3 +1,4 @@
+import pytest
 import sqlalchemy as sa
 
 from sqlalchemy_redshift import commands
@@ -157,7 +158,7 @@ def test_all_redshift_options_with_header():
     assert clean(compile_query(unload)) == clean(expected_result)
 
 
-def test_csv_format():
+def test_csv_format__basic():
     """Tests that UnloadFromSelect uses the format option correctly."""
 
     unload = dialect.UnloadFromSelect(
@@ -176,3 +177,69 @@ def test_csv_format():
         """.format(creds=creds)
 
     assert clean(compile_query(unload)) == clean(expected_result)
+
+
+@pytest.mark.parametrize('delimiter,fixed_width', (
+    ('\t', None),
+    (None, 'id:8,name:32'),
+    (';', 'id:8,name:32'),
+))
+def test_csv_format__bad_options_crash(delimiter, fixed_width):
+    """Test that UnloadFromSelect crashes if you try to use DELIMITER and/or
+    FIXEDWIDTH with the CSV format.
+    """
+    unload = dialect.UnloadFromSelect(
+        select=sa.select([sa.func.count(table.c.id)]),
+        unload_location='s3://bucket/key',
+        access_key_id=access_key_id,
+        secret_access_key=secret_access_key,
+        format=commands.Format.csv,
+        delimiter=delimiter,
+        fixed_width=fixed_width
+    )
+
+    with pytest.raises(ValueError):
+        compile_query(unload)
+
+
+def test_parquet_format__basic():
+    """Basic successful test of unloading with the Parquet format."""
+    unload = dialect.UnloadFromSelect(
+        select=sa.select([sa.func.count(table.c.id)]),
+        unload_location='s3://bucket/key',
+        access_key_id=access_key_id,
+        secret_access_key=secret_access_key,
+        format=commands.Format.parquet,
+    )
+
+    expected_result = """
+        UNLOAD ('SELECT count(t1.id) AS count_1 FROM t1')
+        TO 's3://bucket/key'
+        CREDENTIALS '{creds}'
+        FORMAT AS PARQUET
+    """.format(creds=creds)
+
+    assert clean(compile_query(unload)) == clean(expected_result)
+
+
+@pytest.mark.parametrize('kwargs', (
+    {'delimiter': '\t'},
+    {'fixed_width': 'id:8,name:32'},
+    {'gzip': True},
+    {'add_quotes': True, 'escape': True},
+    {'null': '\\N'},
+    {'header': True},
+))
+def test_parquet_format__bad_options_crash(kwargs):
+    """Verify we crash if we use the Parquet format with a bad option."""
+    unload = dialect.UnloadFromSelect(
+        select=sa.select([sa.func.count(table.c.id)]),
+        unload_location='s3://bucket/key',
+        access_key_id=access_key_id,
+        secret_access_key=secret_access_key,
+        format=commands.Format.parquet,
+        **kwargs
+    )
+
+    with pytest.raises(ValueError):
+        compile_query(unload)

pip install -e .
parse_log_pytest
requirements.txt
pytest requests alembic
apt-get update apt-get install -y gcc pip install psycopg2-binary
3.9
requirements-docs.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
alembic==1.15.2
babel==2.17.0
certifi==2025.1.31
charset-normalizer==3.4.1
docutils==0.21.2
exceptiongroup==1.2.2
greenlet==3.1.1
idna==3.10
imagesize==1.4.1
iniconfig==2.1.0
Jinja2==3.1.6
Mako==1.3.9
MarkupSafe==3.0.2
numpydoc==0.6.0
packaging==24.2
pluggy==1.5.0
psycopg2-binary==2.9.10
Pygments==2.19.1
pytest==8.3.5
requests==2.32.3
six==1.17.0
snowballstemmer==2.2.0
Sphinx==1.5.3
SQLAlchemy==1.4.54
-e git+https://github.com/sqlalchemy-redshift/sqlalchemy-redshift.git@fd6269d04fe7620db7e922d0675e6952a9879fc5#egg=sqlalchemy_redshift
tomli==2.2.1
typing_extensions==4.13.0
urllib3==2.3.0

name: sqlalchemy-redshift
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - alembic==1.15.2
      - babel==2.17.0
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - greenlet==3.1.1
      - idna==3.10
      - imagesize==1.4.1
      - iniconfig==2.1.0
      - jinja2==3.1.6
      - mako==1.3.9
      - markupsafe==3.0.2
      - numpydoc==0.6.0
      - packaging==24.2
      - pluggy==1.5.0
      - psycopg2-binary==2.9.10
      - pygments==2.19.1
      - pytest==8.3.5
      - requests==2.32.3
      - six==1.17.0
      - snowballstemmer==2.2.0
      - sphinx==1.5.3
      - sqlalchemy==1.4.54
      - tomli==2.2.1
      - typing-extensions==4.13.0
      - urllib3==2.3.0
prefix: /opt/conda/envs/sqlalchemy-redshift

tests/test_unload_from_select.py::test_parquet_format__basic
tests/test_unload_from_select.py::test_basic_unload_case tests/test_unload_from_select.py::test_iam_role tests/test_unload_from_select.py::test_all_redshift_options tests/test_unload_from_select.py::test_all_redshift_options_with_header tests/test_unload_from_select.py::test_csv_format__basic tests/test_unload_from_select.py::test_csv_format__bad_options_crash[\t-None] tests/test_unload_from_select.py::test_csv_format__bad_options_crash[None-id:8,name:32] tests/test_unload_from_select.py::test_csv_format__bad_options_crash[;-id:8,name:32] tests/test_unload_from_select.py::test_parquet_format__bad_options_crash[kwargs0] tests/test_unload_from_select.py::test_parquet_format__bad_options_crash[kwargs1] tests/test_unload_from_select.py::test_parquet_format__bad_options_crash[kwargs2] tests/test_unload_from_select.py::test_parquet_format__bad_options_crash[kwargs3] tests/test_unload_from_select.py::test_parquet_format__bad_options_crash[kwargs4] tests/test_unload_from_select.py::test_parquet_format__bad_options_crash[kwargs5]
sqlalchemy_redshift/commands.py CHANGES.rst
sqlalchemy_redshift/commands.py CHANGES.rst