# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['pyathena',
 'pyathena.arrow',
 'pyathena.fastparquet',
 'pyathena.filesystem',
 'pyathena.pandas']

package_data = \
{'': ['*']}

install_requires = \
['boto3>=1.26.4', 'botocore>=1.29.4', 'fsspec', 'tenacity>=4.1.0']

extras_require = \
{'arrow': ['pyarrow>=7.0.0'],
 'fastparquet': ['fastparquet>=0.4.0'],
 'pandas': ['pandas>=1.3.0'],
 'sqlalchemy': ['sqlalchemy>=1.0.0,<2.0.0']}

entry_points = \
{'sqlalchemy.dialects': ['awsathena = pyathena.sqlalchemy_athena:AthenaDialect',
                         'awsathena.arrow = '
                         'pyathena.sqlalchemy_athena:AthenaArrowDialect',
                         'awsathena.pandas = '
                         'pyathena.sqlalchemy_athena:AthenaPandasDialect',
                         'awsathena.rest = '
                         'pyathena.sqlalchemy_athena:AthenaRestDialect']}

setup_kwargs = {
    'name': 'pyathena',
    'version': '2.21.3',
    'description': 'Python DB API 2.0 (PEP 249) client for Amazon Athena',
    'long_description': '.. image:: https://badge.fury.io/py/pyathena.svg\n    :target: https://badge.fury.io/py/pyathena\n\n.. image:: https://img.shields.io/pypi/pyversions/PyAthena.svg\n    :target: https://pypi.org/project/PyAthena/\n\n.. image:: https://github.com/laughingman7743/PyAthena/actions/workflows/test.yaml/badge.svg\n    :target: https://github.com/laughingman7743/PyAthena/actions/workflows/test.yaml\n\n.. image:: https://img.shields.io/pypi/l/PyAthena.svg\n    :target: https://github.com/laughingman7743/PyAthena/blob/master/LICENSE\n\n.. image:: https://pepy.tech/badge/pyathena/month\n    :target: https://pepy.tech/project/pyathena\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n    :target: https://github.com/psf/black\n\n.. image:: https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336\n    :target: https://pycqa.github.io/isort/\n\nPyAthena\n========\n\nPyAthena is a Python `DB API 2.0 (PEP 249)`_ client for `Amazon Athena`_.\n\n.. _`DB API 2.0 (PEP 249)`: https://www.python.org/dev/peps/pep-0249/\n.. _`Amazon Athena`: https://docs.aws.amazon.com/athena/latest/APIReference/Welcome.html\n\n.. contents:: Table of Contents:\n   :local:\n   :depth: 2\n\nRequirements\n------------\n\n* Python\n\n  - CPython 3.7 3.8 3.9 3.10, 3.11\n\nInstallation\n------------\n\n.. code:: bash\n\n    $ pip install PyAthena\n\nExtra packages:\n\n+---------------+---------------------------------------+------------------+\n| Package       | Install command                       | Version          |\n+===============+=======================================+==================+\n| SQLAlchemy    | ``pip install PyAthena[SQLAlchemy]``  | >=1.0.0, <2.0.0  |\n+---------------+---------------------------------------+------------------+\n| Pandas        | ``pip install PyAthena[Pandas]``      | >=1.3.0          |\n+---------------+---------------------------------------+------------------+\n| Arrow         | ``pip install PyAthena[Arrow]``       | >=7.0.0          |\n+---------------+---------------------------------------+------------------+\n| fastparquet   | ``pip install PyAthena[fastparquet]`` | >=0.4.0          |\n+---------------+---------------------------------------+------------------+\n\nUsage\n-----\n\nBasic usage\n~~~~~~~~~~~\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n    cursor.execute("SELECT * FROM one_row")\n    print(cursor.description)\n    print(cursor.fetchall())\n\nCursor iteration\n~~~~~~~~~~~~~~~~\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n    cursor.execute("SELECT * FROM many_rows LIMIT 10")\n    for row in cursor:\n        print(row)\n\nQuery with parameter\n~~~~~~~~~~~~~~~~~~~~\n\nSupported `DB API paramstyle`_ is only ``PyFormat``.\n``PyFormat`` only supports `named placeholders`_ with old ``%`` operator style and parameters specify dictionary format.\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n    cursor.execute("""\n                   SELECT col_string FROM one_row_complex\n                   WHERE col_string = %(param)s\n                   """, {"param": "a string"})\n    print(cursor.fetchall())\n\nif ``%`` character is contained in your query, it must be escaped with ``%%`` like the following:\n\n.. code:: sql\n\n    SELECT col_string FROM one_row_complex\n    WHERE col_string = %(param)s OR col_string LIKE \'a%%\'\n\n.. _`DB API paramstyle`: https://www.python.org/dev/peps/pep-0249/#paramstyle\n.. _`named placeholders`: https://pyformat.info/#named_placeholders\n\nSQLAlchemy\n~~~~~~~~~~\n\nInstall SQLAlchemy with ``pip install "SQLAlchemy>=1.0.0, <2.0.0"`` or ``pip install PyAthena[SQLAlchemy]``.\nSupported SQLAlchemy is 1.0.0 or higher and less than 2.0.0.\n\n.. code:: python\n\n    from urllib.parse import quote_plus\n    from sqlalchemy.engine import create_engine\n    from sqlalchemy.sql.expression import select\n    from sqlalchemy.sql.functions import func\n    from sqlalchemy.sql.schema import Table, MetaData\n\n    conn_str = "awsathena+rest://{aws_access_key_id}:{aws_secret_access_key}@athena.{region_name}.amazonaws.com:443/"\\\n               "{schema_name}?s3_staging_dir={s3_staging_dir}"\n    engine = create_engine(conn_str.format(\n        aws_access_key_id=quote_plus("YOUR_ACCESS_KEY_ID"),\n        aws_secret_access_key=quote_plus("YOUR_SECRET_ACCESS_KEY"),\n        region_name="us-west-2",\n        schema_name="default",\n        s3_staging_dir=quote_plus("s3://YOUR_S3_BUCKET/path/to/")))\n    with engine.connect() as connection:\n        many_rows = Table("many_rows", MetaData(), autoload_with=connection)\n        result = connection.execute(select([func.count("*")], from_obj=many_rows))\n        print(result.scalar())\n\nThe connection string has the following format:\n\n.. code:: text\n\n    awsathena+rest://{aws_access_key_id}:{aws_secret_access_key}@athena.{region_name}.amazonaws.com:443/{schema_name}?s3_staging_dir={s3_staging_dir}&...\n\nIf you do not specify ``aws_access_key_id`` and ``aws_secret_access_key`` using instance profile or boto3 configuration file:\n\n.. code:: text\n\n    awsathena+rest://:@athena.{region_name}.amazonaws.com:443/{schema_name}?s3_staging_dir={s3_staging_dir}&...\n\nNOTE: ``s3_staging_dir`` requires quote. If ``aws_access_key_id``, ``aws_secret_access_key`` and other parameter contain special characters, quote is also required.\n\nDialect & driver\n^^^^^^^^^^^^^^^^\n\n+-----------+--------+------------------+-----------------+\n| Dialect   | Driver | Schema           | Cursor          |\n+===========+========+==================+=================+\n| awsathena |        | awsathena        | DefaultCursor   |\n+-----------+--------+------------------+-----------------+\n| awsathena | rest   | awsathena+rest   | DefaultCursor   |\n+-----------+--------+------------------+-----------------+\n| awsathena | pandas | awsathena+pandas | `PandasCursor`_ |\n+-----------+--------+------------------+-----------------+\n| awsathena | arrow  | awsathena+arrow  | `ArrowCursor`_  |\n+-----------+--------+------------------+-----------------+\n| awsathena | jdbc   | awsathena+jdbc   | `PyAthenaJDBC`_ |\n+-----------+--------+------------------+-----------------+\n\n.. _`PyAthenaJDBC`: https://github.com/laughingman7743/PyAthenaJDBC\n\n\nDialect options\n^^^^^^^^^^^^^^^\n\nTable options\n#############\n\nlocation\n    Type:\n        str\n    Description:\n        Specifies the location of the underlying data in the Amazon S3 from which the table is created.\n    value:\n        s3://bucket/path/to/\n    Example:\n        .. code:: python\n\n            Table("some_table", metadata, ..., awsathena_location="s3://bucket/path/to/")\ncompression\n    Type:\n        str\n    Description:\n        Specifies the compression format.\n    Value:\n        * BZIP2\n        * DEFLATE\n        * GZIP\n        * LZ4\n        * LZO\n        * SNAPPY\n        * ZLIB\n        * ZSTD\n        * NONE|UNCOMPRESSED\n    Example:\n        .. code:: python\n\n            Table("some_table", metadata, ..., awsathena_compression="SNAPPY")\nrow_format\n    Type:\n        str\n    Description:\n        Specifies the row format of the table and its underlying source data if applicable.\n    Value:\n        * [DELIMITED FIELDS TERMINATED BY char [ESCAPED BY char]]\n        * [DELIMITED COLLECTION ITEMS TERMINATED BY char]\n        * [MAP KEYS TERMINATED BY char]\n        * [LINES TERMINATED BY char]\n        * [NULL DEFINED AS char]\n        * SERDE \'serde_name\'\n    Example:\n        .. code:: python\n\n            Table("some_table", metadata, ..., awsathena_row_format="SERDE \'org.openx.data.jsonserde.JsonSerDe\'")\nfile_format\n    Type:\n        str\n    Description:\n        Specifies the file format for table data.\n    Value:\n        * SEQUENCEFILE\n        * TEXTFILE\n        * RCFILE\n        * ORC\n        * PARQUET\n        * AVRO\n        * ION\n        * INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname\n    Example:\n        .. code:: python\n\n            Table("some_table", metadata, ..., awsathena_file_format="PARQUET")\n            Table("some_table", metadata, ..., awsathena_file_format="INPUTFORMAT \'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat\' OUTPUTFORMAT \'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat\'")\nserdeproperties\n    Type:\n        dict[str, str]\n    Description:\n        Specifies one or more custom properties allowed in SerDe.\n    Value:\n        .. code:: python\n\n            { "property_name": "property_value", "property_name": "property_value", ... }\n    Example:\n        .. code:: python\n\n            Table("some_table", metadata, ..., awsathena_serdeproperties={\n                "separatorChar": ",", "escapeChar": "\\\\\\\\"\n            })\ntblproperties\n    Type:\n        dict[str, str]\n    Description:\n        Specifies custom metadata key-value pairs for the table definition in addition to predefined table properties.\n    Value:\n        .. code:: python\n\n            { "property_name": "property_value", "property_name": "property_value", ... }\n    Example:\n        .. code:: python\n\n            Table("some_table", metadata, ..., awsathena_tblproperties={\n                "projection.enabled": "true",\n                "projection.dt.type": "date",\n                "projection.dt.range": "NOW-1YEARS,NOW",\n                "projection.dt.format": "yyyy-MM-dd",\n            })\nbucket_count\n    Type:\n        int\n    Description:\n        The number of buckets for bucketing your data.\n    Value:\n        Integer value greater than or equal to 0\n    Example:\n        .. code:: python\n\n            Table("some_table", metadata, ..., awsathena_bucket_count=5)\n\nAll table options can also be configured with the connection string as follows:\n\n.. code:: text\n\n    awsathena+rest://:@athena.us-west-2.amazonaws.com:443/default?s3_staging_dir=s3%3A%2F%2Fbucket%2Fpath%2Fto%2F&location=s3%3A%2F%2Fbucket%2Fpath%2Fto%2F&file_format=parquet&compression=snappy&...\n\n``serdeproperties`` and ``tblproperties`` must be converted to strings in the ``\'key\'=\'value\',\'key\'=\'value\'`` format and url encoded.\nIf single quotes are included, escape them with a backslash.\n\nFor example, if you configure a projection setting ``\'projection.enabled\'=\'true\',\'projection.dt.type\'=\'date\',\'projection.dt.range\'=\'NOW-1YEARS,NOW\',\'projection.dt.format\'= \'yyyy-MM-dd\'`` in tblproperties, it would look like this\n\n.. code:: text\n\n    awsathena+rest://:@athena.us-west-2.amazonaws.com:443/default?s3_staging_dir=s3%3A%2F%2Fbucket%2Fpath%2Fto%2F&tblproperties=%27projection.enabled%27%3D%27true%27%2C%27projection.dt.type%27%3D%27date%27%2C%27projection.dt.range%27%3D%27NOW-1YEARS%2CNOW%27%2C%27projection.dt.format%27%3D+%27yyyy-MM-dd%27\n\nColumn options\n##############\n\npartition\n    Type:\n        bool\n    Description:\n        Specifies a key for partitioning data.\n    Value:\n        True / False\n    Example:\n        .. code:: python\n\n            Column("some_column", types.String, ..., awsathena_partition=True)\ncluster\n    Type:\n        bool\n    Description:\n        Divides the data in the specified column into data subsets called buckets, with or without partitioning.\n    Value:\n        True / False\n    Example:\n        .. code:: python\n\n            Column("some_column", types.String, ..., awsathena_cluster=True)\n\nTo configure column options from the connection string, specify the column name as a comma-separated string.\n\n.. code:: text\n\n    awsathena+rest://:@athena.us-west-2.amazonaws.com:443/default?partition=column1%2Ccolumn2&cluster=column1%2Ccolumn2&...\n\nIf you want to limit the column options to specific table names only, specify the table and column names connected by dots as a comma-separated string.\n\n.. code:: text\n\n    awsathena+rest://:@athena.us-west-2.amazonaws.com:443/default?partition=table1.column1%2Ctable1.column2&cluster=table2.column1%2Ctable2.column2&...\n\nPandas\n~~~~~~\n\nAs DataFrame\n^^^^^^^^^^^^\n\nYou can use the `pandas.read_sql_query`_ to handle the query results as a `pandas.DataFrame object`_.\n\n.. code:: python\n\n    from pyathena import connect\n    import pandas as pd\n\n    conn = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                   region_name="us-west-2")\n    df = pd.read_sql_query("SELECT * FROM many_rows", conn)\n    print(df.head())\n\nNOTE: `Poor performance when using pandas.read_sql #222 <https://github.com/laughingman7743/PyAthena/issues/222>`_\n\nThe ``pyathena.pandas.util`` package also has helper methods.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.util import as_pandas\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n    cursor.execute("SELECT * FROM many_rows")\n    df = as_pandas(cursor)\n    print(df.describe())\n\nIf you want to use the query results output to S3 directly, you can use `PandasCursor`_.\nThis cursor fetches query results faster than the default cursor. (See `benchmark results`_.)\n\n.. _`pandas.read_sql_query`: https://pandas.pydata.org/docs/reference/api/pandas.read_sql_query.html\n.. _`benchmark results`: benchmarks/\n\nTo SQL\n^^^^^^\n\nYou can use `pandas.DataFrame.to_sql`_ to write records stored in DataFrame to Amazon Athena.\n`pandas.DataFrame.to_sql`_ uses `SQLAlchemy`_, so you need to install it.\n\n.. code:: python\n\n    import pandas as pd\n    from urllib.parse import quote_plus\n    from sqlalchemy import create_engine\n\n    conn_str = "awsathena+rest://:@athena.{region_name}.amazonaws.com:443/"\\\n               "{schema_name}?s3_staging_dir={s3_staging_dir}&location={location}&compression=snappy"\n    engine = create_engine(conn_str.format(\n        region_name="us-west-2",\n        schema_name="YOUR_SCHEMA",\n        s3_staging_dir=quote_plus("s3://YOUR_S3_BUCKET/path/to/"),\n        location=quote_plus("s3://YOUR_S3_BUCKET/path/to/")))\n\n    df = pd.DataFrame({"a": [1, 2, 3, 4, 5]})\n    df.to_sql("YOUR_TABLE", engine, schema="YOUR_SCHEMA", index=False, if_exists="replace", method="multi")\n\nThe location of the Amazon S3 table is specified by the ``location`` parameter in the connection string.\nIf ``location`` is not specified, ``s3_staging_dir`` parameter will be used. The following rules apply.\n\n.. code:: text\n\n    s3://{location or s3_staging_dir}/{schema}/{table}/\n\nThe file format, row format, and compression settings are specified in the connection string, see `Table options`_.\n\nThe ``pyathena.pandas.util`` package also has helper methods.\n\n.. code:: python\n\n    import pandas as pd\n    from pyathena import connect\n    from pyathena.pandas.util import to_sql\n\n    conn = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                   region_name="us-west-2")\n    df = pd.DataFrame({"a": [1, 2, 3, 4, 5]})\n    to_sql(df, "YOUR_TABLE", conn, "s3://YOUR_S3_BUCKET/path/to/",\n           schema="YOUR_SCHEMA", index=False, if_exists="replace")\n\nThis helper method supports partitioning.\n\n.. code:: python\n\n    import pandas as pd\n    from datetime import date\n    from pyathena import connect\n    from pyathena.pandas.util import to_sql\n\n    conn = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                   region_name="us-west-2")\n    df = pd.DataFrame({\n        "a": [1, 2, 3, 4, 5],\n        "dt": [\n            date(2020, 1, 1), date(2020, 1, 1), date(2020, 1, 1),\n            date(2020, 1, 2),\n            date(2020, 1, 3)\n        ],\n    })\n    to_sql(df, "YOUR_TABLE", conn, "s3://YOUR_S3_BUCKET/path/to/",\n           schema="YOUR_SCHEMA", partitions=["dt"])\n\n    cursor = conn.cursor()\n    cursor.execute("SHOW PARTITIONS YOUR_TABLE")\n    print(cursor.fetchall())\n\nConversion to Parquet and upload to S3 use `ThreadPoolExecutor`_ by default.\nIt is also possible to use `ProcessPoolExecutor`_.\n\n.. code:: python\n\n    import pandas as pd\n    from concurrent.futures.process import ProcessPoolExecutor\n    from pyathena import connect\n    from pyathena.pandas.util import to_sql\n\n    conn = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                   region_name="us-west-2")\n    df = pd.DataFrame({"a": [1, 2, 3, 4, 5]})\n    to_sql(df, "YOUR_TABLE", conn, "s3://YOUR_S3_BUCKET/path/to/",\n           schema="YOUR_SCHEMA", index=False, if_exists="replace",\n           chunksize=1, executor_class=ProcessPoolExecutor, max_workers=5)\n\n.. _`pandas.DataFrame.to_sql`: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_sql.html\n.. _`ThreadPoolExecutor`: https://docs.python.org/3/library/concurrent.futures.html#threadpoolexecutor\n.. _`ProcessPoolExecutor`: https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor\n\nDictCursor\n~~~~~~~~~~\n\nDictCursor retrieve the query execution result as a dictionary type with column names and values.\n\nYou can use the DictCursor by specifying the ``cursor_class``\nwith the connect method or connection object.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.cursor import DictCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=DictCursor).cursor()\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.cursor import DictCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2",\n                        cursor_class=DictCursor).cursor()\n\nIt can also be used by specifying the cursor class when calling the connection object\'s cursor method.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.cursor import DictCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor(DictCursor)\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.cursor import DictCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2").cursor(DictCursor)\n\nThe basic usage is the same as the Cursor.\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.cursor import DictCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2").cursor(DictCursor)\n    cursor.execute("SELECT * FROM many_rows LIMIT 10")\n    for row in cursor:\n        print(row["a"])\n\nIf you want to change the dictionary type (e.g., use OrderedDict), you can specify like the following.\n\n.. code:: python\n\n    from collections import OrderedDict\n    from pyathena import connect\n    from pyathena.cursor import DictCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=DictCursor).cursor(dict_type=OrderedDict)\n\n.. code:: python\n\n    from collections import OrderedDict\n    from pyathena import connect\n    from pyathena.cursor import DictCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor(cursor=DictCursor, dict_type=OrderedDict)\n\nAsyncCursor\n~~~~~~~~~~~\n\nAsyncCursor is a simple implementation using the concurrent.futures package.\nThis cursor does not follow the `DB API 2.0 (PEP 249)`_.\n\nYou can use the AsyncCursor by specifying the ``cursor_class``\nwith the connect method or connection object.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.async_cursor import AsyncCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncCursor).cursor()\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.async_cursor import AsyncCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2",\n                        cursor_class=AsyncCursor).cursor()\n\nIt can also be used by specifying the cursor class when calling the connection object\'s cursor method.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.async_cursor import AsyncCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor(AsyncCursor)\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.async_cursor import AsyncCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2").cursor(AsyncCursor)\n\nThe default number of workers is 5 or cpu number * 5.\nIf you want to change the number of workers you can specify like the following.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.async_cursor import AsyncCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncCursor).cursor(max_workers=10)\n\nThe execute method of the AsyncCursor returns the tuple of the query ID and the `future object`_.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.async_cursor import AsyncCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncCursor).cursor()\n\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n\nThe return value of the `future object`_ is an ``AthenaResultSet`` object.\nThis object has an interface that can fetch and iterate query results similar to synchronous cursors.\nIt also has information on the result of query execution.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.async_cursor import AsyncCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncCursor).cursor()\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n    result_set = future.result()\n    print(result_set.state)\n    print(result_set.state_change_reason)\n    print(result_set.completion_date_time)\n    print(result_set.submission_date_time)\n    print(result_set.data_scanned_in_bytes)\n    print(result_set.engine_execution_time_in_millis)\n    print(result_set.query_queue_time_in_millis)\n    print(result_set.total_execution_time_in_millis)\n    print(result_set.query_planning_time_in_millis)\n    print(result_set.service_processing_time_in_millis)\n    print(result_set.output_location)\n    print(result_set.description)\n    for row in result_set:\n        print(row)\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.async_cursor import AsyncCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncCursor).cursor()\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n    result_set = future.result()\n    print(result_set.fetchall())\n\nA query ID is required to cancel a query with the AsyncCursor.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.async_cursor import AsyncCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncCursor).cursor()\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n    cursor.cancel(query_id)\n\nNOTE: The cancel method of the `future object`_ does not cancel the query.\n\n.. _`future object`: https://docs.python.org/3/library/concurrent.futures.html#future-objects\n\nAsyncDictCursor\n~~~~~~~~~~~~~~~\n\nAsyncDIctCursor is an AsyncCursor that can retrieve the query execution result\nas a dictionary type with column names and values.\n\nYou can use the DictCursor by specifying the ``cursor_class``\nwith the connect method or connection object.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.async_cursor import AsyncDictCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncDictCursor).cursor()\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.async_cursor import AsyncDictCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2",\n                        cursor_class=AsyncDictCursor).cursor()\n\nIt can also be used by specifying the cursor class when calling the connection object\'s cursor method.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.async_cursor import AsyncDictCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor(AsyncDictCursor)\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.async_cursor import AsyncDictCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2").cursor(AsyncDictCursor)\n\nThe basic usage is the same as the AsyncCursor.\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.cursor import DictCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2").cursor(AsyncDictCursor)\n    query_id, future = cursor.execute("SELECT * FROM many_rows LIMIT 10")\n    result_set = future.result()\n    for row in result_set:\n        print(row["a"])\n\nIf you want to change the dictionary type (e.g., use OrderedDict), you can specify like the following.\n\n.. code:: python\n\n    from collections import OrderedDict\n    from pyathena import connect\n    from pyathena.async_cursor import AsyncDictCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncDictCursor).cursor(dict_type=OrderedDict)\n\n.. code:: python\n\n    from collections import OrderedDict\n    from pyathena import connect\n    from pyathena.async_cursor import AsyncDictCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor(cursor=AsyncDictCursor, dict_type=OrderedDict)\n\nPandasCursor\n~~~~~~~~~~~~\n\nPandasCursor directly handles the CSV file of the query execution result output to S3.\nThis cursor is to download the CSV file after executing the query, and then loaded into `pandas.DataFrame object`_.\nPerformance is better than fetching data with Cursor.\n\nYou can use the PandasCursor by specifying the ``cursor_class``\nwith the connect method or connection object.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor).cursor()\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2",\n                        cursor_class=PandasCursor).cursor()\n\nIt can also be used by specifying the cursor class when calling the connection object\'s cursor method.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor(PandasCursor)\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2").cursor(PandasCursor)\n\nThe as_pandas method returns a `pandas.DataFrame object`_.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor).cursor()\n\n    df = cursor.execute("SELECT * FROM many_rows").as_pandas()\n    print(df.describe())\n    print(df.head())\n\nSupport fetch and iterate query results.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor).cursor()\n\n    cursor.execute("SELECT * FROM many_rows")\n    print(cursor.fetchone())\n    print(cursor.fetchmany())\n    print(cursor.fetchall())\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor).cursor()\n\n    cursor.execute("SELECT * FROM many_rows")\n    for row in cursor:\n        print(row)\n\nThe DATE and TIMESTAMP of Athena\'s data type are returned as `pandas.Timestamp`_ type.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor).cursor()\n\n    cursor.execute("SELECT col_timestamp FROM one_row_complex")\n    print(type(cursor.fetchone()[0]))  # <class \'pandas._libs.tslibs.timestamps.Timestamp\'>\n\nExecution information of the query can also be retrieved.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor).cursor()\n\n    cursor.execute("SELECT * FROM many_rows")\n    print(cursor.state)\n    print(cursor.state_change_reason)\n    print(cursor.completion_date_time)\n    print(cursor.submission_date_time)\n    print(cursor.data_scanned_in_bytes)\n    print(cursor.engine_execution_time_in_millis)\n    print(cursor.query_queue_time_in_millis)\n    print(cursor.total_execution_time_in_millis)\n    print(cursor.query_planning_time_in_millis)\n    print(cursor.service_processing_time_in_millis)\n    print(cursor.output_location)\n\nIf you want to customize the pandas.Dataframe object dtypes and converters, create a converter class like this:\n\n.. code:: python\n\n    from pyathena.converter import Converter\n\n    class CustomPandasTypeConverter(Converter):\n\n        def __init__(self):\n            super(CustomPandasTypeConverter, self).__init__(\n                mappings=None,\n                types={\n                    "boolean": object,\n                    "tinyint": float,\n                    "smallint": float,\n                    "integer": float,\n                    "bigint": float,\n                    "float": float,\n                    "real": float,\n                    "double": float,\n                    "decimal": float,\n                    "char": str,\n                    "varchar": str,\n                    "array": str,\n                    "map": str,\n                    "row": str,\n                    "varbinary": str,\n                    "json": str,\n                }\n            )\n\n        def convert(self, type_, value):\n            # Not used in PandasCursor.\n            pass\n\nSpecify the combination of converter functions in the mappings argument and the dtypes combination in the types argument.\n\nThen you simply specify an instance of this class in the convertes argument when creating a connection or cursor.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor(PandasCursor, converter=CustomPandasTypeConverter())\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     converter=CustomPandasTypeConverter()).cursor(PandasCursor)\n\nIf the unload option is enabled, the Parquet file itself has a schema, so the conversion is done to the dtypes according to that schema,\nand the ``mappings`` and ``types`` settings of the Converter class are not used.\n\nIf you want to change the NaN behavior of pandas.Dataframe,\nyou can do so by using the ``keep_default_na``, ``na_values`` and ``quoting`` arguments of the cursor object\'s execute method.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor).cursor()\n    df = cursor.execute("SELECT * FROM many_rows",\n                        keep_default_na=False,\n                        na_values=[""]).as_pandas()\n\nNOTE: PandasCursor handles the CSV file on memory. Pay attention to the memory capacity.\n\n.. _`pandas.DataFrame object`: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html\n.. _`pandas.Timestamp`: https://pandas.pydata.org/docs/reference/api/pandas.Timestamp.html\n\n[PandasCursor] Chunksize options\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe Pandas cursor can read the CSV file for each specified number of rows by using the chunksize option.\nThis option should reduce memory usage.\n\nThe chunksize option can be enabled by specifying an integer value in the ``cursor_kwargs`` argument of the connect method or as an argument to the cursor method.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor,\n                     cursor_kwargs={\n                         "chunksize": 1_000_000\n                     }).cursor()\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor).cursor(chunksize=1_000_000)\n\nIt can also be specified in the execution method when executing the query.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor).cursor()\n    cursor.execute("SELECT * FROM many_rows", chunksize=1_000_000)\n\nSQLAlchemy allows this option to be specified in the connection string.\n\n.. code:: text\n\n    awsathena+pandas://:@athena.{region_name}.amazonaws.com:443/{schema_name}?s3_staging_dir={s3_staging_dir}&chunksize=1000000...\n\nWhen this option is used, the object returned by the as_pandas method is a ``DataFrameIterator`` object.\nThis object has exactly the same interface as the ``TextFileReader`` object and can be handled in the same way.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor).cursor()\n    df_iter = cursor.execute("SELECT * FROM many_rows", chunksize=1_000_000).as_pandas()\n    for df in df_iter:\n        print(df.describe())\n        print(df.head())\n\nYou can also concatenate them into a single `pandas.DataFrame object`_ using `pandas.concat`_.\n\n.. code:: python\n\n    import pandas\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor).cursor()\n    df_iter = cursor.execute("SELECT * FROM many_rows", chunksize=1_000_000).as_pandas()\n    df = pandas.concat((df for df in df_iter), ignore_index=True)\n\nYou can use the ``get_chunk`` method to retrieve a `pandas.DataFrame object`_ for each specified number of rows.\nWhen all rows have been read, calling the ``get_chunk`` method will raise ``StopIteration``.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor).cursor()\n    df_iter = cursor.execute("SELECT * FROM many_rows LIMIT 15", chunksize=1_000_000).as_pandas()\n    df_iter.get_chunk(10)\n    df_iter.get_chunk(10)\n    df_iter.get_chunk(10)  # raise StopIteration\n\n.. _`pandas.concat`: https://pandas.pydata.org/docs/reference/api/pandas.concat.html\n\n[PandasCursor] Unload options\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nPandasCursor also supports the unload option, as does `ArrowCursor`_.\n\nSee `[ArrowCursor] Unload options`_ for more information.\n\nThe unload option can be enabled by specifying it in the ``cursor_kwargs`` argument of the connect method or as an argument to the cursor method.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor,\n                     cursor_kwargs={\n                         "unload": True\n                     }).cursor()\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import PandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=PandasCursor).cursor(unload=True)\n\nSQLAlchemy allows this option to be specified in the connection string.\n\n.. code:: text\n\n    awsathena+pandas://:@athena.{region_name}.amazonaws.com:443/{schema_name}?s3_staging_dir={s3_staging_dir}&unload=true...\n\nAsyncPandasCursor\n~~~~~~~~~~~~~~~~~\n\nAsyncPandasCursor is an AsyncCursor that can handle `pandas.DataFrame object`_.\nThis cursor directly handles the CSV of query results output to S3 in the same way as PandasCursor.\n\nYou can use the AsyncPandasCursor by specifying the ``cursor_class``\nwith the connect method or connection object.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.async_cursor import AsyncPandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncPandasCursor).cursor()\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.pandas.async_cursor import AsyncPandasCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2",\n                        cursor_class=AsyncPandasCursor).cursor()\n\nIt can also be used by specifying the cursor class when calling the connection object\'s cursor method.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.async_cursor import AsyncPandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor(AsyncPandasCursor)\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.pandas.async_cursor import AsyncPandasCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2").cursor(AsyncPandasCursor)\n\nThe default number of workers is 5 or cpu number * 5.\nIf you want to change the number of workers you can specify like the following.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.async_cursor import AsyncPandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncPandasCursor).cursor(max_workers=10)\n\nThe execute method of the AsyncPandasCursor returns the tuple of the query ID and the `future object`_.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.async_cursor import AsyncPandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncPandasCursor).cursor()\n\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n\nThe return value of the `future object`_ is an ``AthenaPandasResultSet`` object.\nThis object has an interface similar to ``AthenaResultSetObject``.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.async_cursor import AsyncPandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncPandasCursor).cursor()\n\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n    result_set = future.result()\n    print(result_set.state)\n    print(result_set.state_change_reason)\n    print(result_set.completion_date_time)\n    print(result_set.submission_date_time)\n    print(result_set.data_scanned_in_bytes)\n    print(result_set.engine_execution_time_in_millis)\n    print(result_set.query_queue_time_in_millis)\n    print(result_set.total_execution_time_in_millis)\n    print(result_set.query_planning_time_in_millis)\n    print(result_set.service_processing_time_in_millis)\n    print(result_set.output_location)\n    print(result_set.description)\n    for row in result_set:\n        print(row)\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.async_cursor import AsyncPandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncPandasCursor).cursor()\n\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n    result_set = future.result()\n    print(result_set.fetchall())\n\nThis object also has an as_pandas method that returns a `pandas.DataFrame object`_ similar to the PandasCursor.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.async_cursor import AsyncPandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncPandasCursor).cursor()\n\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n    result_set = future.result()\n    df = result_set.as_pandas()\n    print(df.describe())\n    print(df.head())\n\nThe DATE and TIMESTAMP of Athena\'s data type are returned as `pandas.Timestamp`_ type.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.async_cursor import AsyncPandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncPandasCursor).cursor()\n\n    query_id, future = cursor.execute("SELECT col_timestamp FROM one_row_complex")\n    result_set = future.result()\n    print(type(result_set.fetchone()[0]))  # <class \'pandas._libs.tslibs.timestamps.Timestamp\'>\n\nAs with AsyncCursor, you need a query ID to cancel a query.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.async_cursor import AsyncPandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncPandasCursor).cursor()\n\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n    cursor.cancel(query_id)\n\nAs with PandasCursor, the unload option is also available.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import AsyncPandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncPandasCursor,\n                     cursor_kwargs={\n                         "unload": True\n                     }).cursor()\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.pandas.cursor import AsyncPandasCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncPandasCursor).cursor(unload=True)\n\nArrowCursor\n~~~~~~~~~~~\n\nArrowCursor directly handles the CSV file of the query execution result output to S3.\nThis cursor is to download the CSV file after executing the query, and then loaded into `pyarrow.Table object`_.\nPerformance is better than fetching data with Cursor.\n\nYou can use the ArrowCursor by specifying the ``cursor_class``\nwith the connect method or connection object.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.cursor import ArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=ArrowCursor).cursor()\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.arrow.cursor import ArrowCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2",\n                        cursor_class=ArrowCursor).cursor()\n\nIt can also be used by specifying the cursor class when calling the connection object\'s cursor method.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.cursor import ArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor(ArrowCursor)\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.arrow.cursor import ArrowCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2").cursor(ArrowCursor)\n\nThe as_arrow method returns a `pyarrow.Table object`_.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.cursor import ArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=ArrowCursor).cursor()\n\n    table = cursor.execute("SELECT * FROM many_rows").as_arrow()\n    print(table)\n    print(table.column_names)\n    print(table.columns)\n    print(table.nbytes)\n    print(table.num_columns)\n    print(table.num_rows)\n    print(table.schema)\n    print(table.shape)\n\nSupport fetch and iterate query results.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.cursor import ArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=ArrowCursor).cursor()\n\n    cursor.execute("SELECT * FROM many_rows")\n    print(cursor.fetchone())\n    print(cursor.fetchmany())\n    print(cursor.fetchall())\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.cursor import ArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=ArrowCursor).cursor()\n\n    cursor.execute("SELECT * FROM many_rows")\n    for row in cursor:\n        print(row)\n\nExecution information of the query can also be retrieved.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.cursor import ArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=ArrowCursor).cursor()\n\n    cursor.execute("SELECT * FROM many_rows")\n    print(cursor.state)\n    print(cursor.state_change_reason)\n    print(cursor.completion_date_time)\n    print(cursor.submission_date_time)\n    print(cursor.data_scanned_in_bytes)\n    print(cursor.engine_execution_time_in_millis)\n    print(cursor.query_queue_time_in_millis)\n    print(cursor.total_execution_time_in_millis)\n    print(cursor.query_planning_time_in_millis)\n    print(cursor.service_processing_time_in_millis)\n    print(cursor.output_location)\n\nIf you want to customize the `pyarrow.Table object`_ types, create a converter class like this:\n\n.. code:: python\n\n    import pyarrow as pa\n    from pyathena.arrow.converter import _to_date\n    from pyathena.converter import Converter\n\n    class CustomArrowTypeConverter(Converter):\n        def __init__(self) -> None:\n            super(CustomArrowTypeConverter, self).__init__(\n                mappings={\n                    "date": _to_date,\n                },\n                types={\n                    "boolean": pa.bool_(),\n                    "tinyint": pa.int8(),\n                    "smallint": pa.int16(),\n                    "integer": pa.int32(),\n                    "bigint": pa.int64(),\n                    "float": pa.float32(),\n                    "real": pa.float64(),\n                    "double": pa.float64(),\n                    "char": pa.string(),\n                    "varchar": pa.string(),\n                    "string": pa.string(),\n                    "timestamp": pa.timestamp("ms"),\n                    "date": pa.timestamp("ms"),\n                    "time": pa.string(),\n                    "varbinary": pa.string(),\n                    "array": pa.string(),\n                    "map": pa.string(),\n                    "row": pa.string(),\n                    "decimal": pa.string(),\n                    "json": pa.string(),\n                },\n            )\n\n    def convert(self, type_, value):\n        converter = self.get(type_)\n        return converter(value)\n\n``types`` is used to explicitly specify the Arrow type when reading CSV files.\n``mappings`` is used as a conversion method when fetching data from a cursor object.\n\nThen you simply specify an instance of this class in the convertes argument when creating a connection or cursor.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.cursor import ArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor(ArrowCursor, converter=CustomArrowTypeConverter())\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.cursor import ArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     converter=CustomArrowTypeConverter()).cursor(ArrowCursor)\n\nIf the unload option is enabled, the Parquet file itself has a schema, so the conversion is done to the Arrow type according to that schema,\nand the ``types`` setting of the Converter class is not used.\n\n[ArrowCursor] Unload options\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nArrowCursor supports the unload option. When this option is enabled,\nqueries with SELECT statements are automatically converted to unload statements and executed to Athena,\nand the results are output in Parquet format (Snappy compressed) to ``s3_staging_dir``.\nThe cursor reads the output Parquet file directly.\n\nThe output of query results with the unload statement is faster than normal query execution.\nIn addition, the output Parquet file is split and can be read faster than a CSV file.\nWe recommend trying this option if you are concerned about the time it takes to execute the query and retrieve the results.\n\nHowever, unload has some limitations. Please refer to the `official unload documentation`_ for more information on limitations.\nAs per the limitations of the official documentation, the results of unload will be written to multiple files in parallel,\nand the contents of each file will be in sort order, but the relative order of the files to each other will not be sorted.\nNote that specifying ORDER BY with this option enabled does not guarantee the sort order of the data.\n\nThe unload option can be enabled by specifying it in the ``cursor_kwargs`` argument of the connect method or as an argument to the cursor method.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.cursor import ArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=ArrowCursor,\n                     cursor_kwargs={\n                         "unload": True\n                     }).cursor()\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.cursor import ArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=ArrowCursor).cursor(unload=True)\n\nSQLAlchemy allows this option to be specified in the connection string.\n\n.. code:: text\n\n    awsathena+arrow://:@athena.{region_name}.amazonaws.com:443/{schema_name}?s3_staging_dir={s3_staging_dir}&unload=true...\n\nIf a ``NOT_SUPPORTED`` occurs, a type not supported by unload is included in the result of the SELECT.\nTry converting to another type, such as ``SELECT CAST(1 AS VARCHAR) AS name``.\n\n.. code:: text\n\n    pyathena.error.OperationalError: NOT_SUPPORTED: Unsupported Hive type: time\n\nIn most cases of ``SYNTAX_ERROR``, you forgot to alias the column in the SELECT result.\nTry adding an alias to the SELECTed column, such as ``SELECT 1 AS name``.\n\n.. code:: text\n\n    pyathena.error.OperationalError: SYNTAX_ERROR: line 1:1: Column name not specified at position 1\n\n.. _`pyarrow.Table object`: https://arrow.apache.org/docs/python/generated/pyarrow.Table.html\n.. _`official unload documentation`: https://docs.aws.amazon.com/athena/latest/ug/unload.html\n\nAsyncArrowCursor\n~~~~~~~~~~~~~~~~\n\nAsyncArrowCursor is an AsyncCursor that can handle `pyarrow.Table object`_.\nThis cursor directly handles the CSV of query results output to S3 in the same way as ArrowCursor.\n\nYou can use the AsyncArrowCursor by specifying the ``cursor_class``\nwith the connect method or connection object.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.async_cursor import AsyncArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncArrowCursor).cursor()\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.arrow.async_cursor import AsyncArrowCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2",\n                        cursor_class=AsyncArrowCursor).cursor()\n\nIt can also be used by specifying the cursor class when calling the connection object\'s cursor method.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.async_cursor import AsyncArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor(AsyncArrowCursor)\n\n.. code:: python\n\n    from pyathena.connection import Connection\n    from pyathena.arrow.async_cursor import AsyncArrowCursor\n\n    cursor = Connection(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                        region_name="us-west-2").cursor(AsyncArrowCursor)\n\nThe default number of workers is 5 or cpu number * 5.\nIf you want to change the number of workers you can specify like the following.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.async_cursor import AsyncArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncArrowCursor).cursor(max_workers=10)\n\nThe execute method of the AsyncArrowCursor returns the tuple of the query ID and the `future object`_.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.async_cursor import AsyncArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncArrowCursor).cursor()\n\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n\nThe return value of the `future object`_ is an ``AthenaArrowResultSet`` object.\nThis object has an interface similar to ``AthenaResultSetObject``.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.async_cursor import AsyncArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncArrowCursor).cursor()\n\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n    result_set = future.result()\n    print(result_set.state)\n    print(result_set.state_change_reason)\n    print(result_set.completion_date_time)\n    print(result_set.submission_date_time)\n    print(result_set.data_scanned_in_bytes)\n    print(result_set.engine_execution_time_in_millis)\n    print(result_set.query_queue_time_in_millis)\n    print(result_set.total_execution_time_in_millis)\n    print(result_set.query_planning_time_in_millis)\n    print(result_set.service_processing_time_in_millis)\n    print(result_set.output_location)\n    print(result_set.description)\n    for row in result_set:\n        print(row)\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.async_cursor import AsyncArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncArrowCursor).cursor()\n\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n    result_set = future.result()\n    print(result_set.fetchall())\n\nThis object also has an as_arrow method that returns a `pyarrow.Table object`_ similar to the ArrowCursor.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.async_cursor import AsyncArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncArrowCursor).cursor()\n\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n    result_set = future.result()\n    table = result_set.as_arrow()\n    print(table)\n    print(table.column_names)\n    print(table.columns)\n    print(table.nbytes)\n    print(table.num_columns)\n    print(table.num_rows)\n    print(table.schema)\n    print(table.shape)\n\nAs with AsyncCursor, you need a query ID to cancel a query.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.async_cursor import AsyncArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncArrowCursor).cursor()\n\n    query_id, future = cursor.execute("SELECT * FROM many_rows")\n    cursor.cancel(query_id)\n\nAs with ArrowCursor, the UNLOAD option is also available.\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.cursor import AsyncArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncArrowCursor,\n                     cursor_kwargs={\n                         "unload": True\n                     }).cursor()\n\n.. code:: python\n\n    from pyathena import connect\n    from pyathena.arrow.cursor import AsyncArrowCursor\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2",\n                     cursor_class=AsyncArrowCursor).cursor(unload=True)\n\nQuickly re-run queries\n~~~~~~~~~~~~~~~~~~~~~~\n\nResult reuse configuration\n^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nAthena engine version 3 allows you to `reuse the results of previous queries`_.\n\nIt is available by specifying the arguments ``result_reuse_enable`` and ``result_reuse_minutes`` in the connection object.\n\n.. code:: python\n\n    from pyathena import connect\n\n    conn = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                   region_name="us-west-2",\n                   work_group="YOUR_WORK_GROUP",\n                   result_reuse_enable=True,\n                   result_reuse_minutes=60)\n\nYou can also specify ``result_reuse_enable`` and ``result_reuse_minutes`` when executing a query.\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n    cursor.execute("SELECT * FROM one_row",\n                   work_group="YOUR_WORK_GROUP",\n                   result_reuse_enable=True,\n                   result_reuse_minutes=60)\n\nIf the following error occurs, please use a workgroup configured with Athena engine version 3.\n\n.. code:: text\n\n    pyathena.error.DatabaseError: An error occurred (InvalidRequestException) when calling the StartQueryExecution operation: This functionality is not enabled in the selected engine version. Please check the engine version settings or contact AWS support for further assistance.\n\nIf for some reason you cannot use the reuse feature of Athena engine version 3, please use the `Cache configuration`_ implemented by PyAthena.\n\n.. _`reuse the results of previous queries`: https://docs.aws.amazon.com/athena/latest/ug/reusing-query-results.html\n\nCache configuration\n^^^^^^^^^^^^^^^^^^^\n\n**Please use the Result reuse configuration.**\n\nYou can attempt to re-use the results from a previously executed query to help save time and money in the cases where your underlying data isn\'t changing.\nSet the ``cache_size`` or ``cache_expiration_time`` parameter of ``cursor.execute()`` to a number larger than 0 to enable caching.\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n    cursor.execute("SELECT * FROM one_row")  # run once\n    print(cursor.query_id)\n    cursor.execute("SELECT * FROM one_row", cache_size=10)  # re-use earlier results\n    print(cursor.query_id)  # You should expect to see the same Query ID\n\nThe unit of ``expiration_time`` is seconds. To use the results of queries executed up to one hour ago, specify like the following.\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n    cursor.execute("SELECT * FROM one_row", cache_expiration_time=3600)  # Use queries executed within 1 hour as cache.\n\nIf ``cache_size`` is not specified, the value of ``sys.maxsize`` will be automatically set and all query results executed up to one hour ago will be checked.\nTherefore, it is recommended to specify ``cache_expiration_time`` together with ``cache_size`` like the following.\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n    cursor.execute("SELECT * FROM one_row", cache_size=100, cache_expiration_time=3600)  # Use the last 100 queries within 1 hour as cache.\n\nResults will only be re-used if the query strings match *exactly*,\nand the query was a DML statement (the assumption being that you always want to re-run queries like ``CREATE TABLE`` and ``DROP TABLE``).\n\nThe S3 staging directory is not checked, so it\'s possible that the location of the results is not in your provided ``s3_staging_dir``.\n\nCredentials\n-----------\n\nSupport `Boto3 credentials`_.\n\n.. _`Boto3 credentials`: http://boto3.readthedocs.io/en/latest/guide/configuration.html\n\nAdditional environment variable:\n\n.. code:: bash\n\n    $ export AWS_ATHENA_S3_STAGING_DIR=s3://YOUR_S3_BUCKET/path/to/\n    $ export AWS_ATHENA_WORK_GROUP=YOUR_WORK_GROUP\n\nExamples\n~~~~~~~~\n\nPassing credentials as parameters\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(aws_access_key_id="YOUR_ACCESS_KEY_ID",\n                     aws_secret_access_key="YOUR_SECRET_ACCESS_KEY",\n                     s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(aws_access_key_id="YOUR_ACCESS_KEY_ID",\n                     aws_secret_access_key="YOUR_SECRET_ACCESS_KEY",\n                     aws_session_token="YOUR_SESSION_TOKEN",\n                     s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n\nMulti-factor authentication\n^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nYou will be prompted to enter the MFA code.\nThe program execution will be blocked until the MFA code is entered.\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(duration_seconds=3600,\n                     serial_number="arn:aws:iam::ACCOUNT_NUMBER_WITHOUT_HYPHENS:mfa/MFA_DEVICE_ID",\n                     s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n\nShared credentials file\n^^^^^^^^^^^^^^^^^^^^^^^\n\nThe shared credentials file has a default location of ~/.aws/credentials.\n\nIf you use the default profile, there is no need to specify credential information.\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n\nYou can also specify a profile other than the default.\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(profile_name="YOUR_PROFILE_NAME",\n                     s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n\nAssume role provider\n^^^^^^^^^^^^^^^^^^^^\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(role_arn="YOUR_ASSUME_ROLE_ARN",\n                     role_session_name="PyAthena-session",\n                     duration_seconds=3600,\n                     s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n\nAssume role provider with MFA\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nYou will be prompted to enter the MFA code.\nThe program execution will be blocked until the MFA code is entered.\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(role_arn="YOUR_ASSUME_ROLE_ARN",\n                     role_session_name="PyAthena-session",\n                     duration_seconds=3600,\n                     serial_number="arn:aws:iam::ACCOUNT_NUMBER_WITHOUT_HYPHENS:mfa/MFA_DEVICE_ID",\n                     s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n\nInstance profiles\n^^^^^^^^^^^^^^^^^\n\nNo need to specify credential information.\n\n.. code:: python\n\n    from pyathena import connect\n\n    cursor = connect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",\n                     region_name="us-west-2").cursor()\n\nTesting\n-------\n\nDepends on the following environment variables:\n\n.. code:: bash\n\n    $ export AWS_DEFAULT_REGION=us-west-2\n    $ export AWS_ATHENA_S3_STAGING_DIR=s3://YOUR_S3_BUCKET/path/to/\n    $ export AWS_ATHENA_WORKGROUP=pyathena-test\n\nIn addition, you need to create a workgroup with the `Query result location` set to the name specified in the `AWS_ATHENA_WORKGROUP` environment variable.\nIf primary is not available as the default workgroup, specify an alternative workgroup name for the default in the environment variable `AWS_ATHENA_DEFAULT_WORKGROUP`.\n\n.. code:: bash\n\n    $ export AWS_ATHENA_DEFAULT_WORKGROUP=DEFAULT_WORKGROUP\n\nRun test\n~~~~~~~~\n\n.. code:: bash\n\n    $ pip install poetry\n    $ poetry install -v\n    $ poetry run pytest\n\nRun test multiple Python versions\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code:: bash\n\n    $ pip install poetry\n    $ poetry install -v\n    $ pyenv local 3.11.1 3.10.1 3.9.1 3.8.2 3.7.2\n    $ poetry run tox\n\nGitHub Actions\n~~~~~~~~~~~~~~\n\nGitHub Actions uses OpenID Connect (OIDC) to access AWS resources. You will need to refer to the `GitHub Actions documentation`_ to configure it.\n\n.. _`GitHub Actions documentation`: https://docs.github.com/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services\n\nThe CloudFormation templates for creating GitHub OIDC Provider and IAM Role can be found in the `aws-actions/configure-aws-credentials repository`_.\n\n.. _`aws-actions/configure-aws-credentials repository`: https://github.com/aws-actions/configure-aws-credentials#sample-iam-role-cloudformation-template\n\nUnder `scripts/cloudformation`_ you will also find a CloudFormation template with additional permissions and workgroup settings needed for testing.\n\n.. _`scripts/cloudformation`: scripts/cloudformation/\n\nThe example of the CloudFormation execution command is the following:\n\n.. code:: bash\n\n    $ aws --region us-west-2 \\\n        cloudformation create-stack \\\n        --stack-name github-actions-oidc-pyathena \\\n        --capabilities CAPABILITY_NAMED_IAM \\\n        --template-body file://./scripts/cloudformation/github_actions_oidc.yaml \\\n        --parameters ParameterKey=GitHubOrg,ParameterValue=laughingman7743 \\\n          ParameterKey=RepositoryName,ParameterValue=PyAthena \\\n          ParameterKey=BucketName,ParameterValue=laughingman7743-athena \\\n          ParameterKey=RoleName,ParameterValue=github-actions-oidc-pyathena-test \\\n          ParameterKey=WorkGroupName,ParameterValue=pyathena-test\n\nCode formatting\n---------------\n\nThe code formatting uses `black`_ and `isort`_.\n\nAppy format\n~~~~~~~~~~~\n\n.. code:: bash\n\n    $ make fmt\n\nCheck format\n~~~~~~~~~~~~\n\n.. code:: bash\n\n    $ make chk\n\n.. _`black`: https://github.com/psf/black\n.. _`isort`: https://github.com/timothycrosley/isort\n\nLicense\n-------\n\n`MIT license`_\n\nMany of the implementations in this library are based on `PyHive`_, thanks for `PyHive`_.\n\n.. _`MIT license`: LICENSE\n.. _`PyHive`: https://github.com/dropbox/PyHive\n',
    'author': 'laughingman7743',
    'author_email': 'laughingman7743@gmail.com',
    'maintainer': 'None',
    'maintainer_email': 'None',
    'url': 'https://github.com/laughingman7743/PyAthena/',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'extras_require': extras_require,
    'entry_points': entry_points,
    'python_requires': '>=3.7.1,<4.0.0',
}


setup(**setup_kwargs)
