Repository: databricks/python-bitdotio (language: python)

Issue:
Docs v2
Add docs for v2


Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index 734a73a..626d951 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,5 +3,6 @@ build
 dist
 env
 venv
+*.pyc
 __pycache__
 .vscode/settings.json
diff --git a/README.md b/README.md
index a2499c5..5788a5f 100644
--- a/README.md
+++ b/README.md
@@ -1,31 +1,9 @@
 # bit.io Python SDK & Command Line Tool
 
-# bitdotio module
+## Installation
 
-The v2 SDK currently only supports generation of pre-configured `psycopg2` connections
-to v2 bit.io. We plan to add further SDK operations as we begin expanding the 
-bit.io [Developer API](https://docs.bit.io/reference/get_db_list_v2beta_db__get). 
-
-Example v2 usage:
-```python
-#!/usr/bin/env python3
-import bitdotio
-from pprint import pprint
-
-# Instantiate a bit.io client for connecting to databases
-b = bitdotio.bitdotio(<YOUR_API_KEY>)
-
-# Connect to a database by name 
-conn = b.get_connection(<YOUR_DATABASE_NAME>)
-cur = conn.cursor()
-cur.execute("SELECT 1")
-pprint(cur.fetchone())
-```
-
-## Requirements
-
-In order to support different environments, we have a few ways to install the bitdotio package
-with or without the `psycopg2` dependency.
+In order to support different environments, we have a few ways to install the bitdotio
+package with or without the `psycopg2` dependency.
 
 1. If you already have `psycopg2` installed, you can install the default bitdotio package:
 ```
@@ -42,38 +20,312 @@ pip install 'bitdotio[psycopg2]'
 pip install 'bitdotio[psycopg2-binary]'
 ```
 
-### Install Postgres
-
-To install Postgres on Windows, go to https://www.postgresql.org/download/ and download the version
-that is correct for your computer, or use your operating system's preferred package manager.
-
-After you have Postgres installed you can install this library with `pip install bitdotio[psycopg2]`.
-
+# `bitdotio` module
 
 ## Usage
 
+The `bitdotio` module consists of a `bitdotio` SDK object which provides helpful
+utilities for creating and managing pre-configured connections to bit.io databases
+via `psycopg2`, as well as easy methods for accessing the functionality exposed by the
+[bit.io developer API](https://docs.bit.io/reference)
+
 Once you have `bitdotio` installed all you need is your API key to start working with bit.io.
 
 You can get your API key by logging into bit.io and opening [the "Connect" tab](https://docs.bit.io/docs/your-connection-credentials) on a database page.
 
+### Example usage
 
-### Python DB-API usage
-
-`bitdotio` provides easy Python access to querying your data with just a bit.io API key:
+See API reference at the bottom of this document for a full list of methods provided by
+the SDK.
 
 ```python
-#!/usr/bin/env python3
-import bitdotio
+import os
+
+from bitdotio import bitdotio
+
+
+# Load bit.io API key from environment variable
+BITIO_KEY = os.environ.get("BITIO_KEY")
+
+# Instantiate the bit.io SDK object
+b = bitdotio(BITIO_KEY)
+
+# Create a new public database on bit.io
+db_metadata = b.create_database("my-db", is_private=False)
+db_name = db_metadata["name"]
+
+# Use a pooled cursor to insert some data
+with b.pooled_cursor(db_name) as cur:
+    cur.execute("CREATE TABLE person (name text, age integer);")
+    people = [("Alice", 45), ("Bob", 84), ("Catherine", 19), ("Davis", 22), ("Emily", 34)]
+    for name, age in people:
+        cur.execute("INSERT INTO person (name, age) VALUES (%s, %s)", (name, age))
+
+# Execute a query via the HTTP API
+print(b.query(db_name, "SELECT * FROM person", data_format="objects"))
+```
+
+### Making queries
+
+#### Connecting directly
+
+The `bitdotio` SDK object provides the methods `pooled_connection`, `pooled_cursor`, and
+`get_connection` for connecting directly to your database (see below for discusson on
+when to use each of these). The connections/cursors returned by these methods are
+`psycopg2` connections and cursors, which are fully compatible with the
+[Python DB-API](https://peps.python.org/pep-0249/). Full documentation on `psycopg2` can
+be found [here](https://www.psycopg.org/docs/usage.html.).
+
+It is preferable to use direct connections in the majority of cases, since they have
+superior performance and enable more features compared to the `query` method. In
+particular we strongly recommend using direct connections in programs that are
+long-running, require transaction management, or transfer large quantities of data.
+
+#### The `query` method
+
+The `query` runs queries via the bit.io HTTP API, and therefore will have worse
+performance and feature support than direct connections. Importantly, each query run
+via the `query` method is run in a single transaction. The `query` method is recommended
+in situations where installing a database driver is undesirable or impossible, when
+queries are being run very infrequently, or in very short-lived contexts such as one-off
+scripts or serverless backends.
+
+### Connection pooling and management
+
+The recommended way to obtain a direct connection to a bit.io database is via a
+connection pool. In order to support scaling to zero, bit.io automatically closes idle
+connections after a period of time, and puts databases into a dormant state when there
+are no live connections. If you are designing a long-running application, you should
+make sure that your database access pattern is resilient to connection closures and
+database shutdowns. The best way to do this is via a connection pool. Acquiring
+connections from a connection pool allows connection re-use, and handles reconnects in
+the event that a connection is dropped. The `bitdotio` SDK object internally manages a
+thread-safe connection pool per-database that the caller connects to, and provides two
+helpful context mangers for acquiring connections from a pool:
+- `pooled_connection`: A context manager providing a `psycopg2` connection to the
+  given database acquired from a connection pool. When exiting the context created by
+  this context manager, the connection is returned to the pool if still open, or
+  discarded if closed. It is recommended to use this method when executing multiple
+  transacions, or in situations where explicit transaction management is required.
+- `pooled_cursor`: A context manager providing a `psycopg2` cursor created from a
+  connection acquired from a connection pool. When exiting the context created by this
+  context manager, the cursor's tansaction will be committed, and its connection will be
+  returned to the connection pool. It is recommended to use this method in situations
+  where a single transaction is required without any complex handling logic. For
+  example, performing a sequence of `SELECT` queries, or performing a single insertion
+  or update.
+
+There may be situations in which a self-managed, unpooled connection is needed. For
+example, if the client needs to persist state onto the connection's database session using
+the `SET` command. For such situations, the SDK object provides the `get_connection`
+method.
 
-# Connect to bit.io
-b = bitdotio.bitdotio(<YOUR_API_KEY>)
+For more information on all of the above, refer to the `psycopg2` documentation on
+[connections](https://www.psycopg.org/docs/connection.html),
+[cursors](https://www.psycopg.org/docs/cursor.html),
+and [pools](https://www.psycopg.org/docs/pool.html).
 
-conn = b.get_connection(<YOUR_DATABASE_NAME>)
-cur = conn.cursor()
-cur.execute("SELECT 1")
-print(cur.fetchone())
+### Multiprocessing
+
+The `bitdotio` SDK object is not safe to share between multiple processes. If you are
+programming in a multiprocess environment, ensure that a `bitdotio` SDK object is
+created per-process, not pre-fork.
+
+# `bit` CLI
+
+Installing the `bitdotio` module also installs the command line tool `bit` which lets
+you interact with bit.io from scripts or the command line. This is installed next to
+your python binary.
+
+You'll want to grab your API key from your bit.io account - to get the key, log into to
+bit.io, go to any database, and retrieve it from the "Connect" tab.
+
+```
+Usage: bit [OPTIONS] COMMAND [ARGS]...
+
+Options:
+  -k, --key TEXT  Your bit.io API key, available when you click the connect
+                  button in bit.io
+  --help          Show this message and exit.
+
+Commands:
+  db
+  query
+```
+
+All of the commands return JSON.
+
+You can supply your API key either via the `-k/--key` argument, or by setting the it to
+the `BITIO_KEY` environment variable. The latter option keeps the key from showing up
+in, eg, a `ps` command, and allows secret injection for systems like Kubernetes.
+
+
+### Examples
+
+#### List databases
+```sh
+BITIO_KEY=<your key> bit db list
 ```
 
-The connection and cursor provided by `bitdotio` are fully Python DB-API compatible, are in fact Pyscopg2 connections and cursors.
+This is the same as:
+
+```sh
+bit -k <your-key> db list
+```
+
+#### Run a query
+```sh
+bit -k <your-key> query -d "username/dbname" -q "SELECT * FROM my_table"
+```
+
+# API Reference
+
+#### `bitdotio(access_token, min_conn=0, max_conn=100)`
+
+Returns an instance of the bit.io SDK object.
+
+_Args_:
+- `access_token (str)`: Your bit.io API key
+
+_Kwargs_:
+- `min_conn (int)`: The minimum number of live connections per database connection pool.
+- `max_conn (int)`: The maximum number of live connections per database connection pool.
+
+_Returns_:
+
+A bit.io SDK instance
+
+<hr>
+
+#### `bitdotio.pooled_connection(db_name)`
+
+Creates a context manager which provides a connection from the connection pool for the
+given database name. When the context manager is exited, the connection will be returned
+to the connection pool.
+
+_Args_:
+- `db_name (str)`: The name of the database to connect to.
+
+_Returns_:
+
+Context manager yielding a `psycopg2.connection`.
+
+<hr>
+
+#### `bitdotio.pooled_cursor(db_name)`
+
+Creates a context manager which provides a cursor from the connection pool for the
+given database name. When the context manager is exited, the cursor's transaction will
+be committed, and its connection will be returned to the connection pool.
+
+_Args_:
+- `db_name (str)`: The name of the database to connect to.
+
+_Returns_:
+
+Context manager yielding a `psycopg2.connection`.
+
+<hr>
+
+#### `bitdotio.get_connection(db_name)`
+
+Returns an unmanaged, unpooled connection to the given database.
+
+_Args_:
+- `db_name (str)`: The name of the database to connect to.
+
+_Returns_:
+
+A `psycopg2.connection` object configured for the given database.
+
+<hr>
+
+#### `bitdotio.query(db_name, query_str, data_format=None)`
+
+Execute a query via the bit.io HTTP API
+
+_Args_:
+- `db_name (str)`: Name of the database to execute a query against.
+- `query_str (str)`: Query to execute.
+
+_Kwargs_:
+- `data_format (Optional[str])`:
+
+_Returns_:
+
+Dictionary describing query results.
+
+<hr>
+
+#### `bitdotio.list_databases()`
+
+List metadata pertaining to databases the requester is an owner or collaborator of.
+
+_Returns_:
+
+List of dictionaries describing database metadata.
+
+<hr>
+
+#### `bitdotio.create_database(name, is_private=True, storage_limit_bytes=None)`
+
+_Args_:
+- `name (str)`: Name of the database being created (excluding the owner's username)
+
+_Kwargs_:
+- `is_private (bool)`: Whether or not the database is set to private. Databases default
+  to private.
+- `storage_limit_bytes (Optional[int])`: Maximum storage for the database in bytes.
+  Limits and defaults are enforced based on billing plan regardless of what is set here.
+
+_Returns_:
+
+Dict containing metadata about the newly created database.
+
+<hr>
+
+#### `bitdotio.get_database(db_name)`
+
+Get metadata about a single database.
+
+_Args_:
+- `db_name (str)`: Name of the database to fetch metadata for.
+
+_Returns_:
+
+Dict containing metadata about the given database.
+
+<hr>
+
+#### `bitdotio.update_database(db_name, name=None, is_private=None, storage_limit_bytes=None)`
+
+Update metadata parameters for a given database.
+
+_Args_:
+- `db_name (str)`: Name of the database to update.
+
+_Kwargs_:
+- `name (Optional[str])`: New name for the database (excluding the owner's username).
+- `is_private (Optional[str])`: Whether or not the database is set to private.
+- `storage_limit_bytes (Optional[int])`: Maximum storage for the database in bytes.
+  Limits and defaults are enforced based on billing plan regardless of what is set here.
+
+_Returns_:
+
+Up to date metadata about the updated database.
+
+<hr>
+
+#### `bitdotio.delete_database(db_name)`
+
+Delete a database. After deletion the database's name will be unusable for up to 30
+days. If you need to reuse it sooner, please contact bit.io support.
+
+_Args_:
+- `db_name (str)`: Name of the database to delete
+
+_Returns_:
+
+None.
 
-Full documentation on Psycopg2 can be found on https://www.psycopg.org/docs/usage.html.
\ No newline at end of file
+<hr>
diff --git a/bit/bit.py b/bit/bit.py
index 53ec56a..1706d7f 100755
--- a/bit/bit.py
+++ b/bit/bit.py
@@ -1,11 +1,17 @@
 #!/usr/bin/env python3
-import bitdotio
+import os
 import click
 import sys
 import json
-from urllib.parse import urlparse
-import posixpath
 
+from bitdotio import __version__, bitdotio
+
+
+USER_AGENT = f"python-bitdotio-cli/{__version__}"
+
+
+def printj(obj):
+    print(json.dumps(obj))
 
 
 # Allows overriding the required `-k` when subcommands have `--help`
@@ -13,167 +19,137 @@
 class IgnoreRequiredWithHelp(click.Group):
     def parse_args(self, ctx, args):
         try:
-            return super(IgnoreRequiredWithHelp, self).parse_args(ctx, args)
-        except click.MissingParameter as exc:
-            if '--help' not in args:
+            return super().parse_args(ctx, args)
+        except click.MissingParameter:
+            if "--help" not in args:
                 raise
-            # remove the required params so that help can display
-            for param in self.params:
-                if param.name == "key":
-                    param.required = False
-                    break
-            return super(IgnoreRequiredWithHelp, self).parse_args(ctx, args)
+
+            # HACK: if just doing --help, pass in a phony key that passes regex
+            # validation.
+            return super().parse_args(ctx, ["-k", "v2_help", "--help"])
+
 
 @click.group(cls=IgnoreRequiredWithHelp)
-@click.option("-k", "--key", required=True, help="Your bit.io API key, available when you click the connect button in bit.io")
-@click.option("-v", "--verbose", default=False, is_flag=True, show_default=True, help="Verbose output")
+@click.option(
+    "-k",
+    "--key",
+    required=False,
+    help="Your bit.io API key, available when you click the connect button in bit.io",
+)
 @click.pass_context
-def bitio(ctx, key, verbose):
-    if key:
-        b = bitdotio.bitdotio(key)
-        b.api_client.user_agent = b.api_client.user_agent + "/CLI"
-        if verbose:
-            b.api_client.configuration.debug = True
-        ctx.obj = b
+def bitio(ctx, key):
+    if key is None:
+        key = os.environ.get("BITIO_KEY")
+        if key is None:
+            raise click.MissingParameter(
+                "Your bit.io key must be set either using the -k/--key argument or as the environment variable BITIO_KEY"
+            )
 
+    b = bitdotio(key)
+    b._api_client.set_header("User-Agent", USER_AGENT)
+    ctx.obj = b
 
-#  python3 bit.py -k your_api_key_here query -q "SELECT *  FROM \"a/demo_repo\".\"atl_home_sales\""
-# echo  "SELECT *  FROM \"a/demo_repo\".\"atl_home_sales\"" | python3 bit.py -k your_api_key_here query -qf -
+
+# bit -k <api-key> query -d <db-name> -q "SELECT 1"
 @bitio.command()
+@click.option("-d", "--database", required=True, help="Name of the database to query")
 @click.option("-q", "--query", required=False, help="The SQL to run.")
-@click.option("-qf", "--query_file", required=False, help="A SQL file run, containing a single query. Use - for stdin.", type=click.File('r'))
+@click.option(
+    "-qf",
+    "--query_file",
+    required=False,
+    help="A SQL file to run, containing a single query. Use - for stdin.",
+    type=click.File("r"),
+)
+@click.option(
+    "-o",
+    "--objects",
+    is_flag=True,
+    help="Return data as an array of JSON objects instead of row arrays",
+)
 @click.pass_obj
-def query(b, query, query_file):
+def query(b, database, query, query_file, objects):
     if query:
         query_string = query
     elif query_file:
         with query_file:
             query_string = query_file.read()
     else:
-        raise click.UsageError("One of --query or --query_file is required.")
+        raise click.UsageError("One of --query or --query_file is required")
 
-    query_obj = bitdotio.model.query.Query(query_string=query_string)
-    print_json_model(b.create_query(query=query_obj))
+    if objects:
+        printj(b.query(database, query_string, data_format="objects"))
+    else:
+        printj(b.query(database, query_string))
 
 
 @bitio.group()
 @click.pass_obj
-def repo(b):
+def db(b):
     pass
 
 
-# python3 bit.py -k your_api_key_here repo create -n foobarsadsasds -d "foo bar baz" -p False
-@repo.command()
-@click.option("-r", "--repo_name", required=True, help="The repo name.")
-@click.option("-d", "--description", default="", help="The repo description.")
-@click.option("-p", "--is_private", show_default=True, default=True, help="Is this repo private or not.")
-@click.pass_obj
-def create(b, repo_name, description, is_private):
-    r = bitdotio.model.repo.Repo(name=repo_name)
-    r.description = description
-    r.is_private = is_private
-    print_json_model(b.create_repo(repo=r))
-
-@repo.command()
+@db.command()
 @click.pass_obj
 def list(b):
-    print_json_model_list(b.list_repos())
-
-# bit.py -k your_api_key_here repo retrieve -n demo_repo
-@repo.command()
-@click.option("-r", "--repo_name", required=True, help="The repo name.")
-@click.pass_obj
-def retrieve(b, repo_name):
-    print_json_model(b.retrieve_repo(repo_name))
-
-# bit.py -k your_api_key_here repo destroy -n demo_repo
-@repo.command()
-@click.option("-n", "--name", required=True, help="The repo name.")
-@click.option("-y", "--yes", default=False, is_flag=True, show_default=True, help="Skip the confirmation")
-@click.pass_obj
-def destroy(b, name, yes):
-    if yes:
-        print_json_model(b.destroy_repo(name))
-    elif click.confirm(f"Are you sure you want destroy the repo {name}?"):
-        print_json_model(b.destroy_repo(name))
-
-
-@bitio.group(name="import")
+    printj(b.list_databases())
+
+
+@db.command()
+@click.option("-n", "--name", required=True, help="The database name")
+@click.option(
+    "-p",
+    "--is_private",
+    show_default=True,
+    default=True,
+    help="Whether or not the database is set to private",
+)
 @click.pass_obj
-def import_stub(b):
-    pass
+def create(b, name, is_private):
+    printj(b.create_database(name, is_private=is_private))
 
-@import_stub.command()
-@click.option("-i", "--job_id", required=True, help="The importer job id.")
-@click.pass_obj
-def status(b, job_id):
-    print_json_model(b.retrieve_ingestor_job(q_uuid=job_id))
 
-@import_stub.command()
-@click.option("-r", "--repo_name", required=True, help="The repo name.")
-@click.option("-t", "--table_name", required=True, help="The table name.")
-@click.option("--data", required=True, hidden=True, type=click.File('r'), default="-", help="The json data")
+@db.command()
+@click.option("-d", "--database", required=True, help="Name of the database to show")
 @click.pass_obj
-def json_data(b, repo_name, table_name, data):
-    with data:
-        json_str = data.read()
-        # this is a way to do local json validation
-        json_obj = json.loads(json_str)
-        import_json = bitdotio.model.import_json.ImportJson(json_str, table_name, repo_name)
-        ingestor_job_details = b.create_import_json(import_json=import_json)
-        print_json_model(ingestor_job_details)
-
-@import_stub.command()
-@click.option("-r", "--repo_name", required=True, help="The repo name.")
-@click.option("-t", "--table_name", required=False, help="The table name.")
-@click.option("-u", "--url", required=True, help="The url to import.")
+def info(b, database):
+    printj(b.get_database(database))
+
+
+@db.command()
+@click.option("-d", "--database", required=True, help="Name of the database to show")
+@click.option(
+    "-n", "--name", required=False, default=None, help="New name for the database"
+)
+@click.option(
+    "-p",
+    "--is_private",
+    required=False,
+    default=None,
+    help="Whether or not the database is set to private",
+)
 @click.pass_obj
-def url(b, repo_name, table_name, url):
-    if table_name:
-        import_url = bitdotio.model.import_url.ImportUrl(url, table_name, repo_name)
-    else:
-        path = urlparse(url).path
-        filename = posixpath.basename(path)
-        import_url = bitdotio.model.import_url.ImportUrl(url, filename, repo_name)
+def update(b, database, name, is_private):
+    printj(b.update_database(database, name=name, is_private=is_private))
 
-    ingestor_job_details = b.create_import_url(import_url=import_url)
-    print_json_model(ingestor_job_details)
 
-@import_stub.command()
-@click.option("-r", "--repo_name", required=True, help="The repo name.")
-@click.option("-t", "--table_name", required=False, help="The table name.")
-@click.option("-f", "--file_name", required=True,  type=click.File('r'), default="-", help="The file to import; defaults to stdin.")
+@db.command()
+@click.option("-d", "--database", required=True, help="Name of the database to show")
 @click.pass_obj
-def file(b, repo_name, table_name, file_name):
-
-    if file_name.name == "<stdin>":
-        if not table_name:
-            raise click.UsageError("--table_name is required when reading a file from stdin.")
-
-    if table_name:
-        ingestor_job_details = b.create_import_file(file_name, repo_name, table_name=table_name)
-    else:
-        ingestor_job_details = b.create_import_file(file_name, repo_name)
-    print_json_model(ingestor_job_details)
-
-def print_json_model(model):
-    print(json.dumps(model.to_dict(), indent = 4))
+def delete(b, database):
+    b.delete_database(database)
+    print(f"Successfully deleted database: {database}")
 
-def print_json_model_list(models):
-    print(json.dumps([x.to_dict() for x in models], indent = 4))
 
 def main():
     try:
         bitio(auto_envvar_prefix="BITIO")
     except click.UsageError as e:
         raise e
-        sys.exit(1)
-    except bitdotio.exceptions.NotFoundException:
-        print("Repo not found.")
-        sys.exit(2)
     except Exception as e:
         print(e)
         sys.exit(3)
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     main()
diff --git a/bitdotio/__init__.py b/bitdotio/__init__.py
index 08e0926..04e06ed 100644
--- a/bitdotio/__init__.py
+++ b/bitdotio/__init__.py
@@ -1,31 +1,3 @@
 # flake8: noqa
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-__version__ = "1.0.0"
-
-# import ApiClient
-from bitdotio.api_client import ApiClient
-
-# import Configuration
-from bitdotio.configuration import Configuration
-
-# import exceptions
-from bitdotio.exceptions import OpenApiException
-from bitdotio.exceptions import ApiAttributeError
-from bitdotio.exceptions import ApiTypeError
-from bitdotio.exceptions import ApiValueError
-from bitdotio.exceptions import ApiKeyError
-from bitdotio.exceptions import ApiException
-# import apis into sdk package
-from bitdotio.api.api_bitdotio import ApiBitdotio
-
-from bitdotio.bitdotio import bitdotio
+from bitdotio._bitdotio import bitdotio
+from bitdotio._version import __version__
diff --git a/bitdotio/_bitdotio.py b/bitdotio/_bitdotio.py
new file mode 100644
index 0000000..71ef798
--- /dev/null
+++ b/bitdotio/_bitdotio.py
@@ -0,0 +1,226 @@
+#!/usr/bin/env python3
+import functools
+import sys
+import typing as t
+from contextlib import contextmanager
+
+from requests import Response
+
+from bitdotio.api_client import ApiClient
+from bitdotio.utils import validate_database_name, validate_min_max_conn, validate_token
+
+API_VERSION = "v2beta"
+
+
+def bitdotio(
+    access_token: str,
+    api_version: str = API_VERSION,
+    min_conn: int = 0,
+    max_conn: int = 100,
+):
+    return _BitV2(access_token, api_version, min_conn, max_conn)
+
+
+class ApiError(Exception):
+    def __init__(self, status_code: int, data: t.Any) -> None:
+        self.status_code = status_code
+        self.data = data
+
+    def __str__(self) -> str:
+        return f"ApiError status_code={self.status_code} data={self.data}"
+
+
+def api_method(
+    returning: t.Optional[str] = None,
+) -> t.Callable[[t.Callable[..., Response]], t.Callable[..., t.Any]]:
+    def decorator(method: t.Callable[..., Response]) -> t.Callable[..., t.Any]:
+        @functools.wraps(method)
+        def wrapper(*args, **kwargs):
+            response = method(*args, **kwargs)
+            body = response.json()
+            if response.ok:
+                if returning:
+                    return body[returning]
+                return body
+
+            raise ApiError(response.status_code, body)
+
+        return wrapper
+
+    return decorator
+
+
+class _BitV2:
+
+    _port = 5432
+    _host = "db.bit.io"
+
+    def __init__(
+        self,
+        access_token: str,
+        api_version: str,
+        min_conn: int,
+        max_conn: int,
+    ) -> None:
+        validate_token(access_token)
+        validate_min_max_conn(min_conn, max_conn)
+
+        self._access_token = access_token
+        self._api_client = ApiClient(access_token, api_version)
+        self._min_conn = min_conn
+        self._max_conn = max_conn
+
+        self._pools = {}
+
+    def __repr__(self):
+        return "<bitdotio SDK object: v2>"
+
+    def _get_conn_string(self, db_name):
+        db = db_name
+        user = "api_user"
+        password = self._access_token
+        host = self._host
+        port = self._port
+        return f"dbname={db} user={user} password={password} host={host} port={port} sslmode=require"
+
+    @staticmethod
+    def _create_pool(pool_cls, *args, **kwargs):
+        """This is super weird code factorization but it's necessary in order to mock
+        out the connection pool in testing. We can't mock ThreadedConnectionPool
+        directly since it's not imported at the module level.
+        """
+        return pool_cls(*args, **kwargs)
+
+    def _get_pool(self, db_name: str):
+        pool = self._pools.get(db_name)
+        if pool is not None:
+            return pool
+
+        try:
+            # Threadsafe by default
+            from psycopg2.pool import ThreadedConnectionPool
+        except ImportError as exc:
+            _print_psycopg2_message()
+            raise exc
+
+        conn_string = self._get_conn_string(db_name)
+        pool = self._create_pool(
+            ThreadedConnectionPool,
+            self._min_conn,
+            self._max_conn,
+            conn_string,
+        )
+        self._pools[db_name] = pool
+        return pool
+
+    def get_connection(self, db_name):
+        try:
+            import psycopg2
+        except ImportError as e:
+            _print_psycopg2_message()
+            raise e
+
+        conn_str = self._get_conn_string(db_name)
+        conn = psycopg2.connect(conn_str)
+
+        return conn
+
+    @contextmanager
+    def pooled_connection(self, db_name: str):
+        pool, conn = None, None
+        try:
+            pool = self._get_pool(db_name)
+            conn = pool.getconn()
+            yield conn
+        finally:
+            if pool is not None and conn is not None:
+                pool.putconn(conn)
+
+    @contextmanager
+    def pooled_cursor(self, db_name: str):
+        with self.pooled_connection(db_name) as conn:
+            with conn.cursor() as cursor:
+                yield cursor
+
+    @api_method()
+    def query(self, db_name: str, query_str: str, data_format: t.Optional[str] = None):
+        url = f"/query"
+        if data_format is not None:
+            url += f"?data_format={data_format}"
+
+        request_body = {"database_name": db_name, "query_string": query_str}
+
+        return self._api_client.post(url, json=request_body)
+
+    @api_method(returning="databases")
+    def list_databases(self):
+        return self._api_client.get("/db/")
+
+    @api_method()
+    def create_database(
+        self,
+        name: str,
+        is_private: bool = True,
+        storage_limit_bytes: t.Optional[int] = None,
+    ):
+        request_body = {"name": name, "is_private": is_private}
+        if storage_limit_bytes:
+            request_body["storage_limit_bytes"] = storage_limit_bytes
+
+        return self._api_client.post("/db/", json=request_body)
+
+    @api_method()
+    def get_database(self, db_name: str):
+        validate_database_name(db_name)
+        return self._api_client.get(f"/db/{db_name}")
+
+    @api_method()
+    def update_database(
+        self,
+        db_name: str,
+        name: t.Optional[str] = None,
+        is_private: t.Optional[bool] = None,
+        storage_limit_bytes: t.Optional[int] = None,
+    ):
+        validate_database_name(db_name)
+        request_body = {
+            k: v
+            for k, v in {
+                "name": name,
+                "is_private": is_private,
+                "storage_limit_bytes": storage_limit_bytes,
+            }.items()
+            if v is not None
+        }
+
+        return self._api_client.patch(f"/db/{db_name}", json=request_body)
+
+    @api_method()
+    def delete_database(self, db_name: str):
+        validate_database_name(db_name)
+        return self._api_client.delete(f"/db/{db_name}")
+
+
+def _print_psycopg2_message():
+    print(
+        """
+It looks like we couldn't import the psycopg2 library!
+
+In order to support different environments, we have a few ways to install the bitdotio package
+with or without the psycopg2 dependency.
+
+1. If you already have psycopg2 install, you can install the default bitdotio package:
+
+  pip install bitdotio
+
+2. If you already have Postgres installed, you can install with the psycopg2 dependency:
+
+  pip install bitdotio[psycopg2]
+
+3. If you do not have or cannot install Postgres, you can install with the psycopg2-binary dependency:
+
+  pip install bitdotio[psycopg2-binary]
+
+""",
+        file=sys.stderr,
+    )
diff --git a/bitdotio/_version.py b/bitdotio/_version.py
new file mode 100644
index 0000000..8c0d5d5
--- /dev/null
+++ b/bitdotio/_version.py
@@ -0,0 +1,1 @@
+__version__ = "2.0.0"
diff --git a/bitdotio/api/__init__.py b/bitdotio/api/__init__.py
deleted file mode 100644
index 85b5fa3..0000000
--- a/bitdotio/api/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# do not import all apis into this module because that uses a lot of memory and stack frames
-# if you need the ability to import all apis from one package, import them with
-# from bitdotio.apis import ApiBitdotio
diff --git a/bitdotio/api/api_bitdotio.py b/bitdotio/api/api_bitdotio.py
deleted file mode 100644
index 523787f..0000000
--- a/bitdotio/api/api_bitdotio.py
+++ /dev/null
@@ -1,1362 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import re  # noqa: F401
-import sys  # noqa: F401
-
-from bitdotio.api_client import ApiClient, Endpoint as _Endpoint
-from bitdotio.model_utils import (  # noqa: F401
-    check_allowed_values,
-    check_validations,
-    date,
-    datetime,
-    file_type,
-    none_type,
-    validate_and_convert_types
-)
-from bitdotio.model.import_json import ImportJson
-from bitdotio.model.import_url import ImportUrl
-from bitdotio.model.ingestion_result import IngestionResult
-from bitdotio.model.ingestor_job import IngestorJob
-from bitdotio.model.query import Query
-from bitdotio.model.repo import Repo
-
-
-class ApiBitdotio(object):
-    """NOTE: This class is auto generated by OpenAPI Generator
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-    """
-
-    def __init__(self, api_client=None):
-        if api_client is None:
-            api_client = ApiClient()
-        self.api_client = api_client
-
-        def __create_import_file(
-            self,
-            file_to_import,
-            repo_name,
-            **kwargs
-        ):
-            """create_import_file  # noqa: E501
-
-            This method makes a synchronous HTTP request by default. To make an
-            asynchronous HTTP request, please pass async_req=True
-
-            >>> thread = api.create_import_file(file_to_import, repo_name, async_req=True)
-            >>> result = thread.get()
-
-            Args:
-                file_to_import (file_type):
-                repo_name (str):
-
-            Keyword Args:
-                table_name (str): [optional]
-                create_table_if_not_exists (bool): [optional] if omitted the server will use the default value of True
-                _return_http_data_only (bool): response data without head status
-                    code and headers. Default is True.
-                _preload_content (bool): if False, the urllib3.HTTPResponse object
-                    will be returned without reading/decoding response data.
-                    Default is True.
-                _request_timeout (float/tuple): timeout setting for this request. If one
-                    number provided, it will be total request timeout. It can also
-                    be a pair (tuple) of (connection, read) timeouts.
-                    Default is None.
-                _check_input_type (bool): specifies if type checking
-                    should be done one the data sent to the server.
-                    Default is True.
-                _check_return_type (bool): specifies if type checking
-                    should be done one the data received from the server.
-                    Default is True.
-                _host_index (int/None): specifies the index of the server
-                    that we want to use.
-                    Default is read from the configuration.
-                async_req (bool): execute request asynchronously
-
-            Returns:
-                IngestionResult
-                    If the method is called asynchronously, returns the request
-                    thread.
-            """
-            kwargs['async_req'] = kwargs.get(
-                'async_req', False
-            )
-            kwargs['_return_http_data_only'] = kwargs.get(
-                '_return_http_data_only', True
-            )
-            kwargs['_preload_content'] = kwargs.get(
-                '_preload_content', True
-            )
-            kwargs['_request_timeout'] = kwargs.get(
-                '_request_timeout', None
-            )
-            kwargs['_check_input_type'] = kwargs.get(
-                '_check_input_type', True
-            )
-            kwargs['_check_return_type'] = kwargs.get(
-                '_check_return_type', True
-            )
-            kwargs['_host_index'] = kwargs.get('_host_index')
-            kwargs['file_to_import'] = \
-                file_to_import
-            kwargs['repo_name'] = \
-                repo_name
-            return self.call_with_http_info(**kwargs)
-
-        self.create_import_file = _Endpoint(
-            settings={
-                'response_type': (IngestionResult,),
-                'auth': [
-                    'bearerAuth'
-                ],
-                'endpoint_path': '/import/file/',
-                'operation_id': 'create_import_file',
-                'http_method': 'POST',
-                'servers': None,
-            },
-            params_map={
-                'all': [
-                    'file_to_import',
-                    'repo_name',
-                    'table_name',
-                    'create_table_if_not_exists',
-                ],
-                'required': [
-                    'file_to_import',
-                    'repo_name',
-                ],
-                'nullable': [
-                ],
-                'enum': [
-                ],
-                'validation': [
-                ]
-            },
-            root_map={
-                'validations': {
-                },
-                'allowed_values': {
-                },
-                'openapi_types': {
-                    'file_to_import':
-                        (file_type,),
-                    'repo_name':
-                        (str,),
-                    'table_name':
-                        (str,),
-                    'create_table_if_not_exists':
-                        (bool,),
-                },
-                'attribute_map': {
-                    'file_to_import': 'file_to_import',
-                    'repo_name': 'repo_name',
-                    'table_name': 'table_name',
-                    'create_table_if_not_exists': 'create_table_if_not_exists',
-                },
-                'location_map': {
-                    'file_to_import': 'form',
-                    'repo_name': 'form',
-                    'table_name': 'form',
-                    'create_table_if_not_exists': 'form',
-                },
-                'collection_format_map': {
-                }
-            },
-            headers_map={
-                'accept': [
-                    'application/json'
-                ],
-                'content_type': [
-                    'multipart/form-data'
-                ]
-            },
-            api_client=api_client,
-            callable=__create_import_file
-        )
-
-        def __create_import_json(
-            self,
-            **kwargs
-        ):
-            """create_import_json  # noqa: E501
-
-            This method makes a synchronous HTTP request by default. To make an
-            asynchronous HTTP request, please pass async_req=True
-
-            >>> thread = api.create_import_json(async_req=True)
-            >>> result = thread.get()
-
-
-            Keyword Args:
-                import_json (ImportJson): [optional]
-                _return_http_data_only (bool): response data without head status
-                    code and headers. Default is True.
-                _preload_content (bool): if False, the urllib3.HTTPResponse object
-                    will be returned without reading/decoding response data.
-                    Default is True.
-                _request_timeout (float/tuple): timeout setting for this request. If one
-                    number provided, it will be total request timeout. It can also
-                    be a pair (tuple) of (connection, read) timeouts.
-                    Default is None.
-                _check_input_type (bool): specifies if type checking
-                    should be done one the data sent to the server.
-                    Default is True.
-                _check_return_type (bool): specifies if type checking
-                    should be done one the data received from the server.
-                    Default is True.
-                _host_index (int/None): specifies the index of the server
-                    that we want to use.
-                    Default is read from the configuration.
-                async_req (bool): execute request asynchronously
-
-            Returns:
-                IngestionResult
-                    If the method is called asynchronously, returns the request
-                    thread.
-            """
-            kwargs['async_req'] = kwargs.get(
-                'async_req', False
-            )
-            kwargs['_return_http_data_only'] = kwargs.get(
-                '_return_http_data_only', True
-            )
-            kwargs['_preload_content'] = kwargs.get(
-                '_preload_content', True
-            )
-            kwargs['_request_timeout'] = kwargs.get(
-                '_request_timeout', None
-            )
-            kwargs['_check_input_type'] = kwargs.get(
-                '_check_input_type', True
-            )
-            kwargs['_check_return_type'] = kwargs.get(
-                '_check_return_type', True
-            )
-            kwargs['_host_index'] = kwargs.get('_host_index')
-            return self.call_with_http_info(**kwargs)
-
-        self.create_import_json = _Endpoint(
-            settings={
-                'response_type': (IngestionResult,),
-                'auth': [
-                    'bearerAuth'
-                ],
-                'endpoint_path': '/import/json/',
-                'operation_id': 'create_import_json',
-                'http_method': 'POST',
-                'servers': None,
-            },
-            params_map={
-                'all': [
-                    'import_json',
-                ],
-                'required': [],
-                'nullable': [
-                ],
-                'enum': [
-                ],
-                'validation': [
-                ]
-            },
-            root_map={
-                'validations': {
-                },
-                'allowed_values': {
-                },
-                'openapi_types': {
-                    'import_json':
-                        (ImportJson,),
-                },
-                'attribute_map': {
-                },
-                'location_map': {
-                    'import_json': 'body',
-                },
-                'collection_format_map': {
-                }
-            },
-            headers_map={
-                'accept': [
-                    'application/json'
-                ],
-                'content_type': [
-                    'application/json',
-                    'application/x-www-form-urlencoded',
-                    'multipart/form-data'
-                ]
-            },
-            api_client=api_client,
-            callable=__create_import_json
-        )
-
-        def __create_import_url(
-            self,
-            **kwargs
-        ):
-            """create_import_url  # noqa: E501
-
-            This method makes a synchronous HTTP request by default. To make an
-            asynchronous HTTP request, please pass async_req=True
-
-            >>> thread = api.create_import_url(async_req=True)
-            >>> result = thread.get()
-
-
-            Keyword Args:
-                import_url (ImportUrl): [optional]
-                _return_http_data_only (bool): response data without head status
-                    code and headers. Default is True.
-                _preload_content (bool): if False, the urllib3.HTTPResponse object
-                    will be returned without reading/decoding response data.
-                    Default is True.
-                _request_timeout (float/tuple): timeout setting for this request. If one
-                    number provided, it will be total request timeout. It can also
-                    be a pair (tuple) of (connection, read) timeouts.
-                    Default is None.
-                _check_input_type (bool): specifies if type checking
-                    should be done one the data sent to the server.
-                    Default is True.
-                _check_return_type (bool): specifies if type checking
-                    should be done one the data received from the server.
-                    Default is True.
-                _host_index (int/None): specifies the index of the server
-                    that we want to use.
-                    Default is read from the configuration.
-                async_req (bool): execute request asynchronously
-
-            Returns:
-                IngestionResult
-                    If the method is called asynchronously, returns the request
-                    thread.
-            """
-            kwargs['async_req'] = kwargs.get(
-                'async_req', False
-            )
-            kwargs['_return_http_data_only'] = kwargs.get(
-                '_return_http_data_only', True
-            )
-            kwargs['_preload_content'] = kwargs.get(
-                '_preload_content', True
-            )
-            kwargs['_request_timeout'] = kwargs.get(
-                '_request_timeout', None
-            )
-            kwargs['_check_input_type'] = kwargs.get(
-                '_check_input_type', True
-            )
-            kwargs['_check_return_type'] = kwargs.get(
-                '_check_return_type', True
-            )
-            kwargs['_host_index'] = kwargs.get('_host_index')
-            return self.call_with_http_info(**kwargs)
-
-        self.create_import_url = _Endpoint(
-            settings={
-                'response_type': (IngestionResult,),
-                'auth': [
-                    'bearerAuth'
-                ],
-                'endpoint_path': '/import/url/',
-                'operation_id': 'create_import_url',
-                'http_method': 'POST',
-                'servers': None,
-            },
-            params_map={
-                'all': [
-                    'import_url',
-                ],
-                'required': [],
-                'nullable': [
-                ],
-                'enum': [
-                ],
-                'validation': [
-                ]
-            },
-            root_map={
-                'validations': {
-                },
-                'allowed_values': {
-                },
-                'openapi_types': {
-                    'import_url':
-                        (ImportUrl,),
-                },
-                'attribute_map': {
-                },
-                'location_map': {
-                    'import_url': 'body',
-                },
-                'collection_format_map': {
-                }
-            },
-            headers_map={
-                'accept': [
-                    'application/json'
-                ],
-                'content_type': [
-                    'application/json',
-                    'application/x-www-form-urlencoded',
-                    'multipart/form-data'
-                ]
-            },
-            api_client=api_client,
-            callable=__create_import_url
-        )
-
-        def __create_query(
-            self,
-            **kwargs
-        ):
-            """create_query  # noqa: E501
-
-            This method makes a synchronous HTTP request by default. To make an
-            asynchronous HTTP request, please pass async_req=True
-
-            >>> thread = api.create_query(async_req=True)
-            >>> result = thread.get()
-
-
-            Keyword Args:
-                query (Query): [optional]
-                _return_http_data_only (bool): response data without head status
-                    code and headers. Default is True.
-                _preload_content (bool): if False, the urllib3.HTTPResponse object
-                    will be returned without reading/decoding response data.
-                    Default is True.
-                _request_timeout (float/tuple): timeout setting for this request. If one
-                    number provided, it will be total request timeout. It can also
-                    be a pair (tuple) of (connection, read) timeouts.
-                    Default is None.
-                _check_input_type (bool): specifies if type checking
-                    should be done one the data sent to the server.
-                    Default is True.
-                _check_return_type (bool): specifies if type checking
-                    should be done one the data received from the server.
-                    Default is True.
-                _host_index (int/None): specifies the index of the server
-                    that we want to use.
-                    Default is read from the configuration.
-                async_req (bool): execute request asynchronously
-
-            Returns:
-                Query
-                    If the method is called asynchronously, returns the request
-                    thread.
-            """
-            kwargs['async_req'] = kwargs.get(
-                'async_req', False
-            )
-            kwargs['_return_http_data_only'] = kwargs.get(
-                '_return_http_data_only', True
-            )
-            kwargs['_preload_content'] = kwargs.get(
-                '_preload_content', True
-            )
-            kwargs['_request_timeout'] = kwargs.get(
-                '_request_timeout', None
-            )
-            kwargs['_check_input_type'] = kwargs.get(
-                '_check_input_type', True
-            )
-            kwargs['_check_return_type'] = kwargs.get(
-                '_check_return_type', True
-            )
-            kwargs['_host_index'] = kwargs.get('_host_index')
-            return self.call_with_http_info(**kwargs)
-
-        self.create_query = _Endpoint(
-            settings={
-                'response_type': (Query,),
-                'auth': [
-                    'bearerAuth'
-                ],
-                'endpoint_path': '/query/',
-                'operation_id': 'create_query',
-                'http_method': 'POST',
-                'servers': None,
-            },
-            params_map={
-                'all': [
-                    'query',
-                ],
-                'required': [],
-                'nullable': [
-                ],
-                'enum': [
-                ],
-                'validation': [
-                ]
-            },
-            root_map={
-                'validations': {
-                },
-                'allowed_values': {
-                },
-                'openapi_types': {
-                    'query':
-                        (Query,),
-                },
-                'attribute_map': {
-                },
-                'location_map': {
-                    'query': 'body',
-                },
-                'collection_format_map': {
-                }
-            },
-            headers_map={
-                'accept': [
-                    'application/json'
-                ],
-                'content_type': [
-                    'application/json',
-                    'application/x-www-form-urlencoded',
-                    'multipart/form-data'
-                ]
-            },
-            api_client=api_client,
-            callable=__create_query
-        )
-
-        def __create_repo(
-            self,
-            **kwargs
-        ):
-            """create_repo  # noqa: E501
-
-            Create a repository owned by the authenticated user. The request body must contain the required fields for the repository.  # noqa: E501
-            This method makes a synchronous HTTP request by default. To make an
-            asynchronous HTTP request, please pass async_req=True
-
-            >>> thread = api.create_repo(async_req=True)
-            >>> result = thread.get()
-
-
-            Keyword Args:
-                repo (Repo): [optional]
-                _return_http_data_only (bool): response data without head status
-                    code and headers. Default is True.
-                _preload_content (bool): if False, the urllib3.HTTPResponse object
-                    will be returned without reading/decoding response data.
-                    Default is True.
-                _request_timeout (float/tuple): timeout setting for this request. If one
-                    number provided, it will be total request timeout. It can also
-                    be a pair (tuple) of (connection, read) timeouts.
-                    Default is None.
-                _check_input_type (bool): specifies if type checking
-                    should be done one the data sent to the server.
-                    Default is True.
-                _check_return_type (bool): specifies if type checking
-                    should be done one the data received from the server.
-                    Default is True.
-                _host_index (int/None): specifies the index of the server
-                    that we want to use.
-                    Default is read from the configuration.
-                async_req (bool): execute request asynchronously
-
-            Returns:
-                Repo
-                    If the method is called asynchronously, returns the request
-                    thread.
-            """
-            kwargs['async_req'] = kwargs.get(
-                'async_req', False
-            )
-            kwargs['_return_http_data_only'] = kwargs.get(
-                '_return_http_data_only', True
-            )
-            kwargs['_preload_content'] = kwargs.get(
-                '_preload_content', True
-            )
-            kwargs['_request_timeout'] = kwargs.get(
-                '_request_timeout', None
-            )
-            kwargs['_check_input_type'] = kwargs.get(
-                '_check_input_type', True
-            )
-            kwargs['_check_return_type'] = kwargs.get(
-                '_check_return_type', True
-            )
-            kwargs['_host_index'] = kwargs.get('_host_index')
-            return self.call_with_http_info(**kwargs)
-
-        self.create_repo = _Endpoint(
-            settings={
-                'response_type': (Repo,),
-                'auth': [
-                    'bearerAuth'
-                ],
-                'endpoint_path': '/repos/',
-                'operation_id': 'create_repo',
-                'http_method': 'POST',
-                'servers': None,
-            },
-            params_map={
-                'all': [
-                    'repo',
-                ],
-                'required': [],
-                'nullable': [
-                ],
-                'enum': [
-                ],
-                'validation': [
-                ]
-            },
-            root_map={
-                'validations': {
-                },
-                'allowed_values': {
-                },
-                'openapi_types': {
-                    'repo':
-                        (Repo,),
-                },
-                'attribute_map': {
-                },
-                'location_map': {
-                    'repo': 'body',
-                },
-                'collection_format_map': {
-                }
-            },
-            headers_map={
-                'accept': [
-                    'application/json'
-                ],
-                'content_type': [
-                    'application/json',
-                    'application/x-www-form-urlencoded',
-                    'multipart/form-data'
-                ]
-            },
-            api_client=api_client,
-            callable=__create_repo
-        )
-
-        def __destroy_repo(
-            self,
-            name,
-            **kwargs
-        ):
-            """destroy_repo  # noqa: E501
-
-            Delete the given repo.  # noqa: E501
-            This method makes a synchronous HTTP request by default. To make an
-            asynchronous HTTP request, please pass async_req=True
-
-            >>> thread = api.destroy_repo(name, async_req=True)
-            >>> result = thread.get()
-
-            Args:
-                name (str):
-
-            Keyword Args:
-                _return_http_data_only (bool): response data without head status
-                    code and headers. Default is True.
-                _preload_content (bool): if False, the urllib3.HTTPResponse object
-                    will be returned without reading/decoding response data.
-                    Default is True.
-                _request_timeout (float/tuple): timeout setting for this request. If one
-                    number provided, it will be total request timeout. It can also
-                    be a pair (tuple) of (connection, read) timeouts.
-                    Default is None.
-                _check_input_type (bool): specifies if type checking
-                    should be done one the data sent to the server.
-                    Default is True.
-                _check_return_type (bool): specifies if type checking
-                    should be done one the data received from the server.
-                    Default is True.
-                _host_index (int/None): specifies the index of the server
-                    that we want to use.
-                    Default is read from the configuration.
-                async_req (bool): execute request asynchronously
-
-            Returns:
-                None
-                    If the method is called asynchronously, returns the request
-                    thread.
-            """
-            kwargs['async_req'] = kwargs.get(
-                'async_req', False
-            )
-            kwargs['_return_http_data_only'] = kwargs.get(
-                '_return_http_data_only', True
-            )
-            kwargs['_preload_content'] = kwargs.get(
-                '_preload_content', True
-            )
-            kwargs['_request_timeout'] = kwargs.get(
-                '_request_timeout', None
-            )
-            kwargs['_check_input_type'] = kwargs.get(
-                '_check_input_type', True
-            )
-            kwargs['_check_return_type'] = kwargs.get(
-                '_check_return_type', True
-            )
-            kwargs['_host_index'] = kwargs.get('_host_index')
-            kwargs['name'] = \
-                name
-            return self.call_with_http_info(**kwargs)
-
-        self.destroy_repo = _Endpoint(
-            settings={
-                'response_type': None,
-                'auth': [
-                    'bearerAuth'
-                ],
-                'endpoint_path': '/repos/{name}/',
-                'operation_id': 'destroy_repo',
-                'http_method': 'DELETE',
-                'servers': None,
-            },
-            params_map={
-                'all': [
-                    'name',
-                ],
-                'required': [
-                    'name',
-                ],
-                'nullable': [
-                ],
-                'enum': [
-                ],
-                'validation': [
-                ]
-            },
-            root_map={
-                'validations': {
-                },
-                'allowed_values': {
-                },
-                'openapi_types': {
-                    'name':
-                        (str,),
-                },
-                'attribute_map': {
-                    'name': 'name',
-                },
-                'location_map': {
-                    'name': 'path',
-                },
-                'collection_format_map': {
-                }
-            },
-            headers_map={
-                'accept': [],
-                'content_type': [],
-            },
-            api_client=api_client,
-            callable=__destroy_repo
-        )
-
-        def __list_repos(
-            self,
-            **kwargs
-        ):
-            """list_repos  # noqa: E501
-
-            Retrieve a list of the repositories that the currently logged-in user can access in some way.  # noqa: E501
-            This method makes a synchronous HTTP request by default. To make an
-            asynchronous HTTP request, please pass async_req=True
-
-            >>> thread = api.list_repos(async_req=True)
-            >>> result = thread.get()
-
-
-            Keyword Args:
-                _return_http_data_only (bool): response data without head status
-                    code and headers. Default is True.
-                _preload_content (bool): if False, the urllib3.HTTPResponse object
-                    will be returned without reading/decoding response data.
-                    Default is True.
-                _request_timeout (float/tuple): timeout setting for this request. If one
-                    number provided, it will be total request timeout. It can also
-                    be a pair (tuple) of (connection, read) timeouts.
-                    Default is None.
-                _check_input_type (bool): specifies if type checking
-                    should be done one the data sent to the server.
-                    Default is True.
-                _check_return_type (bool): specifies if type checking
-                    should be done one the data received from the server.
-                    Default is True.
-                _host_index (int/None): specifies the index of the server
-                    that we want to use.
-                    Default is read from the configuration.
-                async_req (bool): execute request asynchronously
-
-            Returns:
-                [Repo]
-                    If the method is called asynchronously, returns the request
-                    thread.
-            """
-            kwargs['async_req'] = kwargs.get(
-                'async_req', False
-            )
-            kwargs['_return_http_data_only'] = kwargs.get(
-                '_return_http_data_only', True
-            )
-            kwargs['_preload_content'] = kwargs.get(
-                '_preload_content', True
-            )
-            kwargs['_request_timeout'] = kwargs.get(
-                '_request_timeout', None
-            )
-            kwargs['_check_input_type'] = kwargs.get(
-                '_check_input_type', True
-            )
-            kwargs['_check_return_type'] = kwargs.get(
-                '_check_return_type', True
-            )
-            kwargs['_host_index'] = kwargs.get('_host_index')
-            return self.call_with_http_info(**kwargs)
-
-        self.list_repos = _Endpoint(
-            settings={
-                'response_type': ([Repo],),
-                'auth': [
-                    'bearerAuth'
-                ],
-                'endpoint_path': '/repos/',
-                'operation_id': 'list_repos',
-                'http_method': 'GET',
-                'servers': None,
-            },
-            params_map={
-                'all': [
-                ],
-                'required': [],
-                'nullable': [
-                ],
-                'enum': [
-                ],
-                'validation': [
-                ]
-            },
-            root_map={
-                'validations': {
-                },
-                'allowed_values': {
-                },
-                'openapi_types': {
-                },
-                'attribute_map': {
-                },
-                'location_map': {
-                },
-                'collection_format_map': {
-                }
-            },
-            headers_map={
-                'accept': [
-                    'application/json'
-                ],
-                'content_type': [],
-            },
-            api_client=api_client,
-            callable=__list_repos
-        )
-
-        def __partial_update_repo(
-            self,
-            name,
-            **kwargs
-        ):
-            """partial_update_repo  # noqa: E501
-
-            Given a repo name, update one or more field's value in the given repo.  # noqa: E501
-            This method makes a synchronous HTTP request by default. To make an
-            asynchronous HTTP request, please pass async_req=True
-
-            >>> thread = api.partial_update_repo(name, async_req=True)
-            >>> result = thread.get()
-
-            Args:
-                name (str):
-
-            Keyword Args:
-                repo (Repo): [optional]
-                _return_http_data_only (bool): response data without head status
-                    code and headers. Default is True.
-                _preload_content (bool): if False, the urllib3.HTTPResponse object
-                    will be returned without reading/decoding response data.
-                    Default is True.
-                _request_timeout (float/tuple): timeout setting for this request. If one
-                    number provided, it will be total request timeout. It can also
-                    be a pair (tuple) of (connection, read) timeouts.
-                    Default is None.
-                _check_input_type (bool): specifies if type checking
-                    should be done one the data sent to the server.
-                    Default is True.
-                _check_return_type (bool): specifies if type checking
-                    should be done one the data received from the server.
-                    Default is True.
-                _host_index (int/None): specifies the index of the server
-                    that we want to use.
-                    Default is read from the configuration.
-                async_req (bool): execute request asynchronously
-
-            Returns:
-                Repo
-                    If the method is called asynchronously, returns the request
-                    thread.
-            """
-            kwargs['async_req'] = kwargs.get(
-                'async_req', False
-            )
-            kwargs['_return_http_data_only'] = kwargs.get(
-                '_return_http_data_only', True
-            )
-            kwargs['_preload_content'] = kwargs.get(
-                '_preload_content', True
-            )
-            kwargs['_request_timeout'] = kwargs.get(
-                '_request_timeout', None
-            )
-            kwargs['_check_input_type'] = kwargs.get(
-                '_check_input_type', True
-            )
-            kwargs['_check_return_type'] = kwargs.get(
-                '_check_return_type', True
-            )
-            kwargs['_host_index'] = kwargs.get('_host_index')
-            kwargs['name'] = \
-                name
-            return self.call_with_http_info(**kwargs)
-
-        self.partial_update_repo = _Endpoint(
-            settings={
-                'response_type': (Repo,),
-                'auth': [
-                    'bearerAuth'
-                ],
-                'endpoint_path': '/repos/{name}/',
-                'operation_id': 'partial_update_repo',
-                'http_method': 'PATCH',
-                'servers': None,
-            },
-            params_map={
-                'all': [
-                    'name',
-                    'repo',
-                ],
-                'required': [
-                    'name',
-                ],
-                'nullable': [
-                ],
-                'enum': [
-                ],
-                'validation': [
-                ]
-            },
-            root_map={
-                'validations': {
-                },
-                'allowed_values': {
-                },
-                'openapi_types': {
-                    'name':
-                        (str,),
-                    'repo':
-                        (Repo,),
-                },
-                'attribute_map': {
-                    'name': 'name',
-                },
-                'location_map': {
-                    'name': 'path',
-                    'repo': 'body',
-                },
-                'collection_format_map': {
-                }
-            },
-            headers_map={
-                'accept': [
-                    'application/json'
-                ],
-                'content_type': [
-                    'application/json',
-                    'application/x-www-form-urlencoded',
-                    'multipart/form-data'
-                ]
-            },
-            api_client=api_client,
-            callable=__partial_update_repo
-        )
-
-        def __retrieve_ingestor_job(
-            self,
-            q_uuid,
-            **kwargs
-        ):
-            """retrieve_ingestor_job  # noqa: E501
-
-            This method makes a synchronous HTTP request by default. To make an
-            asynchronous HTTP request, please pass async_req=True
-
-            >>> thread = api.retrieve_ingestor_job(q_uuid, async_req=True)
-            >>> result = thread.get()
-
-            Args:
-                q_uuid (str):
-
-            Keyword Args:
-                _return_http_data_only (bool): response data without head status
-                    code and headers. Default is True.
-                _preload_content (bool): if False, the urllib3.HTTPResponse object
-                    will be returned without reading/decoding response data.
-                    Default is True.
-                _request_timeout (float/tuple): timeout setting for this request. If one
-                    number provided, it will be total request timeout. It can also
-                    be a pair (tuple) of (connection, read) timeouts.
-                    Default is None.
-                _check_input_type (bool): specifies if type checking
-                    should be done one the data sent to the server.
-                    Default is True.
-                _check_return_type (bool): specifies if type checking
-                    should be done one the data received from the server.
-                    Default is True.
-                _host_index (int/None): specifies the index of the server
-                    that we want to use.
-                    Default is read from the configuration.
-                async_req (bool): execute request asynchronously
-
-            Returns:
-                IngestorJob
-                    If the method is called asynchronously, returns the request
-                    thread.
-            """
-            kwargs['async_req'] = kwargs.get(
-                'async_req', False
-            )
-            kwargs['_return_http_data_only'] = kwargs.get(
-                '_return_http_data_only', True
-            )
-            kwargs['_preload_content'] = kwargs.get(
-                '_preload_content', True
-            )
-            kwargs['_request_timeout'] = kwargs.get(
-                '_request_timeout', None
-            )
-            kwargs['_check_input_type'] = kwargs.get(
-                '_check_input_type', True
-            )
-            kwargs['_check_return_type'] = kwargs.get(
-                '_check_return_type', True
-            )
-            kwargs['_host_index'] = kwargs.get('_host_index')
-            kwargs['q_uuid'] = \
-                q_uuid
-            return self.call_with_http_info(**kwargs)
-
-        self.retrieve_ingestor_job = _Endpoint(
-            settings={
-                'response_type': (IngestorJob,),
-                'auth': [
-                    'bearerAuth'
-                ],
-                'endpoint_path': '/import/status/{q_uuid}/',
-                'operation_id': 'retrieve_ingestor_job',
-                'http_method': 'GET',
-                'servers': None,
-            },
-            params_map={
-                'all': [
-                    'q_uuid',
-                ],
-                'required': [
-                    'q_uuid',
-                ],
-                'nullable': [
-                ],
-                'enum': [
-                ],
-                'validation': [
-                ]
-            },
-            root_map={
-                'validations': {
-                },
-                'allowed_values': {
-                },
-                'openapi_types': {
-                    'q_uuid':
-                        (str,),
-                },
-                'attribute_map': {
-                    'q_uuid': 'q_uuid',
-                },
-                'location_map': {
-                    'q_uuid': 'path',
-                },
-                'collection_format_map': {
-                }
-            },
-            headers_map={
-                'accept': [
-                    'application/json'
-                ],
-                'content_type': [],
-            },
-            api_client=api_client,
-            callable=__retrieve_ingestor_job
-        )
-
-        def __retrieve_repo(
-            self,
-            name,
-            **kwargs
-        ):
-            """retrieve_repo  # noqa: E501
-
-            Given a repo name, get the given repo's fields and values of those fields.  # noqa: E501
-            This method makes a synchronous HTTP request by default. To make an
-            asynchronous HTTP request, please pass async_req=True
-
-            >>> thread = api.retrieve_repo(name, async_req=True)
-            >>> result = thread.get()
-
-            Args:
-                name (str):
-
-            Keyword Args:
-                _return_http_data_only (bool): response data without head status
-                    code and headers. Default is True.
-                _preload_content (bool): if False, the urllib3.HTTPResponse object
-                    will be returned without reading/decoding response data.
-                    Default is True.
-                _request_timeout (float/tuple): timeout setting for this request. If one
-                    number provided, it will be total request timeout. It can also
-                    be a pair (tuple) of (connection, read) timeouts.
-                    Default is None.
-                _check_input_type (bool): specifies if type checking
-                    should be done one the data sent to the server.
-                    Default is True.
-                _check_return_type (bool): specifies if type checking
-                    should be done one the data received from the server.
-                    Default is True.
-                _host_index (int/None): specifies the index of the server
-                    that we want to use.
-                    Default is read from the configuration.
-                async_req (bool): execute request asynchronously
-
-            Returns:
-                Repo
-                    If the method is called asynchronously, returns the request
-                    thread.
-            """
-            kwargs['async_req'] = kwargs.get(
-                'async_req', False
-            )
-            kwargs['_return_http_data_only'] = kwargs.get(
-                '_return_http_data_only', True
-            )
-            kwargs['_preload_content'] = kwargs.get(
-                '_preload_content', True
-            )
-            kwargs['_request_timeout'] = kwargs.get(
-                '_request_timeout', None
-            )
-            kwargs['_check_input_type'] = kwargs.get(
-                '_check_input_type', True
-            )
-            kwargs['_check_return_type'] = kwargs.get(
-                '_check_return_type', True
-            )
-            kwargs['_host_index'] = kwargs.get('_host_index')
-            kwargs['name'] = \
-                name
-            return self.call_with_http_info(**kwargs)
-
-        self.retrieve_repo = _Endpoint(
-            settings={
-                'response_type': (Repo,),
-                'auth': [
-                    'bearerAuth'
-                ],
-                'endpoint_path': '/repos/{name}/',
-                'operation_id': 'retrieve_repo',
-                'http_method': 'GET',
-                'servers': None,
-            },
-            params_map={
-                'all': [
-                    'name',
-                ],
-                'required': [
-                    'name',
-                ],
-                'nullable': [
-                ],
-                'enum': [
-                ],
-                'validation': [
-                ]
-            },
-            root_map={
-                'validations': {
-                },
-                'allowed_values': {
-                },
-                'openapi_types': {
-                    'name':
-                        (str,),
-                },
-                'attribute_map': {
-                    'name': 'name',
-                },
-                'location_map': {
-                    'name': 'path',
-                },
-                'collection_format_map': {
-                }
-            },
-            headers_map={
-                'accept': [
-                    'application/json'
-                ],
-                'content_type': [],
-            },
-            api_client=api_client,
-            callable=__retrieve_repo
-        )
-
-        def __update_repo(
-            self,
-            name,
-            **kwargs
-        ):
-            """update_repo  # noqa: E501
-
-            Given a repo name, update the values of all fields in the given repo.  # noqa: E501
-            This method makes a synchronous HTTP request by default. To make an
-            asynchronous HTTP request, please pass async_req=True
-
-            >>> thread = api.update_repo(name, async_req=True)
-            >>> result = thread.get()
-
-            Args:
-                name (str):
-
-            Keyword Args:
-                repo (Repo): [optional]
-                _return_http_data_only (bool): response data without head status
-                    code and headers. Default is True.
-                _preload_content (bool): if False, the urllib3.HTTPResponse object
-                    will be returned without reading/decoding response data.
-                    Default is True.
-                _request_timeout (float/tuple): timeout setting for this request. If one
-                    number provided, it will be total request timeout. It can also
-                    be a pair (tuple) of (connection, read) timeouts.
-                    Default is None.
-                _check_input_type (bool): specifies if type checking
-                    should be done one the data sent to the server.
-                    Default is True.
-                _check_return_type (bool): specifies if type checking
-                    should be done one the data received from the server.
-                    Default is True.
-                _host_index (int/None): specifies the index of the server
-                    that we want to use.
-                    Default is read from the configuration.
-                async_req (bool): execute request asynchronously
-
-            Returns:
-                Repo
-                    If the method is called asynchronously, returns the request
-                    thread.
-            """
-            kwargs['async_req'] = kwargs.get(
-                'async_req', False
-            )
-            kwargs['_return_http_data_only'] = kwargs.get(
-                '_return_http_data_only', True
-            )
-            kwargs['_preload_content'] = kwargs.get(
-                '_preload_content', True
-            )
-            kwargs['_request_timeout'] = kwargs.get(
-                '_request_timeout', None
-            )
-            kwargs['_check_input_type'] = kwargs.get(
-                '_check_input_type', True
-            )
-            kwargs['_check_return_type'] = kwargs.get(
-                '_check_return_type', True
-            )
-            kwargs['_host_index'] = kwargs.get('_host_index')
-            kwargs['name'] = \
-                name
-            return self.call_with_http_info(**kwargs)
-
-        self.update_repo = _Endpoint(
-            settings={
-                'response_type': (Repo,),
-                'auth': [
-                    'bearerAuth'
-                ],
-                'endpoint_path': '/repos/{name}/',
-                'operation_id': 'update_repo',
-                'http_method': 'PUT',
-                'servers': None,
-            },
-            params_map={
-                'all': [
-                    'name',
-                    'repo',
-                ],
-                'required': [
-                    'name',
-                ],
-                'nullable': [
-                ],
-                'enum': [
-                ],
-                'validation': [
-                ]
-            },
-            root_map={
-                'validations': {
-                },
-                'allowed_values': {
-                },
-                'openapi_types': {
-                    'name':
-                        (str,),
-                    'repo':
-                        (Repo,),
-                },
-                'attribute_map': {
-                    'name': 'name',
-                },
-                'location_map': {
-                    'name': 'path',
-                    'repo': 'body',
-                },
-                'collection_format_map': {
-                }
-            },
-            headers_map={
-                'accept': [
-                    'application/json'
-                ],
-                'content_type': [
-                    'application/json',
-                    'application/x-www-form-urlencoded',
-                    'multipart/form-data'
-                ]
-            },
-            api_client=api_client,
-            callable=__update_repo
-        )
diff --git a/bitdotio/api_client.py b/bitdotio/api_client.py
index 15b89fd..a5cf39a 100644
--- a/bitdotio/api_client.py
+++ b/bitdotio/api_client.py
@@ -1,849 +1,46 @@
-"""
-    bit.io REST API
+import typing as t
+from urllib.parse import urljoin
 
-    bit.io API  # noqa: E501
+from requests import Response, Session
 
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
+from bitdotio._version import __version__
 
 
-import json
-import atexit
-import mimetypes
-from multiprocessing.pool import ThreadPool
-import io
-import os
-import re
-import typing
-from urllib.parse import quote
-from urllib3.fields import RequestField
+class ApiClient:
 
+    __slots__ = ("_access_token", "_api_version", "_session")
 
-from bitdotio import rest
-from bitdotio.configuration import Configuration
-from bitdotio.exceptions import ApiTypeError, ApiValueError, ApiException
-from bitdotio.model_utils import (
-    ModelNormal,
-    ModelSimple,
-    ModelComposed,
-    check_allowed_values,
-    check_validations,
-    date,
-    datetime,
-    deserialize_file,
-    file_type,
-    model_to_dict,
-    none_type,
-    validate_and_convert_types
-)
+    def __init__(self, access_token: str, api_version: str) -> None:
+        self._access_token = access_token
+        self._api_version = api_version
 
-
-class ApiClient(object):
-    """Generic API client for OpenAPI client library builds.
-
-    OpenAPI generic API client. This client handles the client-
-    server communication, and is invariant across implementations. Specifics of
-    the methods and models for each application are generated from the OpenAPI
-    templates.
-
-    NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-    Do not edit the class manually.
-
-    :param configuration: .Configuration object for this client
-    :param header_name: a header to pass when making calls to the API.
-    :param header_value: a header value to pass when making calls to
-        the API.
-    :param cookie: a cookie to include in the header when making calls
-        to the API
-    :param pool_threads: The number of threads to use for async requests
-        to the API. More threads means more concurrent API requests.
-    """
-
-    _pool = None
-
-    def __init__(self, configuration=None, header_name=None, header_value=None,
-                 cookie=None, pool_threads=1):
-        if configuration is None:
-            configuration = Configuration.get_default_copy()
-        self.configuration = configuration
-        self.pool_threads = pool_threads
-
-        self.rest_client = rest.RESTClientObject(configuration)
-        self.default_headers = {}
-        if header_name is not None:
-            self.default_headers[header_name] = header_value
-        self.cookie = cookie
-        # Set default User-Agent.
-        self.user_agent = 'OpenAPI-Generator/1.0.0/python'
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, exc_type, exc_value, traceback):
-        self.close()
-
-    def close(self):
-        if self._pool:
-            self._pool.close()
-            self._pool.join()
-            self._pool = None
-            if hasattr(atexit, 'unregister'):
-                atexit.unregister(self.close)
-
-    @property
-    def pool(self):
-        """Create thread pool on first request
-         avoids instantiating unused threadpool for blocking clients.
-        """
-        if self._pool is None:
-            atexit.register(self.close)
-            self._pool = ThreadPool(self.pool_threads)
-        return self._pool
-
-    @property
-    def user_agent(self):
-        """User agent for this API client"""
-        return self.default_headers['User-Agent']
-
-    @user_agent.setter
-    def user_agent(self, value):
-        self.default_headers['User-Agent'] = value
-
-    def set_default_header(self, header_name, header_value):
-        self.default_headers[header_name] = header_value
-
-    def __call_api(
-        self,
-        resource_path: str,
-        method: str,
-        path_params: typing.Optional[typing.Dict[str, typing.Any]] = None,
-        query_params: typing.Optional[typing.List[typing.Tuple[str, typing.Any]]] = None,
-        header_params: typing.Optional[typing.Dict[str, typing.Any]] = None,
-        body: typing.Optional[typing.Any] = None,
-        post_params: typing.Optional[typing.List[typing.Tuple[str, typing.Any]]] = None,
-        files: typing.Optional[typing.Dict[str, typing.List[io.IOBase]]] = None,
-        response_type: typing.Optional[typing.Tuple[typing.Any]] = None,
-        auth_settings: typing.Optional[typing.List[str]] = None,
-        _return_http_data_only: typing.Optional[bool] = None,
-        collection_formats: typing.Optional[typing.Dict[str, str]] = None,
-        _preload_content: bool = True,
-        _request_timeout: typing.Optional[typing.Union[int, typing.Tuple]] = None,
-        _host: typing.Optional[str] = None,
-        _check_type: typing.Optional[bool] = None
-    ):
-
-        config = self.configuration
-
-        # header parameters
-        header_params = header_params or {}
-        header_params.update(self.default_headers)
-        if self.cookie:
-            header_params['Cookie'] = self.cookie
-        if header_params:
-            header_params = self.sanitize_for_serialization(header_params)
-            header_params = dict(self.parameters_to_tuples(header_params,
-                                                           collection_formats))
-
-        # path parameters
-        if path_params:
-            path_params = self.sanitize_for_serialization(path_params)
-            path_params = self.parameters_to_tuples(path_params,
-                                                    collection_formats)
-            for k, v in path_params:
-                # specified safe chars, encode everything
-                resource_path = resource_path.replace(
-                    '{%s}' % k,
-                    quote(str(v), safe=config.safe_chars_for_path_param)
-                )
-
-        # query parameters
-        if query_params:
-            query_params = self.sanitize_for_serialization(query_params)
-            query_params = self.parameters_to_tuples(query_params,
-                                                     collection_formats)
-
-        # post parameters
-        if post_params or files:
-            post_params = post_params if post_params else []
-            post_params = self.sanitize_for_serialization(post_params)
-            post_params = self.parameters_to_tuples(post_params,
-                                                    collection_formats)
-            post_params.extend(self.files_parameters(files))
-            if header_params['Content-Type'].startswith("multipart"):
-                post_params = self.parameters_to_multipart(post_params,
-                                                          (dict) )
-
-        # body
-        if body:
-            body = self.sanitize_for_serialization(body)
-
-        # auth setting
-        self.update_params_for_auth(header_params, query_params,
-                                    auth_settings, resource_path, method, body)
-
-        # request url
-        if _host is None:
-            url = self.configuration.host + resource_path
-        else:
-            # use server/host defined in path or operation instead
-            url = _host + resource_path
-
-        try:
-            # perform request and return response
-            response_data = self.request(
-                method, url, query_params=query_params, headers=header_params,
-                post_params=post_params, body=body,
-                _preload_content=_preload_content,
-                _request_timeout=_request_timeout)
-        except ApiException as e:
-            e.body = e.body.decode('utf-8')
-            raise e
-
-        self.last_response = response_data
-
-        return_data = response_data
-
-        if not _preload_content:
-            return (return_data)
-            return return_data
-
-        # deserialize response data
-        if response_type:
-            if response_type != (file_type,):
-                encoding = "utf-8"
-                content_type = response_data.getheader('content-type')
-                if content_type is not None:
-                    match = re.search(r"charset=([a-zA-Z\-\d]+)[\s\;]?", content_type)
-                    if match:
-                        encoding = match.group(1)
-                response_data.data = response_data.data.decode(encoding)
-
-            return_data = self.deserialize(
-                response_data,
-                response_type,
-                _check_type
-            )
-        else:
-            return_data = None
-
-        if _return_http_data_only:
-            return (return_data)
-        else:
-            return (return_data, response_data.status,
-                    response_data.getheaders())
-
-    def parameters_to_multipart(self, params, collection_types):
-        """Get parameters as list of tuples, formatting as json if value is collection_types
-
-        :param params: Parameters as list of two-tuples
-        :param dict collection_types: Parameter collection types
-        :return: Parameters as list of tuple or urllib3.fields.RequestField
-        """
-        new_params = []
-        if collection_types is None:
-            collection_types = (dict)
-        for k, v in params.items() if isinstance(params, dict) else params:  # noqa: E501
-            if isinstance(v, collection_types): # v is instance of collection_type, formatting as application/json
-                 v = json.dumps(v, ensure_ascii=False).encode("utf-8")
-                 field = RequestField(k, v)
-                 field.make_multipart(content_type="application/json; charset=utf-8")
-                 new_params.append(field)
-            else:
-                 new_params.append((k, v))
-        return new_params
-
-    @classmethod
-    def sanitize_for_serialization(cls, obj):
-        """Prepares data for transmission before it is sent with the rest client
-        If obj is None, return None.
-        If obj is str, int, long, float, bool, return directly.
-        If obj is datetime.datetime, datetime.date
-            convert to string in iso8601 format.
-        If obj is list, sanitize each element in the list.
-        If obj is dict, return the dict.
-        If obj is OpenAPI model, return the properties dict.
-        If obj is io.IOBase, return the bytes
-        :param obj: The data to serialize.
-        :return: The serialized form of data.
-        """
-        if isinstance(obj, (ModelNormal, ModelComposed)):
-            return {
-                key: cls.sanitize_for_serialization(val) for key, val in model_to_dict(obj, serialize=True).items()
+        self._session = Session()
+        self._session.headers.update(
+            {
+                "Accept": "application/json",
+                "Content-Type": "application/json",
+                "Authorization": f"Bearer {self._access_token}",
+                "User-Agent": f"python-bitdotio-sdk/{__version__}"
             }
-        elif isinstance(obj, io.IOBase):
-            return cls.get_file_data_and_close_file(obj)
-        elif isinstance(obj, (str, int, float, none_type, bool)):
-            return obj
-        elif isinstance(obj, (datetime, date)):
-            return obj.isoformat()
-        elif isinstance(obj, ModelSimple):
-            return cls.sanitize_for_serialization(obj.value)
-        elif isinstance(obj, (list, tuple)):
-            return [cls.sanitize_for_serialization(item) for item in obj]
-        if isinstance(obj, dict):
-            return {key: cls.sanitize_for_serialization(val) for key, val in obj.items()}
-        raise ApiValueError('Unable to prepare type {} for serialization'.format(obj.__class__.__name__))
-
-    def deserialize(self, response, response_type, _check_type):
-        """Deserializes response into an object.
-
-        :param response: RESTResponse object to be deserialized.
-        :param response_type: For the response, a tuple containing:
-            valid classes
-            a list containing valid classes (for list schemas)
-            a dict containing a tuple of valid classes as the value
-            Example values:
-            (str,)
-            (Pet,)
-            (float, none_type)
-            ([int, none_type],)
-            ({str: (bool, str, int, float, date, datetime, str, none_type)},)
-        :param _check_type: boolean, whether to check the types of the data
-            received from the server
-        :type _check_type: bool
-
-        :return: deserialized object.
-        """
-        # handle file downloading
-        # save response body into a tmp file and return the instance
-        if response_type == (file_type,):
-            content_disposition = response.getheader("Content-Disposition")
-            return deserialize_file(response.data, self.configuration,
-                                    content_disposition=content_disposition)
-
-        # fetch data from response object
-        try:
-            received_data = json.loads(response.data)
-        except ValueError:
-            received_data = response.data
-
-        # store our data under the key of 'received_data' so users have some
-        # context if they are deserializing a string and the data type is wrong
-        deserialized_data = validate_and_convert_types(
-            received_data,
-            response_type,
-            ['received_data'],
-            True,
-            _check_type,
-            configuration=self.configuration
         )
-        return deserialized_data
-
-    def call_api(
-        self,
-        resource_path: str,
-        method: str,
-        path_params: typing.Optional[typing.Dict[str, typing.Any]] = None,
-        query_params: typing.Optional[typing.List[typing.Tuple[str, typing.Any]]] = None,
-        header_params: typing.Optional[typing.Dict[str, typing.Any]] = None,
-        body: typing.Optional[typing.Any] = None,
-        post_params: typing.Optional[typing.List[typing.Tuple[str, typing.Any]]] = None,
-        files: typing.Optional[typing.Dict[str, typing.List[io.IOBase]]] = None,
-        response_type: typing.Optional[typing.Tuple[typing.Any]] = None,
-        auth_settings: typing.Optional[typing.List[str]] = None,
-        async_req: typing.Optional[bool] = None,
-        _return_http_data_only: typing.Optional[bool] = None,
-        collection_formats: typing.Optional[typing.Dict[str, str]] = None,
-        _preload_content: bool = True,
-        _request_timeout: typing.Optional[typing.Union[int, typing.Tuple]] = None,
-        _host: typing.Optional[str] = None,
-        _check_type: typing.Optional[bool] = None
-    ):
-        """Makes the HTTP request (synchronous) and returns deserialized data.
-
-        To make an async_req request, set the async_req parameter.
-
-        :param resource_path: Path to method endpoint.
-        :param method: Method to call.
-        :param path_params: Path parameters in the url.
-        :param query_params: Query parameters in the url.
-        :param header_params: Header parameters to be
-            placed in the request header.
-        :param body: Request body.
-        :param post_params dict: Request post form parameters,
-            for `application/x-www-form-urlencoded`, `multipart/form-data`.
-        :param auth_settings list: Auth Settings names for the request.
-        :param response_type: For the response, a tuple containing:
-            valid classes
-            a list containing valid classes (for list schemas)
-            a dict containing a tuple of valid classes as the value
-            Example values:
-            (str,)
-            (Pet,)
-            (float, none_type)
-            ([int, none_type],)
-            ({str: (bool, str, int, float, date, datetime, str, none_type)},)
-        :param files: key -> field name, value -> a list of open file
-            objects for `multipart/form-data`.
-        :type files: dict
-        :param async_req bool: execute request asynchronously
-        :type async_req: bool, optional
-        :param _return_http_data_only: response data without head status code
-                                       and headers
-        :type _return_http_data_only: bool, optional
-        :param collection_formats: dict of collection formats for path, query,
-            header, and post parameters.
-        :type collection_formats: dict, optional
-        :param _preload_content: if False, the urllib3.HTTPResponse object will
-                                 be returned without reading/decoding response
-                                 data. Default is True.
-        :type _preload_content: bool, optional
-        :param _request_timeout: timeout setting for this request. If one
-                                 number provided, it will be total request
-                                 timeout. It can also be a pair (tuple) of
-                                 (connection, read) timeouts.
-        :param _check_type: boolean describing if the data back from the server
-            should have its type checked.
-        :type _check_type: bool, optional
-        :return:
-            If async_req parameter is True,
-            the request will be called asynchronously.
-            The method will return the request thread.
-            If parameter async_req is False or missing,
-            then the method will return the response directly.
-        """
-        if not async_req:
-            return self.__call_api(resource_path, method,
-                                   path_params, query_params, header_params,
-                                   body, post_params, files,
-                                   response_type, auth_settings,
-                                   _return_http_data_only, collection_formats,
-                                   _preload_content, _request_timeout, _host,
-                                   _check_type)
-
-        return self.pool.apply_async(self.__call_api, (resource_path,
-                                                       method, path_params,
-                                                       query_params,
-                                                       header_params, body,
-                                                       post_params, files,
-                                                       response_type,
-                                                       auth_settings,
-                                                       _return_http_data_only,
-                                                       collection_formats,
-                                                       _preload_content,
-                                                       _request_timeout,
-                                                       _host, _check_type))
-
-    def request(self, method, url, query_params=None, headers=None,
-                post_params=None, body=None, _preload_content=True,
-                _request_timeout=None):
-        """Makes the HTTP request using RESTClient."""
-        if method == "GET":
-            return self.rest_client.GET(url,
-                                        query_params=query_params,
-                                        _preload_content=_preload_content,
-                                        _request_timeout=_request_timeout,
-                                        headers=headers)
-        elif method == "HEAD":
-            return self.rest_client.HEAD(url,
-                                         query_params=query_params,
-                                         _preload_content=_preload_content,
-                                         _request_timeout=_request_timeout,
-                                         headers=headers)
-        elif method == "OPTIONS":
-            return self.rest_client.OPTIONS(url,
-                                            query_params=query_params,
-                                            headers=headers,
-                                            post_params=post_params,
-                                            _preload_content=_preload_content,
-                                            _request_timeout=_request_timeout,
-                                            body=body)
-        elif method == "POST":
-            return self.rest_client.POST(url,
-                                         query_params=query_params,
-                                         headers=headers,
-                                         post_params=post_params,
-                                         _preload_content=_preload_content,
-                                         _request_timeout=_request_timeout,
-                                         body=body)
-        elif method == "PUT":
-            return self.rest_client.PUT(url,
-                                        query_params=query_params,
-                                        headers=headers,
-                                        post_params=post_params,
-                                        _preload_content=_preload_content,
-                                        _request_timeout=_request_timeout,
-                                        body=body)
-        elif method == "PATCH":
-            return self.rest_client.PATCH(url,
-                                          query_params=query_params,
-                                          headers=headers,
-                                          post_params=post_params,
-                                          _preload_content=_preload_content,
-                                          _request_timeout=_request_timeout,
-                                          body=body)
-        elif method == "DELETE":
-            return self.rest_client.DELETE(url,
-                                           query_params=query_params,
-                                           headers=headers,
-                                           _preload_content=_preload_content,
-                                           _request_timeout=_request_timeout,
-                                           body=body)
-        else:
-            raise ApiValueError(
-                "http method must be `GET`, `HEAD`, `OPTIONS`,"
-                " `POST`, `PATCH`, `PUT` or `DELETE`."
-            )
-
-    def parameters_to_tuples(self, params, collection_formats):
-        """Get parameters as list of tuples, formatting collections.
-
-        :param params: Parameters as dict or list of two-tuples
-        :param dict collection_formats: Parameter collection formats
-        :return: Parameters as list of tuples, collections formatted
-        """
-        new_params = []
-        if collection_formats is None:
-            collection_formats = {}
-        for k, v in params.items() if isinstance(params, dict) else params:  # noqa: E501
-            if k in collection_formats:
-                collection_format = collection_formats[k]
-                if collection_format == 'multi':
-                    new_params.extend((k, value) for value in v)
-                else:
-                    if collection_format == 'ssv':
-                        delimiter = ' '
-                    elif collection_format == 'tsv':
-                        delimiter = '\t'
-                    elif collection_format == 'pipes':
-                        delimiter = '|'
-                    else:  # csv is the default
-                        delimiter = ','
-                    new_params.append(
-                        (k, delimiter.join(str(value) for value in v)))
-            else:
-                new_params.append((k, v))
-        return new_params
-
-    @staticmethod
-    def get_file_data_and_close_file(file_instance: io.IOBase) -> bytes:
-        file_data = file_instance.read()
-        file_instance.close()
-        return file_data
-
-    def files_parameters(self, files: typing.Optional[typing.Dict[str, typing.List[io.IOBase]]] = None):
-        """Builds form parameters.
-
-        :param files: None or a dict with key=param_name and
-            value is a list of open file objects
-        :return: List of tuples of form parameters with file data
-        """
-        if files is None:
-            return []
-
-        params = []
-        for param_name, file_instances in files.items():
-            if file_instances is None:
-                # if the file field is nullable, skip None values
-                continue
-            for file_instance in file_instances:
-                if file_instance is None:
-                    # if the file field is nullable, skip None values
-                    continue
-                if file_instance.closed is True:
-                    raise ApiValueError(
-                        "Cannot read a closed file. The passed in file_type "
-                        "for %s must be open." % param_name
-                    )
-                filename = os.path.basename(file_instance.name)
-                filedata = self.get_file_data_and_close_file(file_instance)
-                mimetype = (mimetypes.guess_type(filename)[0] or
-                            'application/octet-stream')
-                params.append(
-                    tuple([param_name, tuple([filename, filedata, mimetype])]))
-
-        return params
-
-    def select_header_accept(self, accepts):
-        """Returns `Accept` based on an array of accepts provided.
-
-        :param accepts: List of headers.
-        :return: Accept (e.g. application/json).
-        """
-        if not accepts:
-            return
-
-        accepts = [x.lower() for x in accepts]
-
-        if 'application/json' in accepts:
-            return 'application/json'
-        else:
-            return ', '.join(accepts)
-
-    def select_header_content_type(self, content_types):
-        """Returns `Content-Type` based on an array of content_types provided.
-
-        :param content_types: List of content-types.
-        :return: Content-Type (e.g. application/json).
-        """
-        if not content_types:
-            return 'application/json'
-
-        content_types = [x.lower() for x in content_types]
-
-        if 'application/json' in content_types or '*/*' in content_types:
-            return 'application/json'
-        else:
-            return content_types[0]
-
-    def update_params_for_auth(self, headers, querys, auth_settings,
-                               resource_path, method, body):
-        """Updates header and query params based on authentication setting.
-
-        :param headers: Header parameters dict to be updated.
-        :param querys: Query parameters tuple list to be updated.
-        :param auth_settings: Authentication setting identifiers list.
-        :param resource_path: A string representation of the HTTP request resource path.
-        :param method: A string representation of the HTTP request method.
-        :param body: A object representing the body of the HTTP request.
-            The object type is the return value of _encoder.default().
-        """
-        if not auth_settings:
-            return
-
-        for auth in auth_settings:
-            auth_setting = self.configuration.auth_settings().get(auth)
-            if auth_setting:
-                if auth_setting['in'] == 'cookie':
-                    headers['Cookie'] = auth_setting['value']
-                elif auth_setting['in'] == 'header':
-                    if auth_setting['type'] != 'http-signature':
-                        headers[auth_setting['key']] = auth_setting['value']
-                elif auth_setting['in'] == 'query':
-                    querys.append((auth_setting['key'], auth_setting['value']))
-                else:
-                    raise ApiValueError(
-                        'Authentication token must be in `query` or `header`'
-                    )
-
-
-class Endpoint(object):
-    def __init__(self, settings=None, params_map=None, root_map=None,
-                 headers_map=None, api_client=None, callable=None):
-        """Creates an endpoint
-
-        Args:
-            settings (dict): see below key value pairs
-                'response_type' (tuple/None): response type
-                'auth' (list): a list of auth type keys
-                'endpoint_path' (str): the endpoint path
-                'operation_id' (str): endpoint string identifier
-                'http_method' (str): POST/PUT/PATCH/GET etc
-                'servers' (list): list of str servers that this endpoint is at
-            params_map (dict): see below key value pairs
-                'all' (list): list of str endpoint parameter names
-                'required' (list): list of required parameter names
-                'nullable' (list): list of nullable parameter names
-                'enum' (list): list of parameters with enum values
-                'validation' (list): list of parameters with validations
-            root_map
-                'validations' (dict): the dict mapping endpoint parameter tuple
-                    paths to their validation dictionaries
-                'allowed_values' (dict): the dict mapping endpoint parameter
-                    tuple paths to their allowed_values (enum) dictionaries
-                'openapi_types' (dict): param_name to openapi type
-                'attribute_map' (dict): param_name to camelCase name
-                'location_map' (dict): param_name to  'body', 'file', 'form',
-                    'header', 'path', 'query'
-                collection_format_map (dict): param_name to `csv` etc.
-            headers_map (dict): see below key value pairs
-                'accept' (list): list of Accept header strings
-                'content_type' (list): list of Content-Type header strings
-            api_client (ApiClient) api client instance
-            callable (function): the function which is invoked when the
-                Endpoint is called
-        """
-        self.settings = settings
-        self.params_map = params_map
-        self.params_map['all'].extend([
-            'async_req',
-            '_host_index',
-            '_preload_content',
-            '_request_timeout',
-            '_return_http_data_only',
-            '_check_input_type',
-            '_check_return_type'
-        ])
-        self.params_map['nullable'].extend(['_request_timeout'])
-        self.validations = root_map['validations']
-        self.allowed_values = root_map['allowed_values']
-        self.openapi_types = root_map['openapi_types']
-        extra_types = {
-            'async_req': (bool,),
-            '_host_index': (none_type, int),
-            '_preload_content': (bool,),
-            '_request_timeout': (none_type, int, (int,), [int]),
-            '_return_http_data_only': (bool,),
-            '_check_input_type': (bool,),
-            '_check_return_type': (bool,)
-        }
-        self.openapi_types.update(extra_types)
-        self.attribute_map = root_map['attribute_map']
-        self.location_map = root_map['location_map']
-        self.collection_format_map = root_map['collection_format_map']
-        self.headers_map = headers_map
-        self.api_client = api_client
-        self.callable = callable
-
-    def __validate_inputs(self, kwargs):
-        for param in self.params_map['enum']:
-            if param in kwargs:
-                check_allowed_values(
-                    self.allowed_values,
-                    (param,),
-                    kwargs[param]
-                )
-
-        for param in self.params_map['validation']:
-            if param in kwargs:
-                check_validations(
-                    self.validations,
-                    (param,),
-                    kwargs[param],
-                    configuration=self.api_client.configuration
-                )
-
-        if kwargs['_check_input_type'] is False:
-            return
-
-        for key, value in kwargs.items():
-            fixed_val = validate_and_convert_types(
-                value,
-                self.openapi_types[key],
-                [key],
-                False,
-                kwargs['_check_input_type'],
-                configuration=self.api_client.configuration
-            )
-            kwargs[key] = fixed_val
-
-    def __gather_params(self, kwargs):
-        params = {
-            'body': None,
-            'collection_format': {},
-            'file': {},
-            'form': [],
-            'header': {},
-            'path': {},
-            'query': []
-        }
-
-        for param_name, param_value in kwargs.items():
-            param_location = self.location_map.get(param_name)
-            if param_location is None:
-                continue
-            if param_location:
-                if param_location == 'body':
-                    params['body'] = param_value
-                    continue
-                base_name = self.attribute_map[param_name]
-                if (param_location == 'form' and
-                        self.openapi_types[param_name] == (file_type,)):
-                    params['file'][param_name] = [param_value]
-                elif (param_location == 'form' and
-                        self.openapi_types[param_name] == ([file_type],)):
-                    # param_value is already a list
-                    params['file'][param_name] = param_value
-                elif param_location in {'form', 'query'}:
-                    param_value_full = (base_name, param_value)
-                    params[param_location].append(param_value_full)
-                if param_location not in {'form', 'query'}:
-                    params[param_location][base_name] = param_value
-                collection_format = self.collection_format_map.get(param_name)
-                if collection_format:
-                    params['collection_format'][base_name] = collection_format
-
-        return params
-
-    def __call__(self, *args, **kwargs):
-        """ This method is invoked when endpoints are called
-        Example:
-
-        api_instance = ApiBitdotio()
-        api_instance.create_import_file  # this is an instance of the class Endpoint
-        api_instance.create_import_file()  # this invokes api_instance.create_import_file.__call__()
-        which then invokes the callable functions stored in that endpoint at
-        api_instance.create_import_file.callable or self.callable in this class
-
-        """
-        return self.callable(self, *args, **kwargs)
-
-    def call_with_http_info(self, **kwargs):
-
-        try:
-            index = self.api_client.configuration.server_operation_index.get(
-                self.settings['operation_id'], self.api_client.configuration.server_index
-            ) if kwargs['_host_index'] is None else kwargs['_host_index']
-            server_variables = self.api_client.configuration.server_operation_variables.get(
-                self.settings['operation_id'], self.api_client.configuration.server_variables
-            )
-            _host = self.api_client.configuration.get_host_from_settings(
-                index, variables=server_variables, servers=self.settings['servers']
-            )
-        except IndexError:
-            if self.settings['servers']:
-                raise ApiValueError(
-                    "Invalid host index. Must be 0 <= index < %s" %
-                    len(self.settings['servers'])
-                )
-            _host = None
 
-        for key, value in kwargs.items():
-            if key not in self.params_map['all']:
-                raise ApiTypeError(
-                    "Got an unexpected parameter '%s'"
-                    " to method `%s`" %
-                    (key, self.settings['operation_id'])
-                )
-            # only throw this nullable ApiValueError if _check_input_type
-            # is False, if _check_input_type==True we catch this case
-            # in self.__validate_inputs
-            if (key not in self.params_map['nullable'] and value is None
-                    and kwargs['_check_input_type'] is False):
-                raise ApiValueError(
-                    "Value may not be None for non-nullable parameter `%s`"
-                    " when calling `%s`" %
-                    (key, self.settings['operation_id'])
-                )
+    def _url(self, path: str) -> str:
+        return urljoin(f"https://api.bit.io", f"{self._api_version}{path}")
 
-        for key in self.params_map['required']:
-            if key not in kwargs.keys():
-                raise ApiValueError(
-                    "Missing the required parameter `%s` when calling "
-                    "`%s`" % (key, self.settings['operation_id'])
-                )
+    def request(self, method: str, url: str, **kwargs: t.Any) -> Response:
+        return self._session.request(method, self._url(url), **kwargs)
 
-        self.__validate_inputs(kwargs)
+    def get(self, url: str, **kwargs: t.Any) -> Response:
+        return self.request("GET", url, **kwargs)
 
-        params = self.__gather_params(kwargs)
+    def post(self, url: str, json: t.Any = None, **kwargs: t.Any) -> Response:
+        return self.request("POST", url, json=json, **kwargs)
 
-        accept_headers_list = self.headers_map['accept']
-        if accept_headers_list:
-            params['header']['Accept'] = self.api_client.select_header_accept(
-                accept_headers_list)
+    def patch(self, url: str, json: t.Any = None, **kwargs: t.Any) -> Response:
+        return self.request("PATCH", url, json=json, **kwargs)
 
-        content_type_headers_list = self.headers_map['content_type']
-        if content_type_headers_list:
-            header_list = self.api_client.select_header_content_type(
-                content_type_headers_list)
-            params['header']['Content-Type'] = header_list
+    def delete(self, url: str, **kwargs: t.Any) -> Response:
+        return self.request("DELETE", url, **kwargs)
 
-        return self.api_client.call_api(
-            self.settings['endpoint_path'], self.settings['http_method'],
-            params['path'],
-            params['query'],
-            params['header'],
-            body=params['body'],
-            post_params=params['form'],
-            files=params['file'],
-            response_type=self.settings['response_type'],
-            auth_settings=self.settings['auth'],
-            async_req=kwargs['async_req'],
-            _check_type=kwargs['_check_return_type'],
-            _return_http_data_only=kwargs['_return_http_data_only'],
-            _preload_content=kwargs['_preload_content'],
-            _request_timeout=kwargs['_request_timeout'],
-            _host=_host,
-            collection_formats=params['collection_format'])
+    def set_header(self, header: str, value: str) -> None:
+        self._session.headers.update({header: value})
diff --git a/bitdotio/apis/__init__.py b/bitdotio/apis/__init__.py
deleted file mode 100644
index 70f2db0..0000000
--- a/bitdotio/apis/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-
-# flake8: noqa
-
-# Import all APIs into this package.
-# If you have many APIs here with many many models used in each API this may
-# raise a `RecursionError`.
-# In order to avoid this, import only the API that you directly need like:
-#
-#   from .api.api_bitdotio import ApiBitdotio
-#
-# or import this package, but before doing it, use:
-#
-#   import sys
-#   sys.setrecursionlimit(n)
-
-# Import APIs into API package:
-from bitdotio.api.api_bitdotio import ApiBitdotio
diff --git a/bitdotio/bitdotio.py b/bitdotio/bitdotio.py
deleted file mode 100644
index b8bd1dd..0000000
--- a/bitdotio/bitdotio.py
+++ /dev/null
@@ -1,142 +0,0 @@
-#!/usr/bin/env python3
-from __future__ import print_function
-from inspect import Attribute
-import time
-import bitdotio
-from bitdotio import Configuration, ApiClient, ApiBitdotio
-from bitdotio.rest import ApiException
-from pprint import pprint
-import sys
-from . import model
-
-
-def bitdotio(access_token):
-    # determine bit.io version from the token format
-    token_parts = access_token.split('_')
-    if len(token_parts) == 2:
-        return _Bit(access_token)
-    elif (len(token_parts) == 3) and (token_parts[0] == 'v2'):
-        return _BitV2(access_token)
-    else:
-        raise ValueError("Invalid access token format.")
-
-
-class _HostConfigMixin():
-    _port = 5432
-    _host = "db.bit.io"
-
-
-class _Bit(_HostConfigMixin, ApiBitdotio):
-    def __init__(self, access_token):
-        assert access_token
-        configuration = Configuration(
-            host = "https://api.bit.io/api/v1beta",
-        )
-        configuration.access_token = access_token
-        self.access_token = access_token
-        self.api_client = ApiClient(configuration)
-        self.api_client.user_agent = "bit.io-SDK/1.0.0/python"
-        super().__init__(self.api_client)
-
-    def __repr__(self):
-        return "<bitdotio SDK object: v1>"
-
-    def _token_to_creds(self):
-        # Both _user_ and _db_ here are to satisfy psycopg2, but bit.io itself
-        # doesn't care about these - everything we need is in the access token.
-        db = "qap"
-        user = "api_user"
-        password = self.access_token
-        host = self._host
-        port = self._port
-        return f"dbname={db} user={user} password={password} host={host} port={port}"
-
-    def query(self, query_string, fields={}, data=[]):
-        query_obj = model.query.Query(query_string=query_string, fields=fields, data=data)
-        return self.create_query(query=query_obj)
-
-    def get_connection(self):
-        try:
-            import psycopg2
-        except ImportError as e:
-            _print_psycopg2_message()
-            raise e
-
-        conn_str = self._token_to_creds()
-        conn = psycopg2.connect(conn_str)
-        conn.autocommit = True
-
-        return conn
-
-
-class _BitV2(_HostConfigMixin):
-    _BACKWARDS_INCOMPATIBLE_ATTRIBUTES = [
-        'api_client',
-        'create_import_file',
-        'create_import_json',
-        'create_import_url',
-        'create_query',
-        'create_repo',
-        'destroy_repo',
-        'list_repos',
-        'partial_update_repo',
-        'query',
-        'retrieve_ingestor_job',
-        'retrieve_repo',
-        'update_repo',
-        ]
-    
-    def __init__(self, access_token):
-        assert access_token
-        self.access_token = access_token
-
-    def __repr__(self):
-        return "<bitdotio SDK object: v2>"
-
-    # inform user when an attempt is made to access v1-only attribute 
-    def __getattr__(self, name):
-        if name in self._BACKWARDS_INCOMPATIBLE_ATTRIBUTES:
-            raise AttributeError(f"You have configured the SDK with a v2 token, and '{name}' is currently limited to v1.")
-        else:
-            raise AttributeError(f"'_BitV2' object has no attribute '{name}'")
-
-    def _token_to_creds(self, database_name):
-        db = database_name
-        user = "api_user"
-        password = self.access_token
-        host = self._host
-        port = self._port
-        return f"dbname={db} user={user} password={password} host={host} port={port} sslmode=require"
-
-    def get_connection(self, database_name):
-        try:
-            import psycopg2
-        except ImportError as e:
-            _print_psycopg2_message()
-            raise e
-
-        conn_str = self._token_to_creds(database_name)
-        conn = psycopg2.connect(conn_str)
-
-        return conn
-
-def _print_psycopg2_message():
-    print("""
-It looks like we couldn't import the psycopg2 library!
-
-In order to support different environments, we have a few ways to install the bitdotio package
-with or without the psycopg2 dependency.
-
-1. If you already have psycopg2 install, you can install the default bitdotio package:
-
-  pip install bitdotio
-
-2. If you already have Postgres installed, you can install with the psycopg2 dependency:
-
-  pip install bitdotio[psycopg2]
-
-3. If you do not have or cannot install Postgres, you can install with the psycopg2-binary dependency:
-
-  pip install bitdotio[psycopg2-binary]
-
-""", file=sys.stderr)
diff --git a/bitdotio/configuration.py b/bitdotio/configuration.py
deleted file mode 100644
index 48b6b11..0000000
--- a/bitdotio/configuration.py
+++ /dev/null
@@ -1,451 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import copy
-import logging
-import multiprocessing
-import sys
-import urllib3
-
-from http import client as http_client
-from bitdotio.exceptions import ApiValueError
-
-
-JSON_SCHEMA_VALIDATION_KEYWORDS = {
-    'multipleOf', 'maximum', 'exclusiveMaximum',
-    'minimum', 'exclusiveMinimum', 'maxLength',
-    'minLength', 'pattern', 'maxItems', 'minItems'
-}
-
-class Configuration(object):
-    """NOTE: This class is auto generated by OpenAPI Generator
-
-    Ref: https://openapi-generator.tech
-    Do not edit the class manually.
-
-    :param host: Base url
-    :param api_key: Dict to store API key(s).
-      Each entry in the dict specifies an API key.
-      The dict key is the name of the security scheme in the OAS specification.
-      The dict value is the API key secret.
-    :param api_key_prefix: Dict to store API prefix (e.g. Bearer)
-      The dict key is the name of the security scheme in the OAS specification.
-      The dict value is an API key prefix when generating the auth data.
-    :param username: Username for HTTP basic authentication
-    :param password: Password for HTTP basic authentication
-    :param discard_unknown_keys: Boolean value indicating whether to discard
-      unknown properties. A server may send a response that includes additional
-      properties that are not known by the client in the following scenarios:
-      1. The OpenAPI document is incomplete, i.e. it does not match the server
-         implementation.
-      2. The client was generated using an older version of the OpenAPI document
-         and the server has been upgraded since then.
-      If a schema in the OpenAPI document defines the additionalProperties attribute,
-      then all undeclared properties received by the server are injected into the
-      additional properties map. In that case, there are undeclared properties, and
-      nothing to discard.
-    :param disabled_client_side_validations (string): Comma-separated list of
-      JSON schema validation keywords to disable JSON schema structural validation
-      rules. The following keywords may be specified: multipleOf, maximum,
-      exclusiveMaximum, minimum, exclusiveMinimum, maxLength, minLength, pattern,
-      maxItems, minItems.
-      By default, the validation is performed for data generated locally by the client
-      and data received from the server, independent of any validation performed by
-      the server side. If the input data does not satisfy the JSON schema validation
-      rules specified in the OpenAPI document, an exception is raised.
-      If disabled_client_side_validations is set, structural validation is
-      disabled. This can be useful to troubleshoot data validation problem, such as
-      when the OpenAPI document validation rules do not match the actual API data
-      received by the server.
-    :param server_index: Index to servers configuration.
-    :param server_variables: Mapping with string values to replace variables in
-      templated server configuration. The validation of enums is performed for
-      variables with defined enum values before.
-    :param server_operation_index: Mapping from operation ID to an index to server
-      configuration.
-    :param server_operation_variables: Mapping from operation ID to a mapping with
-      string values to replace variables in templated server configuration.
-      The validation of enums is performed for variables with defined enum values before.
-    :param ssl_ca_cert: str - the path to a file of concatenated CA certificates 
-      in PEM format
-
-    :Example:
-    """
-
-    _default = None
-
-    def __init__(self, host=None,
-                 api_key=None, api_key_prefix=None,
-                 access_token=None,
-                 username=None, password=None,
-                 discard_unknown_keys=False,
-                 disabled_client_side_validations="",
-                 server_index=None, server_variables=None,
-                 server_operation_index=None, server_operation_variables=None,
-                 ssl_ca_cert=None,
-                 ):
-        """Constructor
-        """
-        self._base_path = "https://api.bit.io/api/v1beta" if host is None else host
-        """Default Base url
-        """
-        self.server_index = 0 if server_index is None and host is None else server_index
-        self.server_operation_index = server_operation_index or {}
-        """Default server index
-        """
-        self.server_variables = server_variables or {}
-        self.server_operation_variables = server_operation_variables or {}
-        """Default server variables
-        """
-        self.temp_folder_path = None
-        """Temp file folder for downloading files
-        """
-        # Authentication Settings
-        self.access_token = access_token
-        self.api_key = {}
-        if api_key:
-            self.api_key = api_key
-        """dict to store API key(s)
-        """
-        self.api_key_prefix = {}
-        if api_key_prefix:
-            self.api_key_prefix = api_key_prefix
-        """dict to store API prefix (e.g. Bearer)
-        """
-        self.refresh_api_key_hook = None
-        """function hook to refresh API key if expired
-        """
-        self.username = username
-        """Username for HTTP basic authentication
-        """
-        self.password = password
-        """Password for HTTP basic authentication
-        """
-        self.discard_unknown_keys = discard_unknown_keys
-        self.disabled_client_side_validations = disabled_client_side_validations
-        self.logger = {}
-        """Logging Settings
-        """
-        self.logger["package_logger"] = logging.getLogger("bitdotio")
-        self.logger["urllib3_logger"] = logging.getLogger("urllib3")
-        self.logger_format = '%(asctime)s %(levelname)s %(message)s'
-        """Log format
-        """
-        self.logger_stream_handler = None
-        """Log stream handler
-        """
-        self.logger_file_handler = None
-        """Log file handler
-        """
-        self.logger_file = None
-        """Debug file location
-        """
-        self.debug = False
-        """Debug switch
-        """
-
-        self.verify_ssl = True
-        """SSL/TLS verification
-           Set this to false to skip verifying SSL certificate when calling API
-           from https server.
-        """
-        self.ssl_ca_cert = ssl_ca_cert
-        """Set this to customize the certificate file to verify the peer.
-        """
-        self.cert_file = None
-        """client certificate file
-        """
-        self.key_file = None
-        """client key file
-        """
-        self.assert_hostname = None
-        """Set this to True/False to enable/disable SSL hostname verification.
-        """
-
-        self.connection_pool_maxsize = multiprocessing.cpu_count() * 5
-        """urllib3 connection pool's maximum number of connections saved
-           per pool. urllib3 uses 1 connection as default value, but this is
-           not the best value when you are making a lot of possibly parallel
-           requests to the same host, which is often the case here.
-           cpu_count * 5 is used as default value to increase performance.
-        """
-
-        self.proxy = None
-        """Proxy URL
-        """
-        self.proxy_headers = None
-        """Proxy headers
-        """
-        self.safe_chars_for_path_param = ''
-        """Safe chars for path_param
-        """
-        self.retries = None
-        """Adding retries to override urllib3 default value 3
-        """
-        # Enable client side validation
-        self.client_side_validation = True
-
-        # Options to pass down to the underlying urllib3 socket
-        self.socket_options = None
-
-    def __deepcopy__(self, memo):
-        cls = self.__class__
-        result = cls.__new__(cls)
-        memo[id(self)] = result
-        for k, v in self.__dict__.items():
-            if k not in ('logger', 'logger_file_handler'):
-                setattr(result, k, copy.deepcopy(v, memo))
-        # shallow copy of loggers
-        result.logger = copy.copy(self.logger)
-        # use setters to configure loggers
-        result.logger_file = self.logger_file
-        result.debug = self.debug
-        return result
-
-    def __setattr__(self, name, value):
-        object.__setattr__(self, name, value)
-        if name == 'disabled_client_side_validations':
-            s = set(filter(None, value.split(',')))
-            for v in s:
-                if v not in JSON_SCHEMA_VALIDATION_KEYWORDS:
-                    raise ApiValueError(
-                        "Invalid keyword: '{0}''".format(v))
-            self._disabled_client_side_validations = s
-
-    @classmethod
-    def set_default(cls, default):
-        """Set default instance of configuration.
-
-        It stores default configuration, which can be
-        returned by get_default_copy method.
-
-        :param default: object of Configuration
-        """
-        cls._default = copy.deepcopy(default)
-
-    @classmethod
-    def get_default_copy(cls):
-        """Return new instance of configuration.
-
-        This method returns newly created, based on default constructor,
-        object of Configuration class or returns a copy of default
-        configuration passed by the set_default method.
-
-        :return: The configuration object.
-        """
-        if cls._default is not None:
-            return copy.deepcopy(cls._default)
-        return Configuration()
-
-    @property
-    def logger_file(self):
-        """The logger file.
-
-        If the logger_file is None, then add stream handler and remove file
-        handler. Otherwise, add file handler and remove stream handler.
-
-        :param value: The logger_file path.
-        :type: str
-        """
-        return self.__logger_file
-
-    @logger_file.setter
-    def logger_file(self, value):
-        """The logger file.
-
-        If the logger_file is None, then add stream handler and remove file
-        handler. Otherwise, add file handler and remove stream handler.
-
-        :param value: The logger_file path.
-        :type: str
-        """
-        self.__logger_file = value
-        if self.__logger_file:
-            # If set logging file,
-            # then add file handler and remove stream handler.
-            self.logger_file_handler = logging.FileHandler(self.__logger_file)
-            self.logger_file_handler.setFormatter(self.logger_formatter)
-            for _, logger in self.logger.items():
-                logger.addHandler(self.logger_file_handler)
-
-    @property
-    def debug(self):
-        """Debug status
-
-        :param value: The debug status, True or False.
-        :type: bool
-        """
-        return self.__debug
-
-    @debug.setter
-    def debug(self, value):
-        """Debug status
-
-        :param value: The debug status, True or False.
-        :type: bool
-        """
-        self.__debug = value
-        if self.__debug:
-            # if debug status is True, turn on debug logging
-            for _, logger in self.logger.items():
-                logger.setLevel(logging.DEBUG)
-            # turn on http_client debug
-            http_client.HTTPConnection.debuglevel = 1
-        else:
-            # if debug status is False, turn off debug logging,
-            # setting log level to default `logging.WARNING`
-            for _, logger in self.logger.items():
-                logger.setLevel(logging.WARNING)
-            # turn off http_client debug
-            http_client.HTTPConnection.debuglevel = 0
-
-    @property
-    def logger_format(self):
-        """The logger format.
-
-        The logger_formatter will be updated when sets logger_format.
-
-        :param value: The format string.
-        :type: str
-        """
-        return self.__logger_format
-
-    @logger_format.setter
-    def logger_format(self, value):
-        """The logger format.
-
-        The logger_formatter will be updated when sets logger_format.
-
-        :param value: The format string.
-        :type: str
-        """
-        self.__logger_format = value
-        self.logger_formatter = logging.Formatter(self.__logger_format)
-
-    def get_api_key_with_prefix(self, identifier, alias=None):
-        """Gets API key (with prefix if set).
-
-        :param identifier: The identifier of apiKey.
-        :param alias: The alternative identifier of apiKey.
-        :return: The token for api key authentication.
-        """
-        if self.refresh_api_key_hook is not None:
-            self.refresh_api_key_hook(self)
-        key = self.api_key.get(identifier, self.api_key.get(alias) if alias is not None else None)
-        if key:
-            prefix = self.api_key_prefix.get(identifier)
-            if prefix:
-                return "%s %s" % (prefix, key)
-            else:
-                return key
-
-    def get_basic_auth_token(self):
-        """Gets HTTP basic authentication header (string).
-
-        :return: The token for basic HTTP authentication.
-        """
-        username = ""
-        if self.username is not None:
-            username = self.username
-        password = ""
-        if self.password is not None:
-            password = self.password
-        return urllib3.util.make_headers(
-            basic_auth=username + ':' + password
-        ).get('authorization')
-
-    def auth_settings(self):
-        """Gets Auth Settings dict for api client.
-
-        :return: The Auth Settings information dict.
-        """
-        auth = {}
-        if self.access_token is not None:
-            auth['bearerAuth'] = {
-                'type': 'bearer',
-                'in': 'header',
-                'key': 'Authorization',
-                'value': 'Bearer ' + self.access_token
-            }
-        return auth
-
-    def to_debug_report(self):
-        """Gets the essential information for debugging.
-
-        :return: The report for debugging.
-        """
-        return "Python SDK Debug Report:\n"\
-               "OS: {env}\n"\
-               "Python Version: {pyversion}\n"\
-               "Version of the API: 1.0.0b\n"\
-               "SDK Package Version: 1.0.0".\
-               format(env=sys.platform, pyversion=sys.version)
-
-    def get_host_settings(self):
-        """Gets an array of host settings
-
-        :return: An array of host settings
-        """
-        return [
-            {
-                'url': "https://api.bit.io/api/v1beta",
-                'description': "bit.io API",
-            }
-        ]
-
-    def get_host_from_settings(self, index, variables=None, servers=None):
-        """Gets host URL based on the index and variables
-        :param index: array index of the host settings
-        :param variables: hash of variable and the corresponding value
-        :param servers: an array of host settings or None
-        :return: URL based on host settings
-        """
-        if index is None:
-            return self._base_path
-
-        variables = {} if variables is None else variables
-        servers = self.get_host_settings() if servers is None else servers
-
-        try:
-            server = servers[index]
-        except IndexError:
-            raise ValueError(
-                "Invalid index {0} when selecting the host settings. "
-                "Must be less than {1}".format(index, len(servers)))
-
-        url = server['url']
-
-        # go through variables and replace placeholders
-        for variable_name, variable in server.get('variables', {}).items():
-            used_value = variables.get(
-                variable_name, variable['default_value'])
-
-            if 'enum_values' in variable \
-                    and used_value not in variable['enum_values']:
-                raise ValueError(
-                    "The variable `{0}` in the host URL has invalid value "
-                    "{1}. Must be {2}.".format(
-                        variable_name, variables[variable_name],
-                        variable['enum_values']))
-
-            url = url.replace("{" + variable_name + "}", used_value)
-
-        return url
-
-    @property
-    def host(self):
-        """Return generated host."""
-        return self.get_host_from_settings(self.server_index, variables=self.server_variables)
-
-    @host.setter
-    def host(self, value):
-        """Fix base path."""
-        self._base_path = value
-        self.server_index = None
diff --git a/bitdotio/exceptions.py b/bitdotio/exceptions.py
deleted file mode 100644
index 0b2a252..0000000
--- a/bitdotio/exceptions.py
+++ /dev/null
@@ -1,159 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-
-class OpenApiException(Exception):
-    """The base exception class for all OpenAPIExceptions"""
-
-
-class ApiTypeError(OpenApiException, TypeError):
-    def __init__(self, msg, path_to_item=None, valid_classes=None,
-                 key_type=None):
-        """ Raises an exception for TypeErrors
-
-        Args:
-            msg (str): the exception message
-
-        Keyword Args:
-            path_to_item (list): a list of keys an indices to get to the
-                                 current_item
-                                 None if unset
-            valid_classes (tuple): the primitive classes that current item
-                                   should be an instance of
-                                   None if unset
-            key_type (bool): False if our value is a value in a dict
-                             True if it is a key in a dict
-                             False if our item is an item in a list
-                             None if unset
-        """
-        self.path_to_item = path_to_item
-        self.valid_classes = valid_classes
-        self.key_type = key_type
-        full_msg = msg
-        if path_to_item:
-            full_msg = "{0} at {1}".format(msg, render_path(path_to_item))
-        super(ApiTypeError, self).__init__(full_msg)
-
-
-class ApiValueError(OpenApiException, ValueError):
-    def __init__(self, msg, path_to_item=None):
-        """
-        Args:
-            msg (str): the exception message
-
-        Keyword Args:
-            path_to_item (list) the path to the exception in the
-                received_data dict. None if unset
-        """
-
-        self.path_to_item = path_to_item
-        full_msg = msg
-        if path_to_item:
-            full_msg = "{0} at {1}".format(msg, render_path(path_to_item))
-        super(ApiValueError, self).__init__(full_msg)
-
-
-class ApiAttributeError(OpenApiException, AttributeError):
-    def __init__(self, msg, path_to_item=None):
-        """
-        Raised when an attribute reference or assignment fails.
-
-        Args:
-            msg (str): the exception message
-
-        Keyword Args:
-            path_to_item (None/list) the path to the exception in the
-                received_data dict
-        """
-        self.path_to_item = path_to_item
-        full_msg = msg
-        if path_to_item:
-            full_msg = "{0} at {1}".format(msg, render_path(path_to_item))
-        super(ApiAttributeError, self).__init__(full_msg)
-
-
-class ApiKeyError(OpenApiException, KeyError):
-    def __init__(self, msg, path_to_item=None):
-        """
-        Args:
-            msg (str): the exception message
-
-        Keyword Args:
-            path_to_item (None/list) the path to the exception in the
-                received_data dict
-        """
-        self.path_to_item = path_to_item
-        full_msg = msg
-        if path_to_item:
-            full_msg = "{0} at {1}".format(msg, render_path(path_to_item))
-        super(ApiKeyError, self).__init__(full_msg)
-
-
-class ApiException(OpenApiException):
-
-    def __init__(self, status=None, reason=None, http_resp=None):
-        if http_resp:
-            self.status = http_resp.status
-            self.reason = http_resp.reason
-            self.body = http_resp.data
-            self.headers = http_resp.getheaders()
-        else:
-            self.status = status
-            self.reason = reason
-            self.body = None
-            self.headers = None
-
-    def __str__(self):
-        """Custom error messages for exception"""
-        error_message = "({0})\n"\
-                        "Reason: {1}\n".format(self.status, self.reason)
-        if self.headers:
-            error_message += "HTTP response headers: {0}\n".format(
-                self.headers)
-
-        if self.body:
-            error_message += "HTTP response body: {0}\n".format(self.body)
-
-        return error_message
-
-
-class NotFoundException(ApiException):
-
-    def __init__(self, status=None, reason=None, http_resp=None):
-        super(NotFoundException, self).__init__(status, reason, http_resp)
-
-
-class UnauthorizedException(ApiException):
-
-    def __init__(self, status=None, reason=None, http_resp=None):
-        super(UnauthorizedException, self).__init__(status, reason, http_resp)
-
-
-class ForbiddenException(ApiException):
-
-    def __init__(self, status=None, reason=None, http_resp=None):
-        super(ForbiddenException, self).__init__(status, reason, http_resp)
-
-
-class ServiceException(ApiException):
-
-    def __init__(self, status=None, reason=None, http_resp=None):
-        super(ServiceException, self).__init__(status, reason, http_resp)
-
-
-def render_path(path_to_item):
-    """Returns a string representation of a path"""
-    result = ""
-    for pth in path_to_item:
-        if isinstance(pth, int):
-            result += "[{0}]".format(pth)
-        else:
-            result += "['{0}']".format(pth)
-    return result
diff --git a/bitdotio/model/__init__.py b/bitdotio/model/__init__.py
deleted file mode 100644
index cfe32b7..0000000
--- a/bitdotio/model/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# we can not import model classes here because that would create a circular
-# reference which would not work in python2
-# do not import all models into this module because that uses a lot of memory and stack frames
-# if you need the ability to import all models from one package, import them with
-# from {{packageName}.models import ModelA, ModelB
diff --git a/bitdotio/model/import_file.py b/bitdotio/model/import_file.py
deleted file mode 100644
index a7a464d..0000000
--- a/bitdotio/model/import_file.py
+++ /dev/null
@@ -1,179 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import re  # noqa: F401
-import sys  # noqa: F401
-
-from bitdotio.model_utils import (  # noqa: F401
-    ApiTypeError,
-    ModelComposed,
-    ModelNormal,
-    ModelSimple,
-    cached_property,
-    change_keys_js_to_python,
-    convert_js_args_to_python_args,
-    date,
-    datetime,
-    file_type,
-    none_type,
-    validate_get_composed_info,
-)
-
-
-class ImportFile(ModelNormal):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-
-    Attributes:
-      allowed_values (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          with a capitalized key describing the allowed value and an allowed
-          value. These dicts store the allowed enum values.
-      attribute_map (dict): The key is attribute name
-          and the value is json key in definition.
-      discriminator_value_class_map (dict): A dict to go from the discriminator
-          variable value to the discriminator class name.
-      validations (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          that stores validations for max_length, min_length, max_items,
-          min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,
-          inclusive_minimum, and regex.
-      additional_properties_type (tuple): A tuple of classes accepted
-          as additional properties values.
-    """
-
-    allowed_values = {
-    }
-
-    validations = {
-    }
-
-    additional_properties_type = None
-
-    _nullable = False
-
-    @cached_property
-    def openapi_types():
-        """
-        This must be a method because a model may have properties that are
-        of type self, this must run after the class is loaded
-
-        Returns
-            openapi_types (dict): The key is attribute name
-                and the value is attribute type.
-        """
-        return {
-            'file_to_import': (file_type,),  # noqa: E501
-            'repo_name': (str,),  # noqa: E501
-            'table_name': (str,),  # noqa: E501
-            'create_table_if_not_exists': (bool,),  # noqa: E501
-        }
-
-    @cached_property
-    def discriminator():
-        return None
-
-
-    attribute_map = {
-        'file_to_import': 'file_to_import',  # noqa: E501
-        'repo_name': 'repo_name',  # noqa: E501
-        'table_name': 'table_name',  # noqa: E501
-        'create_table_if_not_exists': 'create_table_if_not_exists',  # noqa: E501
-    }
-
-    _composed_schemas = {}
-
-    required_properties = set([
-        '_data_store',
-        '_check_type',
-        '_spec_property_naming',
-        '_path_to_item',
-        '_configuration',
-        '_visited_composed_classes',
-    ])
-
-    @convert_js_args_to_python_args
-    def __init__(self, file_to_import, repo_name, *args, **kwargs):  # noqa: E501
-        """ImportFile - a model defined in OpenAPI
-
-        Args:
-            file_to_import (file_type):
-            repo_name (str):
-
-        Keyword Args:
-            _check_type (bool): if True, values for parameters in openapi_types
-                                will be type checked and a TypeError will be
-                                raised if the wrong type is input.
-                                Defaults to True
-            _path_to_item (tuple/list): This is a list of keys or values to
-                                drill down to the model in received_data
-                                when deserializing a response
-            _spec_property_naming (bool): True if the variable names in the input data
-                                are serialized names, as specified in the OpenAPI document.
-                                False if the variable names in the input data
-                                are pythonic names, e.g. snake case (default)
-            _configuration (Configuration): the instance to use when
-                                deserializing a file_type parameter.
-                                If passed, type conversion is attempted
-                                If omitted no type conversion is done.
-            _visited_composed_classes (tuple): This stores a tuple of
-                                classes that we have traveled through so that
-                                if we see that class again we will not use its
-                                discriminator again.
-                                When traveling through a discriminator, the
-                                composed schema that is
-                                is traveled through is added to this set.
-                                For example if Animal has a discriminator
-                                petType and we pass in "Dog", and the class Dog
-                                allOf includes Animal, we move through Animal
-                                once using the discriminator, and pick Dog.
-                                Then in Dog, we will make an instance of the
-                                Animal class but this time we won't travel
-                                through its discriminator because we passed in
-                                _visited_composed_classes = (Animal,)
-            table_name (str): [optional]  # noqa: E501
-            create_table_if_not_exists (bool): [optional] if omitted the server will use the default value of True  # noqa: E501
-        """
-
-        _check_type = kwargs.pop('_check_type', True)
-        _spec_property_naming = kwargs.pop('_spec_property_naming', False)
-        _path_to_item = kwargs.pop('_path_to_item', ())
-        _configuration = kwargs.pop('_configuration', None)
-        _visited_composed_classes = kwargs.pop('_visited_composed_classes', ())
-
-        if args:
-            raise ApiTypeError(
-                "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
-                    args,
-                    self.__class__.__name__,
-                ),
-                path_to_item=_path_to_item,
-                valid_classes=(self.__class__,),
-            )
-
-        self._data_store = {}
-        self._check_type = _check_type
-        self._spec_property_naming = _spec_property_naming
-        self._path_to_item = _path_to_item
-        self._configuration = _configuration
-        self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
-
-        self.file_to_import = file_to_import
-        self.repo_name = repo_name
-        for var_name, var_value in kwargs.items():
-            if var_name not in self.attribute_map and \
-                        self._configuration is not None and \
-                        self._configuration.discard_unknown_keys and \
-                        self.additional_properties_type is None:
-                # discard variable.
-                continue
-            setattr(self, var_name, var_value)
diff --git a/bitdotio/model/import_json.py b/bitdotio/model/import_json.py
deleted file mode 100644
index b4e5c29..0000000
--- a/bitdotio/model/import_json.py
+++ /dev/null
@@ -1,180 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import re  # noqa: F401
-import sys  # noqa: F401
-
-from bitdotio.model_utils import (  # noqa: F401
-    ApiTypeError,
-    ModelComposed,
-    ModelNormal,
-    ModelSimple,
-    cached_property,
-    change_keys_js_to_python,
-    convert_js_args_to_python_args,
-    date,
-    datetime,
-    file_type,
-    none_type,
-    validate_get_composed_info,
-)
-
-
-class ImportJson(ModelNormal):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-
-    Attributes:
-      allowed_values (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          with a capitalized key describing the allowed value and an allowed
-          value. These dicts store the allowed enum values.
-      attribute_map (dict): The key is attribute name
-          and the value is json key in definition.
-      discriminator_value_class_map (dict): A dict to go from the discriminator
-          variable value to the discriminator class name.
-      validations (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          that stores validations for max_length, min_length, max_items,
-          min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,
-          inclusive_minimum, and regex.
-      additional_properties_type (tuple): A tuple of classes accepted
-          as additional properties values.
-    """
-
-    allowed_values = {
-    }
-
-    validations = {
-    }
-
-    additional_properties_type = None
-
-    _nullable = False
-
-    @cached_property
-    def openapi_types():
-        """
-        This must be a method because a model may have properties that are
-        of type self, this must run after the class is loaded
-
-        Returns
-            openapi_types (dict): The key is attribute name
-                and the value is attribute type.
-        """
-        return {
-            'data': (str,),  # noqa: E501
-            'table_name': (str,),  # noqa: E501
-            'repo_name': (str,),  # noqa: E501
-            'create_table_if_not_exists': (bool,),  # noqa: E501
-        }
-
-    @cached_property
-    def discriminator():
-        return None
-
-
-    attribute_map = {
-        'data': 'data',  # noqa: E501
-        'table_name': 'table_name',  # noqa: E501
-        'repo_name': 'repo_name',  # noqa: E501
-        'create_table_if_not_exists': 'create_table_if_not_exists',  # noqa: E501
-    }
-
-    _composed_schemas = {}
-
-    required_properties = set([
-        '_data_store',
-        '_check_type',
-        '_spec_property_naming',
-        '_path_to_item',
-        '_configuration',
-        '_visited_composed_classes',
-    ])
-
-    @convert_js_args_to_python_args
-    def __init__(self, data, table_name, repo_name, *args, **kwargs):  # noqa: E501
-        """ImportJson - a model defined in OpenAPI
-
-        Args:
-            data (str):
-            table_name (str):
-            repo_name (str):
-
-        Keyword Args:
-            _check_type (bool): if True, values for parameters in openapi_types
-                                will be type checked and a TypeError will be
-                                raised if the wrong type is input.
-                                Defaults to True
-            _path_to_item (tuple/list): This is a list of keys or values to
-                                drill down to the model in received_data
-                                when deserializing a response
-            _spec_property_naming (bool): True if the variable names in the input data
-                                are serialized names, as specified in the OpenAPI document.
-                                False if the variable names in the input data
-                                are pythonic names, e.g. snake case (default)
-            _configuration (Configuration): the instance to use when
-                                deserializing a file_type parameter.
-                                If passed, type conversion is attempted
-                                If omitted no type conversion is done.
-            _visited_composed_classes (tuple): This stores a tuple of
-                                classes that we have traveled through so that
-                                if we see that class again we will not use its
-                                discriminator again.
-                                When traveling through a discriminator, the
-                                composed schema that is
-                                is traveled through is added to this set.
-                                For example if Animal has a discriminator
-                                petType and we pass in "Dog", and the class Dog
-                                allOf includes Animal, we move through Animal
-                                once using the discriminator, and pick Dog.
-                                Then in Dog, we will make an instance of the
-                                Animal class but this time we won't travel
-                                through its discriminator because we passed in
-                                _visited_composed_classes = (Animal,)
-            create_table_if_not_exists (bool): [optional] if omitted the server will use the default value of True  # noqa: E501
-        """
-
-        _check_type = kwargs.pop('_check_type', True)
-        _spec_property_naming = kwargs.pop('_spec_property_naming', False)
-        _path_to_item = kwargs.pop('_path_to_item', ())
-        _configuration = kwargs.pop('_configuration', None)
-        _visited_composed_classes = kwargs.pop('_visited_composed_classes', ())
-
-        if args:
-            raise ApiTypeError(
-                "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
-                    args,
-                    self.__class__.__name__,
-                ),
-                path_to_item=_path_to_item,
-                valid_classes=(self.__class__,),
-            )
-
-        self._data_store = {}
-        self._check_type = _check_type
-        self._spec_property_naming = _spec_property_naming
-        self._path_to_item = _path_to_item
-        self._configuration = _configuration
-        self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
-
-        self.data = data
-        self.table_name = table_name
-        self.repo_name = repo_name
-        for var_name, var_value in kwargs.items():
-            if var_name not in self.attribute_map and \
-                        self._configuration is not None and \
-                        self._configuration.discard_unknown_keys and \
-                        self.additional_properties_type is None:
-                # discard variable.
-                continue
-            setattr(self, var_name, var_value)
diff --git a/bitdotio/model/import_url.py b/bitdotio/model/import_url.py
deleted file mode 100644
index 22f9a4c..0000000
--- a/bitdotio/model/import_url.py
+++ /dev/null
@@ -1,183 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import re  # noqa: F401
-import sys  # noqa: F401
-
-from bitdotio.model_utils import (  # noqa: F401
-    ApiTypeError,
-    ModelComposed,
-    ModelNormal,
-    ModelSimple,
-    cached_property,
-    change_keys_js_to_python,
-    convert_js_args_to_python_args,
-    date,
-    datetime,
-    file_type,
-    none_type,
-    validate_get_composed_info,
-)
-
-
-class ImportUrl(ModelNormal):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-
-    Attributes:
-      allowed_values (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          with a capitalized key describing the allowed value and an allowed
-          value. These dicts store the allowed enum values.
-      attribute_map (dict): The key is attribute name
-          and the value is json key in definition.
-      discriminator_value_class_map (dict): A dict to go from the discriminator
-          variable value to the discriminator class name.
-      validations (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          that stores validations for max_length, min_length, max_items,
-          min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,
-          inclusive_minimum, and regex.
-      additional_properties_type (tuple): A tuple of classes accepted
-          as additional properties values.
-    """
-
-    allowed_values = {
-    }
-
-    validations = {
-        ('url',): {
-            'max_length': 4096,
-        },
-    }
-
-    additional_properties_type = None
-
-    _nullable = False
-
-    @cached_property
-    def openapi_types():
-        """
-        This must be a method because a model may have properties that are
-        of type self, this must run after the class is loaded
-
-        Returns
-            openapi_types (dict): The key is attribute name
-                and the value is attribute type.
-        """
-        return {
-            'url': (str,),  # noqa: E501
-            'table_name': (str,),  # noqa: E501
-            'repo_name': (str,),  # noqa: E501
-            'create_table_if_not_exists': (bool,),  # noqa: E501
-        }
-
-    @cached_property
-    def discriminator():
-        return None
-
-
-    attribute_map = {
-        'url': 'url',  # noqa: E501
-        'table_name': 'table_name',  # noqa: E501
-        'repo_name': 'repo_name',  # noqa: E501
-        'create_table_if_not_exists': 'create_table_if_not_exists',  # noqa: E501
-    }
-
-    _composed_schemas = {}
-
-    required_properties = set([
-        '_data_store',
-        '_check_type',
-        '_spec_property_naming',
-        '_path_to_item',
-        '_configuration',
-        '_visited_composed_classes',
-    ])
-
-    @convert_js_args_to_python_args
-    def __init__(self, url, table_name, repo_name, *args, **kwargs):  # noqa: E501
-        """ImportUrl - a model defined in OpenAPI
-
-        Args:
-            url (str):
-            table_name (str):
-            repo_name (str):
-
-        Keyword Args:
-            _check_type (bool): if True, values for parameters in openapi_types
-                                will be type checked and a TypeError will be
-                                raised if the wrong type is input.
-                                Defaults to True
-            _path_to_item (tuple/list): This is a list of keys or values to
-                                drill down to the model in received_data
-                                when deserializing a response
-            _spec_property_naming (bool): True if the variable names in the input data
-                                are serialized names, as specified in the OpenAPI document.
-                                False if the variable names in the input data
-                                are pythonic names, e.g. snake case (default)
-            _configuration (Configuration): the instance to use when
-                                deserializing a file_type parameter.
-                                If passed, type conversion is attempted
-                                If omitted no type conversion is done.
-            _visited_composed_classes (tuple): This stores a tuple of
-                                classes that we have traveled through so that
-                                if we see that class again we will not use its
-                                discriminator again.
-                                When traveling through a discriminator, the
-                                composed schema that is
-                                is traveled through is added to this set.
-                                For example if Animal has a discriminator
-                                petType and we pass in "Dog", and the class Dog
-                                allOf includes Animal, we move through Animal
-                                once using the discriminator, and pick Dog.
-                                Then in Dog, we will make an instance of the
-                                Animal class but this time we won't travel
-                                through its discriminator because we passed in
-                                _visited_composed_classes = (Animal,)
-            create_table_if_not_exists (bool): [optional] if omitted the server will use the default value of True  # noqa: E501
-        """
-
-        _check_type = kwargs.pop('_check_type', True)
-        _spec_property_naming = kwargs.pop('_spec_property_naming', False)
-        _path_to_item = kwargs.pop('_path_to_item', ())
-        _configuration = kwargs.pop('_configuration', None)
-        _visited_composed_classes = kwargs.pop('_visited_composed_classes', ())
-
-        if args:
-            raise ApiTypeError(
-                "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
-                    args,
-                    self.__class__.__name__,
-                ),
-                path_to_item=_path_to_item,
-                valid_classes=(self.__class__,),
-            )
-
-        self._data_store = {}
-        self._check_type = _check_type
-        self._spec_property_naming = _spec_property_naming
-        self._path_to_item = _path_to_item
-        self._configuration = _configuration
-        self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
-
-        self.url = url
-        self.table_name = table_name
-        self.repo_name = repo_name
-        for var_name, var_value in kwargs.items():
-            if var_name not in self.attribute_map and \
-                        self._configuration is not None and \
-                        self._configuration.discard_unknown_keys and \
-                        self.additional_properties_type is None:
-                # discard variable.
-                continue
-            setattr(self, var_name, var_value)
diff --git a/bitdotio/model/ingestion_result.py b/bitdotio/model/ingestion_result.py
deleted file mode 100644
index 8c6b545..0000000
--- a/bitdotio/model/ingestion_result.py
+++ /dev/null
@@ -1,191 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import re  # noqa: F401
-import sys  # noqa: F401
-
-from bitdotio.model_utils import (  # noqa: F401
-    ApiTypeError,
-    ModelComposed,
-    ModelNormal,
-    ModelSimple,
-    cached_property,
-    change_keys_js_to_python,
-    convert_js_args_to_python_args,
-    date,
-    datetime,
-    file_type,
-    none_type,
-    validate_get_composed_info,
-)
-
-
-class IngestionResult(ModelNormal):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-
-    Attributes:
-      allowed_values (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          with a capitalized key describing the allowed value and an allowed
-          value. These dicts store the allowed enum values.
-      attribute_map (dict): The key is attribute name
-          and the value is json key in definition.
-      discriminator_value_class_map (dict): A dict to go from the discriminator
-          variable value to the discriminator class name.
-      validations (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          that stores validations for max_length, min_length, max_items,
-          min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,
-          inclusive_minimum, and regex.
-      additional_properties_type (tuple): A tuple of classes accepted
-          as additional properties values.
-    """
-
-    allowed_values = {
-    }
-
-    validations = {
-    }
-
-    additional_properties_type = None
-
-    _nullable = False
-
-    @cached_property
-    def openapi_types():
-        """
-        This must be a method because a model may have properties that are
-        of type self, this must run after the class is loaded
-
-        Returns
-            openapi_types (dict): The key is attribute name
-                and the value is attribute type.
-        """
-        return {
-            'result': (str,),  # noqa: E501
-            'message': (str,),  # noqa: E501
-            'table_name': (str,),  # noqa: E501
-            'repo_name': (str,),  # noqa: E501
-            'job_id': (str,),  # noqa: E501
-            'file_name': (str,),  # noqa: E501
-            'url': (str,),  # noqa: E501
-        }
-
-    @cached_property
-    def discriminator():
-        return None
-
-
-    attribute_map = {
-        'result': 'result',  # noqa: E501
-        'message': 'message',  # noqa: E501
-        'table_name': 'table_name',  # noqa: E501
-        'repo_name': 'repo_name',  # noqa: E501
-        'job_id': 'job_id',  # noqa: E501
-        'file_name': 'file_name',  # noqa: E501
-        'url': 'url',  # noqa: E501
-    }
-
-    _composed_schemas = {}
-
-    required_properties = set([
-        '_data_store',
-        '_check_type',
-        '_spec_property_naming',
-        '_path_to_item',
-        '_configuration',
-        '_visited_composed_classes',
-    ])
-
-    @convert_js_args_to_python_args
-    def __init__(self, result, message, table_name, repo_name, job_id, *args, **kwargs):  # noqa: E501
-        """IngestionResult - a model defined in OpenAPI
-
-        Args:
-            result (str):
-            message (str):
-            table_name (str):
-            repo_name (str):
-            job_id (str):
-
-        Keyword Args:
-            _check_type (bool): if True, values for parameters in openapi_types
-                                will be type checked and a TypeError will be
-                                raised if the wrong type is input.
-                                Defaults to True
-            _path_to_item (tuple/list): This is a list of keys or values to
-                                drill down to the model in received_data
-                                when deserializing a response
-            _spec_property_naming (bool): True if the variable names in the input data
-                                are serialized names, as specified in the OpenAPI document.
-                                False if the variable names in the input data
-                                are pythonic names, e.g. snake case (default)
-            _configuration (Configuration): the instance to use when
-                                deserializing a file_type parameter.
-                                If passed, type conversion is attempted
-                                If omitted no type conversion is done.
-            _visited_composed_classes (tuple): This stores a tuple of
-                                classes that we have traveled through so that
-                                if we see that class again we will not use its
-                                discriminator again.
-                                When traveling through a discriminator, the
-                                composed schema that is
-                                is traveled through is added to this set.
-                                For example if Animal has a discriminator
-                                petType and we pass in "Dog", and the class Dog
-                                allOf includes Animal, we move through Animal
-                                once using the discriminator, and pick Dog.
-                                Then in Dog, we will make an instance of the
-                                Animal class but this time we won't travel
-                                through its discriminator because we passed in
-                                _visited_composed_classes = (Animal,)
-            file_name (str): [optional]  # noqa: E501
-            url (str): [optional]  # noqa: E501
-        """
-
-        _check_type = kwargs.pop('_check_type', True)
-        _spec_property_naming = kwargs.pop('_spec_property_naming', False)
-        _path_to_item = kwargs.pop('_path_to_item', ())
-        _configuration = kwargs.pop('_configuration', None)
-        _visited_composed_classes = kwargs.pop('_visited_composed_classes', ())
-
-        if args:
-            raise ApiTypeError(
-                "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
-                    args,
-                    self.__class__.__name__,
-                ),
-                path_to_item=_path_to_item,
-                valid_classes=(self.__class__,),
-            )
-
-        self._data_store = {}
-        self._check_type = _check_type
-        self._spec_property_naming = _spec_property_naming
-        self._path_to_item = _path_to_item
-        self._configuration = _configuration
-        self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
-
-        self.result = result
-        self.message = message
-        self.table_name = table_name
-        self.repo_name = repo_name
-        self.job_id = job_id
-        for var_name, var_value in kwargs.items():
-            if var_name not in self.attribute_map and \
-                        self._configuration is not None and \
-                        self._configuration.discard_unknown_keys and \
-                        self.additional_properties_type is None:
-                # discard variable.
-                continue
-            setattr(self, var_name, var_value)
diff --git a/bitdotio/model/ingestor_job.py b/bitdotio/model/ingestor_job.py
deleted file mode 100644
index bfb5a7c..0000000
--- a/bitdotio/model/ingestor_job.py
+++ /dev/null
@@ -1,193 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import re  # noqa: F401
-import sys  # noqa: F401
-
-from bitdotio.model_utils import (  # noqa: F401
-    ApiTypeError,
-    ModelComposed,
-    ModelNormal,
-    ModelSimple,
-    cached_property,
-    change_keys_js_to_python,
-    convert_js_args_to_python_args,
-    date,
-    datetime,
-    file_type,
-    none_type,
-    validate_get_composed_info,
-)
-
-
-class IngestorJob(ModelNormal):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-
-    Attributes:
-      allowed_values (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          with a capitalized key describing the allowed value and an allowed
-          value. These dicts store the allowed enum values.
-      attribute_map (dict): The key is attribute name
-          and the value is json key in definition.
-      discriminator_value_class_map (dict): A dict to go from the discriminator
-          variable value to the discriminator class name.
-      validations (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          that stores validations for max_length, min_length, max_items,
-          min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,
-          inclusive_minimum, and regex.
-      additional_properties_type (tuple): A tuple of classes accepted
-          as additional properties values.
-    """
-
-    allowed_values = {
-    }
-
-    validations = {
-    }
-
-    additional_properties_type = None
-
-    _nullable = False
-
-    @cached_property
-    def openapi_types():
-        """
-        This must be a method because a model may have properties that are
-        of type self, this must run after the class is loaded
-
-        Returns
-            openapi_types (dict): The key is attribute name
-                and the value is attribute type.
-        """
-        return {
-            'job_id': (str,),  # noqa: E501
-            'state': (str,),  # noqa: E501
-            'status_message': (str,),  # noqa: E501
-            'retries': (int,),  # noqa: E501
-            'file_type': (str, none_type,),  # noqa: E501
-            'original_filename': (str,),  # noqa: E501
-            'repo_name': (str,),  # noqa: E501
-            'table_name': (str,),  # noqa: E501
-        }
-
-    @cached_property
-    def discriminator():
-        return None
-
-
-    attribute_map = {
-        'job_id': 'job_id',  # noqa: E501
-        'state': 'state',  # noqa: E501
-        'status_message': 'status_message',  # noqa: E501
-        'retries': 'retries',  # noqa: E501
-        'file_type': 'file_type',  # noqa: E501
-        'original_filename': 'original_filename',  # noqa: E501
-        'repo_name': 'repo_name',  # noqa: E501
-        'table_name': 'table_name',  # noqa: E501
-    }
-
-    _composed_schemas = {}
-
-    required_properties = set([
-        '_data_store',
-        '_check_type',
-        '_spec_property_naming',
-        '_path_to_item',
-        '_configuration',
-        '_visited_composed_classes',
-    ])
-
-    @convert_js_args_to_python_args
-    def __init__(self, job_id, state, status_message, retries, *args, **kwargs):  # noqa: E501
-        """IngestorJob - a model defined in OpenAPI
-
-        Args:
-            job_id (str):
-            state (str):
-            status_message (str):
-            retries (int):
-
-        Keyword Args:
-            _check_type (bool): if True, values for parameters in openapi_types
-                                will be type checked and a TypeError will be
-                                raised if the wrong type is input.
-                                Defaults to True
-            _path_to_item (tuple/list): This is a list of keys or values to
-                                drill down to the model in received_data
-                                when deserializing a response
-            _spec_property_naming (bool): True if the variable names in the input data
-                                are serialized names, as specified in the OpenAPI document.
-                                False if the variable names in the input data
-                                are pythonic names, e.g. snake case (default)
-            _configuration (Configuration): the instance to use when
-                                deserializing a file_type parameter.
-                                If passed, type conversion is attempted
-                                If omitted no type conversion is done.
-            _visited_composed_classes (tuple): This stores a tuple of
-                                classes that we have traveled through so that
-                                if we see that class again we will not use its
-                                discriminator again.
-                                When traveling through a discriminator, the
-                                composed schema that is
-                                is traveled through is added to this set.
-                                For example if Animal has a discriminator
-                                petType and we pass in "Dog", and the class Dog
-                                allOf includes Animal, we move through Animal
-                                once using the discriminator, and pick Dog.
-                                Then in Dog, we will make an instance of the
-                                Animal class but this time we won't travel
-                                through its discriminator because we passed in
-                                _visited_composed_classes = (Animal,)
-            file_type (str, none_type): [optional]  # noqa: E501
-            original_filename (str): [optional]  # noqa: E501
-            repo_name (str): [optional]  # noqa: E501
-            table_name (str): [optional]  # noqa: E501
-        """
-
-        _check_type = kwargs.pop('_check_type', True)
-        _spec_property_naming = kwargs.pop('_spec_property_naming', False)
-        _path_to_item = kwargs.pop('_path_to_item', ())
-        _configuration = kwargs.pop('_configuration', None)
-        _visited_composed_classes = kwargs.pop('_visited_composed_classes', ())
-
-        if args:
-            raise ApiTypeError(
-                "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
-                    args,
-                    self.__class__.__name__,
-                ),
-                path_to_item=_path_to_item,
-                valid_classes=(self.__class__,),
-            )
-
-        self._data_store = {}
-        self._check_type = _check_type
-        self._spec_property_naming = _spec_property_naming
-        self._path_to_item = _path_to_item
-        self._configuration = _configuration
-        self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
-
-        self.job_id = job_id
-        self.state = state
-        self.status_message = status_message
-        self.retries = retries
-        for var_name, var_value in kwargs.items():
-            if var_name not in self.attribute_map and \
-                        self._configuration is not None and \
-                        self._configuration.discard_unknown_keys and \
-                        self.additional_properties_type is None:
-                # discard variable.
-                continue
-            setattr(self, var_name, var_value)
diff --git a/bitdotio/model/query.py b/bitdotio/model/query.py
deleted file mode 100644
index c7e44e6..0000000
--- a/bitdotio/model/query.py
+++ /dev/null
@@ -1,175 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import re  # noqa: F401
-import sys  # noqa: F401
-
-from bitdotio.model_utils import (  # noqa: F401
-    ApiTypeError,
-    ModelComposed,
-    ModelNormal,
-    ModelSimple,
-    cached_property,
-    change_keys_js_to_python,
-    convert_js_args_to_python_args,
-    date,
-    datetime,
-    file_type,
-    none_type,
-    validate_get_composed_info,
-)
-
-
-class Query(ModelNormal):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-
-    Attributes:
-      allowed_values (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          with a capitalized key describing the allowed value and an allowed
-          value. These dicts store the allowed enum values.
-      attribute_map (dict): The key is attribute name
-          and the value is json key in definition.
-      discriminator_value_class_map (dict): A dict to go from the discriminator
-          variable value to the discriminator class name.
-      validations (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          that stores validations for max_length, min_length, max_items,
-          min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,
-          inclusive_minimum, and regex.
-      additional_properties_type (tuple): A tuple of classes accepted
-          as additional properties values.
-    """
-
-    allowed_values = {
-    }
-
-    validations = {
-    }
-
-    additional_properties_type = None
-
-    _nullable = False
-
-    @cached_property
-    def openapi_types():
-        """
-        This must be a method because a model may have properties that are
-        of type self, this must run after the class is loaded
-
-        Returns
-            openapi_types (dict): The key is attribute name
-                and the value is attribute type.
-        """
-        return {
-            'query_string': (str,),  # noqa: E501
-            'fields': ({str: (bool, date, datetime, dict, float, int, list, str, none_type)},),  # noqa: E501
-            'data': ([bool, date, datetime, dict, float, int, list, str, none_type],),  # noqa: E501
-        }
-
-    @cached_property
-    def discriminator():
-        return None
-
-
-    attribute_map = {
-        'query_string': 'query_string',  # noqa: E501
-        'fields': 'fields',  # noqa: E501
-        'data': 'data',  # noqa: E501
-    }
-
-    _composed_schemas = {}
-
-    required_properties = set([
-        '_data_store',
-        '_check_type',
-        '_spec_property_naming',
-        '_path_to_item',
-        '_configuration',
-        '_visited_composed_classes',
-    ])
-
-    @convert_js_args_to_python_args
-    def __init__(self, query_string, *args, **kwargs):  # noqa: E501
-        """Query - a model defined in OpenAPI
-
-        Args:
-            query_string (str):
-
-        Keyword Args:
-            _check_type (bool): if True, values for parameters in openapi_types
-                                will be type checked and a TypeError will be
-                                raised if the wrong type is input.
-                                Defaults to True
-            _path_to_item (tuple/list): This is a list of keys or values to
-                                drill down to the model in received_data
-                                when deserializing a response
-            _spec_property_naming (bool): True if the variable names in the input data
-                                are serialized names, as specified in the OpenAPI document.
-                                False if the variable names in the input data
-                                are pythonic names, e.g. snake case (default)
-            _configuration (Configuration): the instance to use when
-                                deserializing a file_type parameter.
-                                If passed, type conversion is attempted
-                                If omitted no type conversion is done.
-            _visited_composed_classes (tuple): This stores a tuple of
-                                classes that we have traveled through so that
-                                if we see that class again we will not use its
-                                discriminator again.
-                                When traveling through a discriminator, the
-                                composed schema that is
-                                is traveled through is added to this set.
-                                For example if Animal has a discriminator
-                                petType and we pass in "Dog", and the class Dog
-                                allOf includes Animal, we move through Animal
-                                once using the discriminator, and pick Dog.
-                                Then in Dog, we will make an instance of the
-                                Animal class but this time we won't travel
-                                through its discriminator because we passed in
-                                _visited_composed_classes = (Animal,)
-            fields ({str: (bool, date, datetime, dict, float, int, list, str, none_type)}): [optional]  # noqa: E501
-            data ([bool, date, datetime, dict, float, int, list, str, none_type]): [optional]  # noqa: E501
-        """
-
-        _check_type = kwargs.pop('_check_type', True)
-        _spec_property_naming = kwargs.pop('_spec_property_naming', False)
-        _path_to_item = kwargs.pop('_path_to_item', ())
-        _configuration = kwargs.pop('_configuration', None)
-        _visited_composed_classes = kwargs.pop('_visited_composed_classes', ())
-
-        if args:
-            raise ApiTypeError(
-                "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
-                    args,
-                    self.__class__.__name__,
-                ),
-                path_to_item=_path_to_item,
-                valid_classes=(self.__class__,),
-            )
-
-        self._data_store = {}
-        self._check_type = _check_type
-        self._spec_property_naming = _spec_property_naming
-        self._path_to_item = _path_to_item
-        self._configuration = _configuration
-        self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
-
-        self.query_string = query_string
-        for var_name, var_value in kwargs.items():
-            if var_name not in self.attribute_map and \
-                        self._configuration is not None and \
-                        self._configuration.discard_unknown_keys and \
-                        self.additional_properties_type is None:
-                # discard variable.
-                continue
-            setattr(self, var_name, var_value)
diff --git a/bitdotio/model/repo.py b/bitdotio/model/repo.py
deleted file mode 100644
index b32b25d..0000000
--- a/bitdotio/model/repo.py
+++ /dev/null
@@ -1,190 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import re  # noqa: F401
-import sys  # noqa: F401
-
-from bitdotio.model_utils import (  # noqa: F401
-    ApiTypeError,
-    ModelComposed,
-    ModelNormal,
-    ModelSimple,
-    cached_property,
-    change_keys_js_to_python,
-    convert_js_args_to_python_args,
-    date,
-    datetime,
-    file_type,
-    none_type,
-    validate_get_composed_info,
-)
-
-
-class Repo(ModelNormal):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-
-    Attributes:
-      allowed_values (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          with a capitalized key describing the allowed value and an allowed
-          value. These dicts store the allowed enum values.
-      attribute_map (dict): The key is attribute name
-          and the value is json key in definition.
-      discriminator_value_class_map (dict): A dict to go from the discriminator
-          variable value to the discriminator class name.
-      validations (dict): The key is the tuple path to the attribute
-          and the for var_name this is (var_name,). The value is a dict
-          that stores validations for max_length, min_length, max_items,
-          min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum,
-          inclusive_minimum, and regex.
-      additional_properties_type (tuple): A tuple of classes accepted
-          as additional properties values.
-    """
-
-    allowed_values = {
-    }
-
-    validations = {
-        ('name',): {
-            'max_length': 200,
-        },
-        ('description',): {
-            'max_length': 200,
-        },
-    }
-
-    additional_properties_type = None
-
-    _nullable = False
-
-    @cached_property
-    def openapi_types():
-        """
-        This must be a method because a model may have properties that are
-        of type self, this must run after the class is loaded
-
-        Returns
-            openapi_types (dict): The key is attribute name
-                and the value is attribute type.
-        """
-        return {
-            'name': (str,),  # noqa: E501
-            'url': (str,),  # noqa: E501
-            'description': (str,),  # noqa: E501
-            'documentation': (str,),  # noqa: E501
-            'bytes': (int,),  # noqa: E501
-            'is_private': (bool,),  # noqa: E501
-        }
-
-    @cached_property
-    def discriminator():
-        return None
-
-
-    attribute_map = {
-        'name': 'name',  # noqa: E501
-        'url': 'url',  # noqa: E501
-        'description': 'description',  # noqa: E501
-        'documentation': 'documentation',  # noqa: E501
-        'bytes': 'bytes',  # noqa: E501
-        'is_private': 'is_private',  # noqa: E501
-    }
-
-    _composed_schemas = {}
-
-    required_properties = set([
-        '_data_store',
-        '_check_type',
-        '_spec_property_naming',
-        '_path_to_item',
-        '_configuration',
-        '_visited_composed_classes',
-    ])
-
-    @convert_js_args_to_python_args
-    def __init__(self, name, *args, **kwargs):  # noqa: E501
-        """Repo - a model defined in OpenAPI
-
-        Args:
-            name (str):
-
-        Keyword Args:
-            _check_type (bool): if True, values for parameters in openapi_types
-                                will be type checked and a TypeError will be
-                                raised if the wrong type is input.
-                                Defaults to True
-            _path_to_item (tuple/list): This is a list of keys or values to
-                                drill down to the model in received_data
-                                when deserializing a response
-            _spec_property_naming (bool): True if the variable names in the input data
-                                are serialized names, as specified in the OpenAPI document.
-                                False if the variable names in the input data
-                                are pythonic names, e.g. snake case (default)
-            _configuration (Configuration): the instance to use when
-                                deserializing a file_type parameter.
-                                If passed, type conversion is attempted
-                                If omitted no type conversion is done.
-            _visited_composed_classes (tuple): This stores a tuple of
-                                classes that we have traveled through so that
-                                if we see that class again we will not use its
-                                discriminator again.
-                                When traveling through a discriminator, the
-                                composed schema that is
-                                is traveled through is added to this set.
-                                For example if Animal has a discriminator
-                                petType and we pass in "Dog", and the class Dog
-                                allOf includes Animal, we move through Animal
-                                once using the discriminator, and pick Dog.
-                                Then in Dog, we will make an instance of the
-                                Animal class but this time we won't travel
-                                through its discriminator because we passed in
-                                _visited_composed_classes = (Animal,)
-            url (str): [optional]  # noqa: E501
-            description (str): [optional]  # noqa: E501
-            documentation (str): [optional]  # noqa: E501
-            bytes (int): [optional]  # noqa: E501
-            is_private (bool): [optional]  # noqa: E501
-        """
-
-        _check_type = kwargs.pop('_check_type', True)
-        _spec_property_naming = kwargs.pop('_spec_property_naming', False)
-        _path_to_item = kwargs.pop('_path_to_item', ())
-        _configuration = kwargs.pop('_configuration', None)
-        _visited_composed_classes = kwargs.pop('_visited_composed_classes', ())
-
-        if args:
-            raise ApiTypeError(
-                "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % (
-                    args,
-                    self.__class__.__name__,
-                ),
-                path_to_item=_path_to_item,
-                valid_classes=(self.__class__,),
-            )
-
-        self._data_store = {}
-        self._check_type = _check_type
-        self._spec_property_naming = _spec_property_naming
-        self._path_to_item = _path_to_item
-        self._configuration = _configuration
-        self._visited_composed_classes = _visited_composed_classes + (self.__class__,)
-
-        self.name = name
-        for var_name, var_value in kwargs.items():
-            if var_name not in self.attribute_map and \
-                        self._configuration is not None and \
-                        self._configuration.discard_unknown_keys and \
-                        self.additional_properties_type is None:
-                # discard variable.
-                continue
-            setattr(self, var_name, var_value)
diff --git a/bitdotio/model_utils.py b/bitdotio/model_utils.py
deleted file mode 100644
index 1a11514..0000000
--- a/bitdotio/model_utils.py
+++ /dev/null
@@ -1,1896 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-from datetime import date, datetime  # noqa: F401
-import inspect
-import io
-import os
-import pprint
-import re
-import tempfile
-
-from dateutil.parser import parse
-
-from bitdotio.exceptions import (
-    ApiKeyError,
-    ApiAttributeError,
-    ApiTypeError,
-    ApiValueError,
-)
-
-none_type = type(None)
-file_type = io.IOBase
-
-
-class cached_property(object):
-    # this caches the result of the function call for fn with no inputs
-    # use this as a decorator on fuction methods that you want converted
-    # into cached properties
-    result_key = '_results'
-
-    def __init__(self, fn):
-        self._fn = fn
-
-    def __get__(self, instance, cls=None):
-        if self.result_key in vars(self):
-            return vars(self)[self.result_key]
-        else:
-            result = self._fn()
-            setattr(self, self.result_key, result)
-            return result
-
-
-PRIMITIVE_TYPES = (list, float, int, bool, datetime, date, str, file_type)
-
-def allows_single_value_input(cls):
-    """
-    This function returns True if the input composed schema model or any
-    descendant model allows a value only input
-    This is true for cases where oneOf contains items like:
-    oneOf:
-      - float
-      - NumberWithValidation
-      - StringEnum
-      - ArrayModel
-      - null
-    TODO: lru_cache this
-    """
-    if (
-        issubclass(cls, ModelSimple) or
-        cls in PRIMITIVE_TYPES
-    ):
-        return True
-    elif issubclass(cls, ModelComposed):
-        if not cls._composed_schemas['oneOf']:
-            return False
-        return any(allows_single_value_input(c) for c in cls._composed_schemas['oneOf'])
-    return False
-
-def composed_model_input_classes(cls):
-    """
-    This function returns a list of the possible models that can be accepted as
-    inputs.
-    TODO: lru_cache this
-    """
-    if issubclass(cls, ModelSimple) or cls in PRIMITIVE_TYPES:
-        return [cls]
-    elif issubclass(cls, ModelNormal):
-        if cls.discriminator is None:
-            return [cls]
-        else:
-            return get_discriminated_classes(cls)
-    elif issubclass(cls, ModelComposed):
-        if not cls._composed_schemas['oneOf']:
-            return []
-        if cls.discriminator is None:
-            input_classes = []
-            for c in cls._composed_schemas['oneOf']:
-                input_classes.extend(composed_model_input_classes(c))
-            return input_classes
-        else:
-            return get_discriminated_classes(cls)
-    return []
-
-
-class OpenApiModel(object):
-    """The base class for all OpenAPIModels"""
-
-    def set_attribute(self, name, value):
-        # this is only used to set properties on self
-
-        path_to_item = []
-        if self._path_to_item:
-            path_to_item.extend(self._path_to_item)
-        path_to_item.append(name)
-
-        if name in self.openapi_types:
-            required_types_mixed = self.openapi_types[name]
-        elif self.additional_properties_type is None:
-            raise ApiAttributeError(
-                "{0} has no attribute '{1}'".format(
-                    type(self).__name__, name),
-                path_to_item
-            )
-        elif self.additional_properties_type is not None:
-            required_types_mixed = self.additional_properties_type
-
-        if get_simple_class(name) != str:
-            error_msg = type_error_message(
-                var_name=name,
-                var_value=name,
-                valid_classes=(str,),
-                key_type=True
-            )
-            raise ApiTypeError(
-                error_msg,
-                path_to_item=path_to_item,
-                valid_classes=(str,),
-                key_type=True
-            )
-
-        if self._check_type:
-            value = validate_and_convert_types(
-                value, required_types_mixed, path_to_item, self._spec_property_naming,
-                self._check_type, configuration=self._configuration)
-        if (name,) in self.allowed_values:
-            check_allowed_values(
-                self.allowed_values,
-                (name,),
-                value
-            )
-        if (name,) in self.validations:
-            check_validations(
-                self.validations,
-                (name,),
-                value,
-                self._configuration
-            )
-        self.__dict__['_data_store'][name] = value
-
-    def __repr__(self):
-        """For `print` and `pprint`"""
-        return self.to_str()
-
-    def __ne__(self, other):
-        """Returns true if both objects are not equal"""
-        return not self == other
-
-    def __setattr__(self, attr, value):
-        """set the value of an attribute using dot notation: `instance.attr = val`"""
-        self[attr] = value
-
-    def __getattr__(self, attr):
-        """get the value of an attribute using dot notation: `instance.attr`"""
-        return self.__getitem__(attr)
-
-    def __new__(cls, *args, **kwargs):
-        # this function uses the discriminator to
-        # pick a new schema/class to instantiate because a discriminator
-        # propertyName value was passed in
-
-        if len(args) == 1:
-            arg = args[0]
-            if arg is None and is_type_nullable(cls):
-                # The input data is the 'null' value and the type is nullable.
-                return None
-
-            if issubclass(cls, ModelComposed) and allows_single_value_input(cls):
-                model_kwargs = {}
-                oneof_instance = get_oneof_instance(cls, model_kwargs, kwargs, model_arg=arg)
-                return oneof_instance
-
-
-        visited_composed_classes = kwargs.get('_visited_composed_classes', ())
-        if (
-            cls.discriminator is None or
-            cls in visited_composed_classes
-        ):
-            # Use case 1: this openapi schema (cls) does not have a discriminator
-            # Use case 2: we have already visited this class before and are sure that we
-            # want to instantiate it this time. We have visited this class deserializing
-            # a payload with a discriminator. During that process we traveled through
-            # this class but did not make an instance of it. Now we are making an
-            # instance of a composed class which contains cls in it, so this time make an instance of cls.
-            #
-            # Here's an example of use case 2: If Animal has a discriminator
-            # petType and we pass in "Dog", and the class Dog
-            # allOf includes Animal, we move through Animal
-            # once using the discriminator, and pick Dog.
-            # Then in the composed schema dog Dog, we will make an instance of the
-            # Animal class (because Dal has allOf: Animal) but this time we won't travel
-            # through Animal's discriminator because we passed in
-            # _visited_composed_classes = (Animal,)
-
-            return super(OpenApiModel, cls).__new__(cls)
-
-        # Get the name and value of the discriminator property.
-        # The discriminator name is obtained from the discriminator meta-data
-        # and the discriminator value is obtained from the input data.
-        discr_propertyname_py = list(cls.discriminator.keys())[0]
-        discr_propertyname_js = cls.attribute_map[discr_propertyname_py]
-        if discr_propertyname_js in kwargs:
-            discr_value = kwargs[discr_propertyname_js]
-        elif discr_propertyname_py in kwargs:
-            discr_value = kwargs[discr_propertyname_py]
-        else:
-            # The input data does not contain the discriminator property.
-            path_to_item = kwargs.get('_path_to_item', ())
-            raise ApiValueError(
-                "Cannot deserialize input data due to missing discriminator. "
-                "The discriminator property '%s' is missing at path: %s" %
-                (discr_propertyname_js, path_to_item)
-            )
-
-        # Implementation note: the last argument to get_discriminator_class
-        # is a list of visited classes. get_discriminator_class may recursively
-        # call itself and update the list of visited classes, and the initial
-        # value must be an empty list. Hence not using 'visited_composed_classes'
-        new_cls = get_discriminator_class(
-                    cls, discr_propertyname_py, discr_value, [])
-        if new_cls is None:
-            path_to_item = kwargs.get('_path_to_item', ())
-            disc_prop_value = kwargs.get(
-                discr_propertyname_js, kwargs.get(discr_propertyname_py))
-            raise ApiValueError(
-                "Cannot deserialize input data due to invalid discriminator "
-                "value. The OpenAPI document has no mapping for discriminator "
-                "property '%s'='%s' at path: %s" %
-                (discr_propertyname_js, disc_prop_value, path_to_item)
-            )
-
-        if new_cls in visited_composed_classes:
-            # if we are making an instance of a composed schema Descendent
-            # which allOf includes Ancestor, then Ancestor contains
-            # a discriminator that includes Descendent.
-            # So if we make an instance of Descendent, we have to make an
-            # instance of Ancestor to hold the allOf properties.
-            # This code detects that use case and makes the instance of Ancestor
-            # For example:
-            # When making an instance of Dog, _visited_composed_classes = (Dog,)
-            # then we make an instance of Animal to include in dog._composed_instances
-            # so when we are here, cls is Animal
-            # cls.discriminator != None
-            # cls not in _visited_composed_classes
-            # new_cls = Dog
-            # but we know we know that we already have Dog
-            # because it is in visited_composed_classes
-            # so make Animal here
-            return super(OpenApiModel, cls).__new__(cls)
-
-        # Build a list containing all oneOf and anyOf descendants.
-        oneof_anyof_classes = None
-        if cls._composed_schemas is not None:
-            oneof_anyof_classes = (
-                cls._composed_schemas.get('oneOf', ()) +
-                cls._composed_schemas.get('anyOf', ()))
-        oneof_anyof_child = new_cls in oneof_anyof_classes
-        kwargs['_visited_composed_classes'] = visited_composed_classes + (cls,)
-
-        if cls._composed_schemas.get('allOf') and oneof_anyof_child:
-            # Validate that we can make self because when we make the
-            # new_cls it will not include the allOf validations in self
-            self_inst = super(OpenApiModel, cls).__new__(cls)
-            self_inst.__init__(*args, **kwargs)
-
-        new_inst = new_cls.__new__(new_cls, *args, **kwargs)
-        new_inst.__init__(*args, **kwargs)
-        return new_inst
-
-
-class ModelSimple(OpenApiModel):
-    """the parent class of models whose type != object in their
-    swagger/openapi"""
-
-    def __setitem__(self, name, value):
-        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
-        if name in self.required_properties:
-            self.__dict__[name] = value
-            return
-
-        self.set_attribute(name, value)
-
-    def get(self, name, default=None):
-        """returns the value of an attribute or some default value if the attribute was not set"""
-        if name in self.required_properties:
-            return self.__dict__[name]
-
-        return self.__dict__['_data_store'].get(name, default)
-
-    def __getitem__(self, name):
-        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
-        if name in self:
-            return self.get(name)
-
-        raise ApiAttributeError(
-            "{0} has no attribute '{1}'".format(
-                type(self).__name__, name),
-            [e for e in [self._path_to_item, name] if e]
-        )
-
-    def __contains__(self, name):
-        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
-        if name in self.required_properties:
-            return name in self.__dict__
-
-        return name in self.__dict__['_data_store']
-
-    def to_str(self):
-        """Returns the string representation of the model"""
-        return str(self.value)
-
-    def __eq__(self, other):
-        """Returns true if both objects are equal"""
-        if not isinstance(other, self.__class__):
-            return False
-
-        this_val = self._data_store['value']
-        that_val = other._data_store['value']
-        types = set()
-        types.add(this_val.__class__)
-        types.add(that_val.__class__)
-        vals_equal = this_val == that_val
-        return vals_equal
-
-
-class ModelNormal(OpenApiModel):
-    """the parent class of models whose type == object in their
-    swagger/openapi"""
-
-    def __setitem__(self, name, value):
-        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
-        if name in self.required_properties:
-            self.__dict__[name] = value
-            return
-
-        self.set_attribute(name, value)
-
-    def get(self, name, default=None):
-        """returns the value of an attribute or some default value if the attribute was not set"""
-        if name in self.required_properties:
-            return self.__dict__[name]
-
-        return self.__dict__['_data_store'].get(name, default)
-
-    def __getitem__(self, name):
-        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
-        if name in self:
-            return self.get(name)
-
-        raise ApiAttributeError(
-            "{0} has no attribute '{1}'".format(
-                type(self).__name__, name),
-            [e for e in [self._path_to_item, name] if e]
-        )
-
-    def __contains__(self, name):
-        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
-        if name in self.required_properties:
-            return name in self.__dict__
-
-        return name in self.__dict__['_data_store']
-
-    def to_dict(self):
-        """Returns the model properties as a dict"""
-        return model_to_dict(self, serialize=False)
-
-    def to_str(self):
-        """Returns the string representation of the model"""
-        return pprint.pformat(self.to_dict())
-
-    def __eq__(self, other):
-        """Returns true if both objects are equal"""
-        if not isinstance(other, self.__class__):
-            return False
-
-        if not set(self._data_store.keys()) == set(other._data_store.keys()):
-            return False
-        for _var_name, this_val in self._data_store.items():
-            that_val = other._data_store[_var_name]
-            types = set()
-            types.add(this_val.__class__)
-            types.add(that_val.__class__)
-            vals_equal = this_val == that_val
-            if not vals_equal:
-                return False
-        return True
-
-
-class ModelComposed(OpenApiModel):
-    """the parent class of models whose type == object in their
-    swagger/openapi and have oneOf/allOf/anyOf
-
-    When one sets a property we use var_name_to_model_instances to store the value in
-    the correct class instances + run any type checking + validation code.
-    When one gets a property we use var_name_to_model_instances to get the value
-    from the correct class instances.
-    This allows multiple composed schemas to contain the same property with additive
-    constraints on the value.
-
-    _composed_schemas (dict) stores the anyOf/allOf/oneOf classes
-    key (str): allOf/oneOf/anyOf
-    value (list): the classes in the XOf definition.
-        Note: none_type can be included when the openapi document version >= 3.1.0
-    _composed_instances (list): stores a list of instances of the composed schemas
-    defined in _composed_schemas. When properties are accessed in the self instance,
-    they are returned from the self._data_store or the data stores in the instances
-    in self._composed_schemas
-    _var_name_to_model_instances (dict): maps between a variable name on self and
-    the composed instances (self included) which contain that data
-    key (str): property name
-    value (list): list of class instances, self or instances in _composed_instances
-    which contain the value that the key is referring to.
-    """
-
-    def __setitem__(self, name, value):
-        """set the value of an attribute using square-bracket notation: `instance[attr] = val`"""
-        if name in self.required_properties:
-            self.__dict__[name] = value
-            return
-
-        # set the attribute on the correct instance
-        model_instances = self._var_name_to_model_instances.get(
-            name, self._additional_properties_model_instances)
-        if model_instances:
-            for model_instance in model_instances:
-                if model_instance == self:
-                    self.set_attribute(name, value)
-                else:
-                    setattr(model_instance, name, value)
-                if name not in self._var_name_to_model_instances:
-                    # we assigned an additional property
-                    self.__dict__['_var_name_to_model_instances'][name] = (
-                        model_instance
-                    )
-            return None
-
-        raise ApiAttributeError(
-            "{0} has no attribute '{1}'".format(
-                type(self).__name__, name),
-            [e for e in [self._path_to_item, name] if e]
-        )
-
-    __unset_attribute_value__ = object()
-
-    def get(self, name, default=None):
-        """returns the value of an attribute or some default value if the attribute was not set"""
-        if name in self.required_properties:
-            return self.__dict__[name]
-
-        # get the attribute from the correct instance
-        model_instances = self._var_name_to_model_instances.get(
-            name, self._additional_properties_model_instances)
-        values = []
-        # A composed model stores child (oneof/anyOf/allOf) models under
-        # self._var_name_to_model_instances. A named property can exist in
-        # multiple child models. If the property is present in more than one
-        # child model, the value must be the same across all the child models.
-        if model_instances:
-            for model_instance in model_instances:
-                if name in model_instance._data_store:
-                    v = model_instance._data_store[name]
-                    if v not in values:
-                        values.append(v)
-        len_values = len(values)
-        if len_values == 0:
-            return default
-        elif len_values == 1:
-            return values[0]
-        elif len_values > 1:
-            raise ApiValueError(
-                "Values stored for property {0} in {1} differ when looking "
-                "at self and self's composed instances. All values must be "
-                "the same".format(name, type(self).__name__),
-                [e for e in [self._path_to_item, name] if e]
-            )
-
-    def __getitem__(self, name):
-        """get the value of an attribute using square-bracket notation: `instance[attr]`"""
-        value = self.get(name, self.__unset_attribute_value__)
-        if value is self.__unset_attribute_value__:
-            raise ApiAttributeError(
-                "{0} has no attribute '{1}'".format(
-                    type(self).__name__, name),
-                    [e for e in [self._path_to_item, name] if e]
-            )
-        return value
-
-    def __contains__(self, name):
-        """used by `in` operator to check if an attrbute value was set in an instance: `'attr' in instance`"""
-
-        if name in self.required_properties:
-            return name in self.__dict__
-
-        model_instances = self._var_name_to_model_instances.get(
-            name, self._additional_properties_model_instances)
-
-        if model_instances:
-            for model_instance in model_instances:
-                if name in model_instance._data_store:
-                    return True
-
-        return False
-
-    def to_dict(self):
-        """Returns the model properties as a dict"""
-        return model_to_dict(self, serialize=False)
-
-    def to_str(self):
-        """Returns the string representation of the model"""
-        return pprint.pformat(self.to_dict())
-
-    def __eq__(self, other):
-        """Returns true if both objects are equal"""
-        if not isinstance(other, self.__class__):
-            return False
-
-        if not set(self._data_store.keys()) == set(other._data_store.keys()):
-            return False
-        for _var_name, this_val in self._data_store.items():
-            that_val = other._data_store[_var_name]
-            types = set()
-            types.add(this_val.__class__)
-            types.add(that_val.__class__)
-            vals_equal = this_val == that_val
-            if not vals_equal:
-                return False
-        return True
-
-
-COERCION_INDEX_BY_TYPE = {
-    ModelComposed: 0,
-    ModelNormal: 1,
-    ModelSimple: 2,
-    none_type: 3,    # The type of 'None'.
-    list: 4,
-    dict: 5,
-    float: 6,
-    int: 7,
-    bool: 8,
-    datetime: 9,
-    date: 10,
-    str: 11,
-    file_type: 12,   # 'file_type' is an alias for the built-in 'file' or 'io.IOBase' type.
-}
-
-# these are used to limit what type conversions we try to do
-# when we have a valid type already and we want to try converting
-# to another type
-UPCONVERSION_TYPE_PAIRS = (
-    (str, datetime),
-    (str, date),
-    (int, float),             # A float may be serialized as an integer, e.g. '3' is a valid serialized float.
-    (list, ModelComposed),
-    (dict, ModelComposed),
-    (str, ModelComposed),
-    (int, ModelComposed),
-    (float, ModelComposed),
-    (list, ModelComposed),
-    (list, ModelNormal),
-    (dict, ModelNormal),
-    (str, ModelSimple),
-    (int, ModelSimple),
-    (float, ModelSimple),
-    (list, ModelSimple),
-)
-
-COERCIBLE_TYPE_PAIRS = {
-    False: (  # client instantiation of a model with client data
-        # (dict, ModelComposed),
-        # (list, ModelComposed),
-        # (dict, ModelNormal),
-        # (list, ModelNormal),
-        # (str, ModelSimple),
-        # (int, ModelSimple),
-        # (float, ModelSimple),
-        # (list, ModelSimple),
-        # (str, int),
-        # (str, float),
-        # (str, datetime),
-        # (str, date),
-        # (int, str),
-        # (float, str),
-    ),
-    True: (  # server -> client data
-        (dict, ModelComposed),
-        (list, ModelComposed),
-        (dict, ModelNormal),
-        (list, ModelNormal),
-        (str, ModelSimple),
-        (int, ModelSimple),
-        (float, ModelSimple),
-        (list, ModelSimple),
-        # (str, int),
-        # (str, float),
-        (str, datetime),
-        (str, date),
-        # (int, str),
-        # (float, str),
-        (str, file_type)
-    ),
-}
-
-
-def get_simple_class(input_value):
-    """Returns an input_value's simple class that we will use for type checking
-    Python2:
-    float and int will return int, where int is the python3 int backport
-    str and unicode will return str, where str is the python3 str backport
-    Note: float and int ARE both instances of int backport
-    Note: str_py2 and unicode_py2 are NOT both instances of str backport
-
-    Args:
-        input_value (class/class_instance): the item for which we will return
-                                            the simple class
-    """
-    if isinstance(input_value, type):
-        # input_value is a class
-        return input_value
-    elif isinstance(input_value, tuple):
-        return tuple
-    elif isinstance(input_value, list):
-        return list
-    elif isinstance(input_value, dict):
-        return dict
-    elif isinstance(input_value, none_type):
-        return none_type
-    elif isinstance(input_value, file_type):
-        return file_type
-    elif isinstance(input_value, bool):
-        # this must be higher than the int check because
-        # isinstance(True, int) == True
-        return bool
-    elif isinstance(input_value, int):
-        return int
-    elif isinstance(input_value, datetime):
-        # this must be higher than the date check because
-        # isinstance(datetime_instance, date) == True
-        return datetime
-    elif isinstance(input_value, date):
-        return date
-    elif isinstance(input_value, str):
-        return str
-    return type(input_value)
-
-
-def check_allowed_values(allowed_values, input_variable_path, input_values):
-    """Raises an exception if the input_values are not allowed
-
-    Args:
-        allowed_values (dict): the allowed_values dict
-        input_variable_path (tuple): the path to the input variable
-        input_values (list/str/int/float/date/datetime): the values that we
-            are checking to see if they are in allowed_values
-    """
-    these_allowed_values = list(allowed_values[input_variable_path].values())
-    if (isinstance(input_values, list)
-            and not set(input_values).issubset(
-                set(these_allowed_values))):
-        invalid_values = ", ".join(
-            map(str, set(input_values) - set(these_allowed_values))),
-        raise ApiValueError(
-            "Invalid values for `%s` [%s], must be a subset of [%s]" %
-            (
-                input_variable_path[0],
-                invalid_values,
-                ", ".join(map(str, these_allowed_values))
-            )
-        )
-    elif (isinstance(input_values, dict)
-            and not set(
-                input_values.keys()).issubset(set(these_allowed_values))):
-        invalid_values = ", ".join(
-            map(str, set(input_values.keys()) - set(these_allowed_values)))
-        raise ApiValueError(
-            "Invalid keys in `%s` [%s], must be a subset of [%s]" %
-            (
-                input_variable_path[0],
-                invalid_values,
-                ", ".join(map(str, these_allowed_values))
-            )
-        )
-    elif (not isinstance(input_values, (list, dict))
-            and input_values not in these_allowed_values):
-        raise ApiValueError(
-            "Invalid value for `%s` (%s), must be one of %s" %
-            (
-                input_variable_path[0],
-                input_values,
-                these_allowed_values
-            )
-        )
-
-
-def is_json_validation_enabled(schema_keyword, configuration=None):
-    """Returns true if JSON schema validation is enabled for the specified
-    validation keyword. This can be used to skip JSON schema structural validation
-    as requested in the configuration.
-
-    Args:
-        schema_keyword (string): the name of a JSON schema validation keyword.
-        configuration (Configuration): the configuration class.
-    """
-
-    return (configuration is None or
-        not hasattr(configuration, '_disabled_client_side_validations') or
-        schema_keyword not in configuration._disabled_client_side_validations)
-
-
-def check_validations(
-        validations, input_variable_path, input_values,
-        configuration=None):
-    """Raises an exception if the input_values are invalid
-
-    Args:
-        validations (dict): the validation dictionary.
-        input_variable_path (tuple): the path to the input variable.
-        input_values (list/str/int/float/date/datetime): the values that we
-            are checking.
-        configuration (Configuration): the configuration class.
-    """
-
-    if input_values is None:
-        return
-
-    current_validations = validations[input_variable_path]
-    if (is_json_validation_enabled('multipleOf', configuration) and
-            'multiple_of' in current_validations and
-            isinstance(input_values, (int, float)) and
-            not (float(input_values) / current_validations['multiple_of']).is_integer()):
-        # Note 'multipleOf' will be as good as the floating point arithmetic.
-        raise ApiValueError(
-            "Invalid value for `%s`, value must be a multiple of "
-            "`%s`" % (
-                input_variable_path[0],
-                current_validations['multiple_of']
-            )
-        )
-
-    if (is_json_validation_enabled('maxLength', configuration) and
-            'max_length' in current_validations and
-            len(input_values) > current_validations['max_length']):
-        raise ApiValueError(
-            "Invalid value for `%s`, length must be less than or equal to "
-            "`%s`" % (
-                input_variable_path[0],
-                current_validations['max_length']
-            )
-        )
-
-    if (is_json_validation_enabled('minLength', configuration) and
-            'min_length' in current_validations and
-            len(input_values) < current_validations['min_length']):
-        raise ApiValueError(
-            "Invalid value for `%s`, length must be greater than or equal to "
-            "`%s`" % (
-                input_variable_path[0],
-                current_validations['min_length']
-            )
-        )
-
-    if (is_json_validation_enabled('maxItems', configuration) and
-            'max_items' in current_validations and
-            len(input_values) > current_validations['max_items']):
-        raise ApiValueError(
-            "Invalid value for `%s`, number of items must be less than or "
-            "equal to `%s`" % (
-                input_variable_path[0],
-                current_validations['max_items']
-            )
-        )
-
-    if (is_json_validation_enabled('minItems', configuration) and
-            'min_items' in current_validations and
-            len(input_values) < current_validations['min_items']):
-        raise ValueError(
-            "Invalid value for `%s`, number of items must be greater than or "
-            "equal to `%s`" % (
-                input_variable_path[0],
-                current_validations['min_items']
-            )
-        )
-
-    items = ('exclusive_maximum', 'inclusive_maximum', 'exclusive_minimum',
-             'inclusive_minimum')
-    if (any(item in current_validations for item in items)):
-        if isinstance(input_values, list):
-            max_val = max(input_values)
-            min_val = min(input_values)
-        elif isinstance(input_values, dict):
-            max_val = max(input_values.values())
-            min_val = min(input_values.values())
-        else:
-            max_val = input_values
-            min_val = input_values
-
-    if (is_json_validation_enabled('exclusiveMaximum', configuration) and
-            'exclusive_maximum' in current_validations and
-            max_val >= current_validations['exclusive_maximum']):
-        raise ApiValueError(
-            "Invalid value for `%s`, must be a value less than `%s`" % (
-                input_variable_path[0],
-                current_validations['exclusive_maximum']
-            )
-        )
-
-    if (is_json_validation_enabled('maximum', configuration) and
-            'inclusive_maximum' in current_validations and
-            max_val > current_validations['inclusive_maximum']):
-        raise ApiValueError(
-            "Invalid value for `%s`, must be a value less than or equal to "
-            "`%s`" % (
-                input_variable_path[0],
-                current_validations['inclusive_maximum']
-            )
-        )
-
-    if (is_json_validation_enabled('exclusiveMinimum', configuration) and
-            'exclusive_minimum' in current_validations and
-            min_val <= current_validations['exclusive_minimum']):
-        raise ApiValueError(
-            "Invalid value for `%s`, must be a value greater than `%s`" %
-            (
-                input_variable_path[0],
-                current_validations['exclusive_maximum']
-            )
-        )
-
-    if (is_json_validation_enabled('minimum', configuration) and
-            'inclusive_minimum' in current_validations and
-            min_val < current_validations['inclusive_minimum']):
-        raise ApiValueError(
-            "Invalid value for `%s`, must be a value greater than or equal "
-            "to `%s`" % (
-                input_variable_path[0],
-                current_validations['inclusive_minimum']
-            )
-        )
-    flags = current_validations.get('regex', {}).get('flags', 0)
-    if (is_json_validation_enabled('pattern', configuration) and
-            'regex' in current_validations and
-            not re.search(current_validations['regex']['pattern'],
-                          input_values, flags=flags)):
-        err_msg = r"Invalid value for `%s`, must match regular expression `%s`" % (
-                    input_variable_path[0],
-                    current_validations['regex']['pattern']
-                )
-        if flags != 0:
-            # Don't print the regex flags if the flags are not
-            # specified in the OAS document.
-            err_msg = r"%s with flags=`%s`" % (err_msg, flags)
-        raise ApiValueError(err_msg)
-
-
-def order_response_types(required_types):
-    """Returns the required types sorted in coercion order
-
-    Args:
-        required_types (list/tuple): collection of classes or instance of
-            list or dict with class information inside it.
-
-    Returns:
-        (list): coercion order sorted collection of classes or instance
-            of list or dict with class information inside it.
-    """
-
-    def index_getter(class_or_instance):
-        if isinstance(class_or_instance, list):
-            return COERCION_INDEX_BY_TYPE[list]
-        elif isinstance(class_or_instance, dict):
-            return COERCION_INDEX_BY_TYPE[dict]
-        elif (inspect.isclass(class_or_instance)
-                and issubclass(class_or_instance, ModelComposed)):
-            return COERCION_INDEX_BY_TYPE[ModelComposed]
-        elif (inspect.isclass(class_or_instance)
-                and issubclass(class_or_instance, ModelNormal)):
-            return COERCION_INDEX_BY_TYPE[ModelNormal]
-        elif (inspect.isclass(class_or_instance)
-                and issubclass(class_or_instance, ModelSimple)):
-            return COERCION_INDEX_BY_TYPE[ModelSimple]
-        elif class_or_instance in COERCION_INDEX_BY_TYPE:
-            return COERCION_INDEX_BY_TYPE[class_or_instance]
-        raise ApiValueError("Unsupported type: %s" % class_or_instance)
-
-    sorted_types = sorted(
-        required_types,
-        key=lambda class_or_instance: index_getter(class_or_instance)
-    )
-    return sorted_types
-
-
-def remove_uncoercible(required_types_classes, current_item, spec_property_naming,
-                       must_convert=True):
-    """Only keeps the type conversions that are possible
-
-    Args:
-        required_types_classes (tuple): tuple of classes that are required
-                          these should be ordered by COERCION_INDEX_BY_TYPE
-        spec_property_naming (bool): True if the variable names in the input
-            data are serialized names as specified in the OpenAPI document.
-            False if the variables names in the input data are python
-            variable names in PEP-8 snake case.
-        current_item (any): the current item (input data) to be converted
-
-    Keyword Args:
-        must_convert (bool): if True the item to convert is of the wrong
-                          type and we want a big list of coercibles
-                          if False, we want a limited list of coercibles
-
-    Returns:
-        (list): the remaining coercible required types, classes only
-    """
-    current_type_simple = get_simple_class(current_item)
-
-    results_classes = []
-    for required_type_class in required_types_classes:
-        # convert our models to OpenApiModel
-        required_type_class_simplified = required_type_class
-        if isinstance(required_type_class_simplified, type):
-            if issubclass(required_type_class_simplified, ModelComposed):
-                required_type_class_simplified = ModelComposed
-            elif issubclass(required_type_class_simplified, ModelNormal):
-                required_type_class_simplified = ModelNormal
-            elif issubclass(required_type_class_simplified, ModelSimple):
-                required_type_class_simplified = ModelSimple
-
-        if required_type_class_simplified == current_type_simple:
-            # don't consider converting to one's own class
-            continue
-
-        class_pair = (current_type_simple, required_type_class_simplified)
-        if must_convert and class_pair in COERCIBLE_TYPE_PAIRS[spec_property_naming]:
-            results_classes.append(required_type_class)
-        elif class_pair in UPCONVERSION_TYPE_PAIRS:
-            results_classes.append(required_type_class)
-    return results_classes
-
-def get_discriminated_classes(cls):
-    """
-    Returns all the classes that a discriminator converts to
-    TODO: lru_cache this
-    """
-    possible_classes = []
-    key = list(cls.discriminator.keys())[0]
-    if is_type_nullable(cls):
-        possible_classes.append(cls)
-    for discr_cls in cls.discriminator[key].values():
-        if hasattr(discr_cls, 'discriminator') and discr_cls.discriminator is not None:
-            possible_classes.extend(get_discriminated_classes(discr_cls))
-        else:
-            possible_classes.append(discr_cls)
-    return possible_classes
-
-
-def get_possible_classes(cls, from_server_context):
-    # TODO: lru_cache this
-    possible_classes = [cls]
-    if from_server_context:
-        return possible_classes
-    if hasattr(cls, 'discriminator') and cls.discriminator is not None:
-        possible_classes = []
-        possible_classes.extend(get_discriminated_classes(cls))
-    elif issubclass(cls, ModelComposed):
-        possible_classes.extend(composed_model_input_classes(cls))
-    return possible_classes
-
-
-def get_required_type_classes(required_types_mixed, spec_property_naming):
-    """Converts the tuple required_types into a tuple and a dict described
-    below
-
-    Args:
-        required_types_mixed (tuple/list): will contain either classes or
-            instance of list or dict
-        spec_property_naming (bool): if True these values came from the
-            server, and we use the data types in our endpoints.
-            If False, we are client side and we need to include
-            oneOf and discriminator classes inside the data types in our endpoints
-
-    Returns:
-        (valid_classes, dict_valid_class_to_child_types_mixed):
-            valid_classes (tuple): the valid classes that the current item
-                                   should be
-            dict_valid_class_to_child_types_mixed (dict):
-                valid_class (class): this is the key
-                child_types_mixed (list/dict/tuple): describes the valid child
-                    types
-    """
-    valid_classes = []
-    child_req_types_by_current_type = {}
-    for required_type in required_types_mixed:
-        if isinstance(required_type, list):
-            valid_classes.append(list)
-            child_req_types_by_current_type[list] = required_type
-        elif isinstance(required_type, tuple):
-            valid_classes.append(tuple)
-            child_req_types_by_current_type[tuple] = required_type
-        elif isinstance(required_type, dict):
-            valid_classes.append(dict)
-            child_req_types_by_current_type[dict] = required_type[str]
-        else:
-            valid_classes.extend(get_possible_classes(required_type, spec_property_naming))
-    return tuple(valid_classes), child_req_types_by_current_type
-
-
-def change_keys_js_to_python(input_dict, model_class):
-    """
-    Converts from javascript_key keys in the input_dict to python_keys in
-    the output dict using the mapping in model_class.
-    If the input_dict contains a key which does not declared in the model_class,
-    the key is added to the output dict as is. The assumption is the model_class
-    may have undeclared properties (additionalProperties attribute in the OAS
-    document).
-    """
-
-    if getattr(model_class, 'attribute_map', None) is None:
-        return input_dict
-    output_dict = {}
-    reversed_attr_map = {value: key for key, value in
-                         model_class.attribute_map.items()}
-    for javascript_key, value in input_dict.items():
-        python_key = reversed_attr_map.get(javascript_key)
-        if python_key is None:
-            # if the key is unknown, it is in error or it is an
-            # additionalProperties variable
-            python_key = javascript_key
-        output_dict[python_key] = value
-    return output_dict
-
-
-def get_type_error(var_value, path_to_item, valid_classes, key_type=False):
-    error_msg = type_error_message(
-        var_name=path_to_item[-1],
-        var_value=var_value,
-        valid_classes=valid_classes,
-        key_type=key_type
-    )
-    return ApiTypeError(
-        error_msg,
-        path_to_item=path_to_item,
-        valid_classes=valid_classes,
-        key_type=key_type
-    )
-
-
-def deserialize_primitive(data, klass, path_to_item):
-    """Deserializes string to primitive type.
-
-    :param data: str/int/float
-    :param klass: str/class the class to convert to
-
-    :return: int, float, str, bool, date, datetime
-    """
-    additional_message = ""
-    try:
-        if klass in {datetime, date}:
-            additional_message = (
-                "If you need your parameter to have a fallback "
-                "string value, please set its type as `type: {}` in your "
-                "spec. That allows the value to be any type. "
-            )
-            if klass == datetime:
-                if len(data) < 8:
-                    raise ValueError("This is not a datetime")
-                # The string should be in iso8601 datetime format.
-                parsed_datetime = parse(data)
-                date_only = (
-                    parsed_datetime.hour == 0 and
-                    parsed_datetime.minute == 0 and
-                    parsed_datetime.second == 0 and
-                    parsed_datetime.tzinfo is None and
-                    8 <= len(data) <= 10
-                )
-                if date_only:
-                    raise ValueError("This is a date, not a datetime")
-                return parsed_datetime
-            elif klass == date:
-                if len(data) < 8:
-                    raise ValueError("This is not a date")
-                return parse(data).date()
-        else:
-            converted_value = klass(data)
-            if isinstance(data, str) and klass == float:
-                if str(converted_value) != data:
-                    # '7' -> 7.0 -> '7.0' != '7'
-                    raise ValueError('This is not a float')
-            return converted_value
-    except (OverflowError, ValueError) as ex:
-        # parse can raise OverflowError
-        raise ApiValueError(
-            "{0}Failed to parse {1} as {2}".format(
-                additional_message, repr(data), klass.__name__
-            ),
-            path_to_item=path_to_item
-        ) from ex
-
-
-def get_discriminator_class(model_class,
-                            discr_name,
-                            discr_value, cls_visited):
-    """Returns the child class specified by the discriminator.
-
-    Args:
-        model_class (OpenApiModel): the model class.
-        discr_name (string): the name of the discriminator property.
-        discr_value (any): the discriminator value.
-        cls_visited (list): list of model classes that have been visited.
-            Used to determine the discriminator class without
-            visiting circular references indefinitely.
-
-    Returns:
-        used_model_class (class/None): the chosen child class that will be used
-            to deserialize the data, for example dog.Dog.
-            If a class is not found, None is returned.
-    """
-
-    if model_class in cls_visited:
-        # The class has already been visited and no suitable class was found.
-        return None
-    cls_visited.append(model_class)
-    used_model_class = None
-    if discr_name in model_class.discriminator:
-        class_name_to_discr_class = model_class.discriminator[discr_name]
-        used_model_class = class_name_to_discr_class.get(discr_value)
-    if used_model_class is None:
-        # We didn't find a discriminated class in class_name_to_discr_class.
-        # So look in the ancestor or descendant discriminators
-        # The discriminator mapping may exist in a descendant (anyOf, oneOf)
-        # or ancestor (allOf).
-        # Ancestor example: in the GrandparentAnimal -> ParentPet -> ChildCat
-        #   hierarchy, the discriminator mappings may be defined at any level
-        #   in the hierarchy.
-        # Descendant example:  mammal -> whale/zebra/Pig -> BasquePig/DanishPig
-        #   if we try to make BasquePig from mammal, we need to travel through
-        #   the oneOf descendant discriminators to find BasquePig
-        descendant_classes =  model_class._composed_schemas.get('oneOf', ()) + \
-            model_class._composed_schemas.get('anyOf', ())
-        ancestor_classes = model_class._composed_schemas.get('allOf', ())
-        possible_classes = descendant_classes + ancestor_classes
-        for cls in possible_classes:
-            # Check if the schema has inherited discriminators.
-            if hasattr(cls, 'discriminator') and cls.discriminator is not None:
-                used_model_class = get_discriminator_class(
-                                    cls, discr_name, discr_value, cls_visited)
-                if used_model_class is not None:
-                    return used_model_class
-    return used_model_class
-
-
-def deserialize_model(model_data, model_class, path_to_item, check_type,
-                      configuration, spec_property_naming):
-    """Deserializes model_data to model instance.
-
-    Args:
-        model_data (int/str/float/bool/none_type/list/dict): data to instantiate the model
-        model_class (OpenApiModel): the model class
-        path_to_item (list): path to the model in the received data
-        check_type (bool): whether to check the data tupe for the values in
-            the model
-        configuration (Configuration): the instance to use to convert files
-        spec_property_naming (bool): True if the variable names in the input
-            data are serialized names as specified in the OpenAPI document.
-            False if the variables names in the input data are python
-            variable names in PEP-8 snake case.
-
-    Returns:
-        model instance
-
-    Raise:
-        ApiTypeError
-        ApiValueError
-        ApiKeyError
-    """
-
-    kw_args = dict(_check_type=check_type,
-                   _path_to_item=path_to_item,
-                   _configuration=configuration,
-                   _spec_property_naming=spec_property_naming)
-
-    if issubclass(model_class, ModelSimple):
-        return model_class(model_data, **kw_args)
-    elif isinstance(model_data, list):
-        return model_class(*model_data, **kw_args)
-    if isinstance(model_data, dict):
-        kw_args.update(model_data)
-        return model_class(**kw_args)
-    elif isinstance(model_data, PRIMITIVE_TYPES):
-        return model_class(model_data, **kw_args)
-
-
-def deserialize_file(response_data, configuration, content_disposition=None):
-    """Deserializes body to file
-
-    Saves response body into a file in a temporary folder,
-    using the filename from the `Content-Disposition` header if provided.
-
-    Args:
-        param response_data (str):  the file data to write
-        configuration (Configuration): the instance to use to convert files
-
-    Keyword Args:
-        content_disposition (str):  the value of the Content-Disposition
-            header
-
-    Returns:
-        (file_type): the deserialized file which is open
-            The user is responsible for closing and reading the file
-    """
-    fd, path = tempfile.mkstemp(dir=configuration.temp_folder_path)
-    os.close(fd)
-    os.remove(path)
-
-    if content_disposition:
-        filename = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?',
-                             content_disposition).group(1)
-        path = os.path.join(os.path.dirname(path), filename)
-
-    with open(path, "wb") as f:
-        if isinstance(response_data, str):
-            # change str to bytes so we can write it
-            response_data = response_data.encode('utf-8')
-        f.write(response_data)
-
-    f = open(path, "rb")
-    return f
-
-
-def attempt_convert_item(input_value, valid_classes, path_to_item,
-                         configuration, spec_property_naming, key_type=False,
-                         must_convert=False, check_type=True):
-    """
-    Args:
-        input_value (any): the data to convert
-        valid_classes (any): the classes that are valid
-        path_to_item (list): the path to the item to convert
-        configuration (Configuration): the instance to use to convert files
-        spec_property_naming (bool): True if the variable names in the input
-            data are serialized names as specified in the OpenAPI document.
-            False if the variables names in the input data are python
-            variable names in PEP-8 snake case.
-        key_type (bool): if True we need to convert a key type (not supported)
-        must_convert (bool): if True we must convert
-        check_type (bool): if True we check the type or the returned data in
-            ModelComposed/ModelNormal/ModelSimple instances
-
-    Returns:
-        instance (any) the fixed item
-
-    Raises:
-        ApiTypeError
-        ApiValueError
-        ApiKeyError
-    """
-    valid_classes_ordered = order_response_types(valid_classes)
-    valid_classes_coercible = remove_uncoercible(
-        valid_classes_ordered, input_value, spec_property_naming)
-    if not valid_classes_coercible or key_type:
-        # we do not handle keytype errors, json will take care
-        # of this for us
-        if configuration is None or not configuration.discard_unknown_keys:
-            raise get_type_error(input_value, path_to_item, valid_classes,
-                                 key_type=key_type)
-    for valid_class in valid_classes_coercible:
-        try:
-            if issubclass(valid_class, OpenApiModel):
-                return deserialize_model(input_value, valid_class,
-                                         path_to_item, check_type,
-                                         configuration, spec_property_naming)
-            elif valid_class == file_type:
-                return deserialize_file(input_value, configuration)
-            return deserialize_primitive(input_value, valid_class,
-                                         path_to_item)
-        except (ApiTypeError, ApiValueError, ApiKeyError) as conversion_exc:
-            if must_convert:
-                raise conversion_exc
-            # if we have conversion errors when must_convert == False
-            # we ignore the exception and move on to the next class
-            continue
-    # we were unable to convert, must_convert == False
-    return input_value
-
-
-def is_type_nullable(input_type):
-    """
-    Returns true if None is an allowed value for the specified input_type.
-
-    A type is nullable if at least one of the following conditions is true:
-    1. The OAS 'nullable' attribute has been specified,
-    1. The type is the 'null' type,
-    1. The type is a anyOf/oneOf composed schema, and a child schema is
-       the 'null' type.
-    Args:
-        input_type (type): the class of the input_value that we are
-            checking
-    Returns:
-        bool
-    """
-    if input_type is none_type:
-        return True
-    if issubclass(input_type, OpenApiModel) and input_type._nullable:
-        return True
-    if issubclass(input_type, ModelComposed):
-        # If oneOf/anyOf, check if the 'null' type is one of the allowed types.
-        for t in input_type._composed_schemas.get('oneOf', ()):
-            if is_type_nullable(t): return True
-        for t in input_type._composed_schemas.get('anyOf', ()):
-            if is_type_nullable(t): return True
-    return False
-
-
-def is_valid_type(input_class_simple, valid_classes):
-    """
-    Args:
-        input_class_simple (class): the class of the input_value that we are
-            checking
-        valid_classes (tuple): the valid classes that the current item
-            should be
-    Returns:
-        bool
-    """
-    valid_type = input_class_simple in valid_classes
-    if not valid_type and (
-            issubclass(input_class_simple, OpenApiModel) or
-            input_class_simple is none_type):
-        for valid_class in valid_classes:
-            if input_class_simple is none_type and is_type_nullable(valid_class):
-                # Schema is oneOf/anyOf and the 'null' type is one of the allowed types.
-                return True
-            if not (issubclass(valid_class, OpenApiModel) and valid_class.discriminator):
-                continue
-            discr_propertyname_py = list(valid_class.discriminator.keys())[0]
-            discriminator_classes = (
-                valid_class.discriminator[discr_propertyname_py].values()
-            )
-            valid_type = is_valid_type(input_class_simple, discriminator_classes)
-            if valid_type:
-                return True
-    return valid_type
-
-
-def validate_and_convert_types(input_value, required_types_mixed, path_to_item,
-                               spec_property_naming, _check_type, configuration=None):
-    """Raises a TypeError is there is a problem, otherwise returns value
-
-    Args:
-        input_value (any): the data to validate/convert
-        required_types_mixed (list/dict/tuple): A list of
-            valid classes, or a list tuples of valid classes, or a dict where
-            the value is a tuple of value classes
-        path_to_item: (list) the path to the data being validated
-            this stores a list of keys or indices to get to the data being
-            validated
-        spec_property_naming (bool): True if the variable names in the input
-            data are serialized names as specified in the OpenAPI document.
-            False if the variables names in the input data are python
-            variable names in PEP-8 snake case.
-        _check_type: (boolean) if true, type will be checked and conversion
-            will be attempted.
-        configuration: (Configuration): the configuration class to use
-            when converting file_type items.
-            If passed, conversion will be attempted when possible
-            If not passed, no conversions will be attempted and
-            exceptions will be raised
-
-    Returns:
-        the correctly typed value
-
-    Raises:
-        ApiTypeError
-    """
-    results = get_required_type_classes(required_types_mixed, spec_property_naming)
-    valid_classes, child_req_types_by_current_type = results
-
-    input_class_simple = get_simple_class(input_value)
-    valid_type = is_valid_type(input_class_simple, valid_classes)
-    if not valid_type:
-        if configuration:
-            # if input_value is not valid_type try to convert it
-            converted_instance = attempt_convert_item(
-                input_value,
-                valid_classes,
-                path_to_item,
-                configuration,
-                spec_property_naming,
-                key_type=False,
-                must_convert=True,
-                check_type=_check_type
-            )
-            return converted_instance
-        else:
-            raise get_type_error(input_value, path_to_item, valid_classes,
-                                 key_type=False)
-
-    # input_value's type is in valid_classes
-    if len(valid_classes) > 1 and configuration:
-        # there are valid classes which are not the current class
-        valid_classes_coercible = remove_uncoercible(
-            valid_classes, input_value, spec_property_naming, must_convert=False)
-        if valid_classes_coercible:
-            converted_instance = attempt_convert_item(
-                input_value,
-                valid_classes_coercible,
-                path_to_item,
-                configuration,
-                spec_property_naming,
-                key_type=False,
-                must_convert=False,
-                check_type=_check_type
-            )
-            return converted_instance
-
-    if child_req_types_by_current_type == {}:
-        # all types are of the required types and there are no more inner
-        # variables left to look at
-        return input_value
-    inner_required_types = child_req_types_by_current_type.get(
-        type(input_value)
-    )
-    if inner_required_types is None:
-        # for this type, there are not more inner variables left to look at
-        return input_value
-    if isinstance(input_value, list):
-        if input_value == []:
-            # allow an empty list
-            return input_value
-        for index, inner_value in enumerate(input_value):
-            inner_path = list(path_to_item)
-            inner_path.append(index)
-            input_value[index] = validate_and_convert_types(
-                inner_value,
-                inner_required_types,
-                inner_path,
-                spec_property_naming,
-                _check_type,
-                configuration=configuration
-            )
-    elif isinstance(input_value, dict):
-        if input_value == {}:
-            # allow an empty dict
-            return input_value
-        for inner_key, inner_val in input_value.items():
-            inner_path = list(path_to_item)
-            inner_path.append(inner_key)
-            if get_simple_class(inner_key) != str:
-                raise get_type_error(inner_key, inner_path, valid_classes,
-                                     key_type=True)
-            input_value[inner_key] = validate_and_convert_types(
-                inner_val,
-                inner_required_types,
-                inner_path,
-                spec_property_naming,
-                _check_type,
-                configuration=configuration
-            )
-    return input_value
-
-
-def model_to_dict(model_instance, serialize=True):
-    """Returns the model properties as a dict
-
-    Args:
-        model_instance (one of your model instances): the model instance that
-            will be converted to a dict.
-
-    Keyword Args:
-        serialize (bool): if True, the keys in the dict will be values from
-            attribute_map
-    """
-    result = {}
-
-    model_instances = [model_instance]
-    if model_instance._composed_schemas:
-        model_instances.extend(model_instance._composed_instances)
-    for model_instance in model_instances:
-        for attr, value in model_instance._data_store.items():
-            if serialize:
-                # we use get here because additional property key names do not
-                # exist in attribute_map
-                attr = model_instance.attribute_map.get(attr, attr)
-            if isinstance(value, list):
-               if not value:
-                   # empty list or None
-                   result[attr] = value
-               else:
-                   res = []
-                   for v in value:
-                       if isinstance(v, PRIMITIVE_TYPES) or v is None:
-                           res.append(v)
-                       elif isinstance(v, ModelSimple):
-                           res.append(v.value)
-                       else:
-                           res.append(model_to_dict(v, serialize=serialize))
-                   result[attr] = res
-            elif isinstance(value, dict):
-                result[attr] = dict(map(
-                    lambda item: (item[0],
-                                  model_to_dict(item[1], serialize=serialize))
-                    if hasattr(item[1], '_data_store') else item,
-                    value.items()
-                ))
-            elif isinstance(value, ModelSimple):
-                result[attr] = value.value
-            elif hasattr(value, '_data_store'):
-                result[attr] = model_to_dict(value, serialize=serialize)
-            else:
-                result[attr] = value
-
-    return result
-
-
-def type_error_message(var_value=None, var_name=None, valid_classes=None,
-                       key_type=None):
-    """
-    Keyword Args:
-        var_value (any): the variable which has the type_error
-        var_name (str): the name of the variable which has the typ error
-        valid_classes (tuple): the accepted classes for current_item's
-                                  value
-        key_type (bool): False if our value is a value in a dict
-                         True if it is a key in a dict
-                         False if our item is an item in a list
-    """
-    key_or_value = 'value'
-    if key_type:
-        key_or_value = 'key'
-    valid_classes_phrase = get_valid_classes_phrase(valid_classes)
-    msg = (
-        "Invalid type for variable '{0}'. Required {1} type {2} and "
-        "passed type was {3}".format(
-            var_name,
-            key_or_value,
-            valid_classes_phrase,
-            type(var_value).__name__,
-        )
-    )
-    return msg
-
-
-def get_valid_classes_phrase(input_classes):
-    """Returns a string phrase describing what types are allowed
-    """
-    all_classes = list(input_classes)
-    all_classes = sorted(all_classes, key=lambda cls: cls.__name__)
-    all_class_names = [cls.__name__ for cls in all_classes]
-    if len(all_class_names) == 1:
-        return 'is {0}'.format(all_class_names[0])
-    return "is one of [{0}]".format(", ".join(all_class_names))
-
-
-def convert_js_args_to_python_args(fn):
-    from functools import wraps
-    @wraps(fn)
-    def wrapped_init(_self, *args, **kwargs):
-        """
-        An attribute named `self` received from the api will conflicts with the reserved `self`
-        parameter of a class method. During generation, `self` attributes are mapped
-        to `_self` in models. Here, we name `_self` instead of `self` to avoid conflicts.
-        """
-        spec_property_naming = kwargs.get('_spec_property_naming', False)
-        if spec_property_naming:
-            kwargs = change_keys_js_to_python(kwargs, _self.__class__)
-        return fn(_self, *args, **kwargs)
-    return wrapped_init
-
-
-def get_allof_instances(self, model_args, constant_args):
-    """
-    Args:
-        self: the class we are handling
-        model_args (dict): var_name to var_value
-            used to make instances
-        constant_args (dict): var_name to var_value
-            used to make instances
-
-    Returns
-        composed_instances (list)
-    """
-    composed_instances = []
-    for allof_class in self._composed_schemas['allOf']:
-
-        # no need to handle changing js keys to python because
-        # for composed schemas, allof parameters are included in the
-        # composed schema and were changed to python keys in __new__
-        # extract a dict of only required keys from fixed_model_args
-        kwargs = {}
-        var_names = set(allof_class.openapi_types.keys())
-        for var_name in var_names:
-            if var_name in model_args:
-                kwargs[var_name] = model_args[var_name]
-
-        # and use it to make the instance
-        kwargs.update(constant_args)
-        try:
-            allof_instance = allof_class(**kwargs)
-            composed_instances.append(allof_instance)
-        except Exception as ex:
-            raise ApiValueError(
-                "Invalid inputs given to generate an instance of '%s'. The "
-                "input data was invalid for the allOf schema '%s' in the composed "
-                "schema '%s'. Error=%s" % (
-                    allof_class.__name__,
-                    allof_class.__name__,
-                    self.__class__.__name__,
-                    str(ex)
-                )
-            ) from ex
-    return composed_instances
-
-
-def get_oneof_instance(cls, model_kwargs, constant_kwargs, model_arg=None):
-    """
-    Find the oneOf schema that matches the input data (e.g. payload).
-    If exactly one schema matches the input data, an instance of that schema
-    is returned.
-    If zero or more than one schema match the input data, an exception is raised.
-    In OAS 3.x, the payload MUST, by validation, match exactly one of the
-    schemas described by oneOf.
-
-    Args:
-        cls: the class we are handling
-        model_kwargs (dict): var_name to var_value
-            The input data, e.g. the payload that must match a oneOf schema
-            in the OpenAPI document.
-        constant_kwargs (dict): var_name to var_value
-            args that every model requires, including configuration, server
-            and path to item.
-
-    Kwargs:
-        model_arg: (int, float, bool, str, date, datetime, ModelSimple, None):
-            the value to assign to a primitive class or ModelSimple class
-            Notes:
-            - this is only passed in when oneOf includes types which are not object
-            - None is used to suppress handling of model_arg, nullable models are handled in __new__
-
-    Returns
-        oneof_instance (instance)
-    """
-    if len(cls._composed_schemas['oneOf']) == 0:
-        return None
-
-    oneof_instances = []
-    # Iterate over each oneOf schema and determine if the input data
-    # matches the oneOf schemas.
-    for oneof_class in cls._composed_schemas['oneOf']:
-        # The composed oneOf schema allows the 'null' type and the input data
-        # is the null value. This is a OAS >= 3.1 feature.
-        if oneof_class is none_type:
-            # skip none_types because we are deserializing dict data.
-            # none_type deserialization is handled in the __new__ method
-            continue
-
-        single_value_input = allows_single_value_input(oneof_class)
-
-        if not single_value_input:
-            # transform js keys from input data to python keys in fixed_model_args
-            fixed_model_args = change_keys_js_to_python(
-                model_kwargs, oneof_class)
-
-            # Extract a dict with the properties that are declared in the oneOf schema.
-            # Undeclared properties (e.g. properties that are allowed because of the
-            # additionalProperties attribute in the OAS document) are not added to
-            # the dict.
-            kwargs = {}
-            var_names = set(oneof_class.openapi_types.keys())
-            for var_name in var_names:
-                if var_name in fixed_model_args:
-                    kwargs[var_name] = fixed_model_args[var_name]
-
-            # do not try to make a model with no input args
-            if len(kwargs) == 0:
-                continue
-
-            # and use it to make the instance
-            kwargs.update(constant_kwargs)
-
-        try:
-            if not single_value_input:
-                oneof_instance = oneof_class(**kwargs)
-            else:
-                if issubclass(oneof_class, ModelSimple):
-                    oneof_instance = oneof_class(model_arg, **constant_kwargs)
-                elif oneof_class in PRIMITIVE_TYPES:
-                    oneof_instance = validate_and_convert_types(
-                        model_arg,
-                        (oneof_class,),
-                        constant_kwargs['_path_to_item'],
-                        constant_kwargs['_spec_property_naming'],
-                        constant_kwargs['_check_type'],
-                        configuration=constant_kwargs['_configuration']
-                    )
-            oneof_instances.append(oneof_instance)
-        except Exception:
-            pass
-    if len(oneof_instances) == 0:
-        raise ApiValueError(
-            "Invalid inputs given to generate an instance of %s. None "
-            "of the oneOf schemas matched the input data." %
-            cls.__name__
-        )
-    elif len(oneof_instances) > 1:
-        raise ApiValueError(
-            "Invalid inputs given to generate an instance of %s. Multiple "
-            "oneOf schemas matched the inputs, but a max of one is allowed." %
-            cls.__name__
-        )
-    return oneof_instances[0]
-
-
-def get_anyof_instances(self, model_args, constant_args):
-    """
-    Args:
-        self: the class we are handling
-        model_args (dict): var_name to var_value
-            The input data, e.g. the payload that must match at least one
-            anyOf child schema in the OpenAPI document.
-        constant_args (dict): var_name to var_value
-            args that every model requires, including configuration, server
-            and path to item.
-
-    Returns
-        anyof_instances (list)
-    """
-    anyof_instances = []
-    if len(self._composed_schemas['anyOf']) == 0:
-        return anyof_instances
-
-    for anyof_class in self._composed_schemas['anyOf']:
-        # The composed oneOf schema allows the 'null' type and the input data
-        # is the null value. This is a OAS >= 3.1 feature.
-        if anyof_class is none_type:
-            # skip none_types because we are deserializing dict data.
-            # none_type deserialization is handled in the __new__ method
-            continue
-
-        # transform js keys to python keys in fixed_model_args
-        fixed_model_args = change_keys_js_to_python(model_args, anyof_class)
-
-        # extract a dict of only required keys from these_model_vars
-        kwargs = {}
-        var_names = set(anyof_class.openapi_types.keys())
-        for var_name in var_names:
-            if var_name in fixed_model_args:
-                kwargs[var_name] = fixed_model_args[var_name]
-
-        # do not try to make a model with no input args
-        if len(kwargs) == 0:
-            continue
-
-        # and use it to make the instance
-        kwargs.update(constant_args)
-        try:
-            anyof_instance = anyof_class(**kwargs)
-            anyof_instances.append(anyof_instance)
-        except Exception:
-            pass
-    if len(anyof_instances) == 0:
-        raise ApiValueError(
-            "Invalid inputs given to generate an instance of %s. None of the "
-            "anyOf schemas matched the inputs." %
-            self.__class__.__name__
-        )
-    return anyof_instances
-
-
-def get_additional_properties_model_instances(
-        composed_instances, self):
-    additional_properties_model_instances = []
-    all_instances = [self]
-    all_instances.extend(composed_instances)
-    for instance in all_instances:
-        if instance.additional_properties_type is not None:
-            additional_properties_model_instances.append(instance)
-    return additional_properties_model_instances
-
-
-def get_var_name_to_model_instances(self, composed_instances):
-    var_name_to_model_instances = {}
-    all_instances = [self]
-    all_instances.extend(composed_instances)
-    for instance in all_instances:
-        for var_name in instance.openapi_types:
-            if var_name not in var_name_to_model_instances:
-                var_name_to_model_instances[var_name] = [instance]
-            else:
-                var_name_to_model_instances[var_name].append(instance)
-    return var_name_to_model_instances
-
-
-def get_unused_args(self, composed_instances, model_args):
-    unused_args = dict(model_args)
-    # arguments apssed to self were already converted to python names
-    # before __init__ was called
-    for var_name_py in self.attribute_map:
-        if var_name_py in unused_args:
-            del unused_args[var_name_py]
-    for instance in composed_instances:
-        if instance.__class__ in self._composed_schemas['allOf']:
-            for var_name_py in instance.attribute_map:
-                if var_name_py in unused_args:
-                    del unused_args[var_name_py]
-        else:
-            for var_name_js in instance.attribute_map.values():
-                if var_name_js in unused_args:
-                    del unused_args[var_name_js]
-    return unused_args
-
-
-def validate_get_composed_info(constant_args, model_args, self):
-    """
-    For composed schemas, generate schema instances for
-    all schemas in the oneOf/anyOf/allOf definition. If additional
-    properties are allowed, also assign those properties on
-    all matched schemas that contain additionalProperties.
-    Openapi schemas are python classes.
-
-    Exceptions are raised if:
-    - 0 or > 1 oneOf schema matches the model_args input data
-    - no anyOf schema matches the model_args input data
-    - any of the allOf schemas do not match the model_args input data
-
-    Args:
-        constant_args (dict): these are the args that every model requires
-        model_args (dict): these are the required and optional spec args that
-            were passed in to make this model
-        self (class): the class that we are instantiating
-            This class contains self._composed_schemas
-
-    Returns:
-        composed_info (list): length three
-            composed_instances (list): the composed instances which are not
-                self
-            var_name_to_model_instances (dict): a dict going from var_name
-                to the model_instance which holds that var_name
-                the model_instance may be self or an instance of one of the
-                classes in self.composed_instances()
-            additional_properties_model_instances (list): a list of the
-                model instances which have the property
-                additional_properties_type. This list can include self
-    """
-    # create composed_instances
-    composed_instances = []
-    allof_instances = get_allof_instances(self, model_args, constant_args)
-    composed_instances.extend(allof_instances)
-    oneof_instance = get_oneof_instance(self.__class__, model_args, constant_args)
-    if oneof_instance is not None:
-        composed_instances.append(oneof_instance)
-    anyof_instances = get_anyof_instances(self, model_args, constant_args)
-    composed_instances.extend(anyof_instances)
-
-    # map variable names to composed_instances
-    var_name_to_model_instances = get_var_name_to_model_instances(
-        self, composed_instances)
-
-    # set additional_properties_model_instances
-    additional_properties_model_instances = (
-        get_additional_properties_model_instances(composed_instances, self)
-    )
-
-    # set any remaining values
-    unused_args = get_unused_args(self, composed_instances, model_args)
-    if len(unused_args) > 0 and \
-            len(additional_properties_model_instances) == 0 and \
-            (self._configuration is None or
-                not self._configuration.discard_unknown_keys):
-        raise ApiValueError(
-            "Invalid input arguments input when making an instance of "
-            "class %s. Not all inputs were used. The unused input data "
-            "is %s" % (self.__class__.__name__, unused_args)
-        )
-
-    # no need to add additional_properties to var_name_to_model_instances here
-    # because additional_properties_model_instances will direct us to that
-    # instance when we use getattr or setattr
-    # and we update var_name_to_model_instances in setattr
-
-    return [
-      composed_instances,
-      var_name_to_model_instances,
-      additional_properties_model_instances,
-      unused_args
-    ]
diff --git a/bitdotio/models/__init__.py b/bitdotio/models/__init__.py
deleted file mode 100644
index 2c8614c..0000000
--- a/bitdotio/models/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# flake8: noqa
-
-# import all models into this package
-# if you have many models here with many references from one model to another this may
-# raise a RecursionError
-# to avoid this, import only the models that you directly need like:
-# from from bitdotio.model.pet import Pet
-# or import this package, but before doing it, use:
-# import sys
-# sys.setrecursionlimit(n)
-
-from bitdotio.model.import_json import ImportJson
-from bitdotio.model.import_url import ImportUrl
-from bitdotio.model.ingestion_result import IngestionResult
-from bitdotio.model.ingestor_job import IngestorJob
-from bitdotio.model.query import Query
-from bitdotio.model.repo import Repo
diff --git a/bitdotio/models/column.py b/bitdotio/models/column.py
deleted file mode 100644
index a75d23e..0000000
--- a/bitdotio/models/column.py
+++ /dev/null
@@ -1,207 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import pprint
-import re  # noqa: F401
-
-import six
-
-from bitdotio.configuration import Configuration
-
-
-class Column(object):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-    """
-
-    """
-    Attributes:
-      openapi_types (dict): The key is attribute name
-                            and the value is attribute type.
-      attribute_map (dict): The key is attribute name
-                            and the value is json key in definition.
-    """
-    openapi_types = {
-        'url': 'str',
-        'current_name': 'str',
-        'data_type': 'str',
-        'description': 'str'
-    }
-
-    attribute_map = {
-        'url': 'url',
-        'current_name': 'current_name',
-        'data_type': 'data_type',
-        'description': 'description'
-    }
-
-    def __init__(self, url=None, current_name=None, data_type=None, description=None, local_vars_configuration=None):  # noqa: E501
-        """Column - a model defined in OpenAPI"""  # noqa: E501
-        if local_vars_configuration is None:
-            local_vars_configuration = Configuration()
-        self.local_vars_configuration = local_vars_configuration
-
-        self._url = None
-        self._current_name = None
-        self._data_type = None
-        self._description = None
-        self.discriminator = None
-
-        if url is not None:
-            self.url = url
-        if current_name is not None:
-            self.current_name = current_name
-        if data_type is not None:
-            self.data_type = data_type
-        if description is not None:
-            self.description = description
-
-    @property
-    def url(self):
-        """Gets the url of this Column.  # noqa: E501
-
-
-        :return: The url of this Column.  # noqa: E501
-        :rtype: str
-        """
-        return self._url
-
-    @url.setter
-    def url(self, url):
-        """Sets the url of this Column.
-
-
-        :param url: The url of this Column.  # noqa: E501
-        :type: str
-        """
-
-        self._url = url
-
-    @property
-    def current_name(self):
-        """Gets the current_name of this Column.  # noqa: E501
-
-
-        :return: The current_name of this Column.  # noqa: E501
-        :rtype: str
-        """
-        return self._current_name
-
-    @current_name.setter
-    def current_name(self, current_name):
-        """Sets the current_name of this Column.
-
-
-        :param current_name: The current_name of this Column.  # noqa: E501
-        :type: str
-        """
-
-        self._current_name = current_name
-
-    @property
-    def data_type(self):
-        """Gets the data_type of this Column.  # noqa: E501
-
-
-        :return: The data_type of this Column.  # noqa: E501
-        :rtype: str
-        """
-        return self._data_type
-
-    @data_type.setter
-    def data_type(self, data_type):
-        """Sets the data_type of this Column.
-
-
-        :param data_type: The data_type of this Column.  # noqa: E501
-        :type: str
-        """
-        allowed_values = ["BIGINT", "INTEGER", "SMALLINT", "BOOLEAN", "TEXT", "VARCHAR", "CHAR", "DOUBLE PRECISION", "REAL", "TIMESTAMP WITH TIME ZONE", "TIMESTAMP WITHOUT TIME ZONE", "TIME WITH TIME ZONE", "TIME WITHOUT TIME ZONE", "DATE", "JSON", "JSONB", "BYTEA"]  # noqa: E501
-        if self.local_vars_configuration.client_side_validation and data_type not in allowed_values:  # noqa: E501
-            raise ValueError(
-                "Invalid value for `data_type` ({0}), must be one of {1}"  # noqa: E501
-                .format(data_type, allowed_values)
-            )
-
-        self._data_type = data_type
-
-    @property
-    def description(self):
-        """Gets the description of this Column.  # noqa: E501
-
-
-        :return: The description of this Column.  # noqa: E501
-        :rtype: str
-        """
-        return self._description
-
-    @description.setter
-    def description(self, description):
-        """Sets the description of this Column.
-
-
-        :param description: The description of this Column.  # noqa: E501
-        :type: str
-        """
-        if (self.local_vars_configuration.client_side_validation and
-                description is not None and len(description) > 128):
-            raise ValueError("Invalid value for `description`, length must be less than or equal to `128`")  # noqa: E501
-
-        self._description = description
-
-    def to_dict(self):
-        """Returns the model properties as a dict"""
-        result = {}
-
-        for attr, _ in six.iteritems(self.openapi_types):
-            value = getattr(self, attr)
-            if isinstance(value, list):
-                result[attr] = list(map(
-                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
-                    value
-                ))
-            elif hasattr(value, "to_dict"):
-                result[attr] = value.to_dict()
-            elif isinstance(value, dict):
-                result[attr] = dict(map(
-                    lambda item: (item[0], item[1].to_dict())
-                    if hasattr(item[1], "to_dict") else item,
-                    value.items()
-                ))
-            else:
-                result[attr] = value
-
-        return result
-
-    def to_str(self):
-        """Returns the string representation of the model"""
-        return pprint.pformat(self.to_dict())
-
-    def __repr__(self):
-        """For `print` and `pprint`"""
-        return self.to_str()
-
-    def __eq__(self, other):
-        """Returns true if both objects are equal"""
-        if not isinstance(other, Column):
-            return False
-
-        return self.to_dict() == other.to_dict()
-
-    def __ne__(self, other):
-        """Returns true if both objects are not equal"""
-        if not isinstance(other, Column):
-            return True
-
-        return self.to_dict() != other.to_dict()
diff --git a/bitdotio/models/q_connection.py b/bitdotio/models/q_connection.py
deleted file mode 100644
index fc60615..0000000
--- a/bitdotio/models/q_connection.py
+++ /dev/null
@@ -1,204 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import pprint
-import re  # noqa: F401
-
-import six
-
-from bitdotio.configuration import Configuration
-
-
-class QConnection(object):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-    """
-
-    """
-    Attributes:
-      openapi_types (dict): The key is attribute name
-                            and the value is attribute type.
-      attribute_map (dict): The key is attribute name
-                            and the value is json key in definition.
-    """
-    openapi_types = {
-        'url': 'str',
-        'name': 'str',
-        'owner': 'str',
-        'kind': 'str'
-    }
-
-    attribute_map = {
-        'url': 'url',
-        'name': 'name',
-        'owner': 'owner',
-        'kind': 'kind'
-    }
-
-    def __init__(self, url=None, name=None, owner=None, kind=None, local_vars_configuration=None):  # noqa: E501
-        """QConnection - a model defined in OpenAPI"""  # noqa: E501
-        if local_vars_configuration is None:
-            local_vars_configuration = Configuration()
-        self.local_vars_configuration = local_vars_configuration
-
-        self._url = None
-        self._name = None
-        self._owner = None
-        self._kind = None
-        self.discriminator = None
-
-        if url is not None:
-            self.url = url
-        if name is not None:
-            self.name = name
-        if owner is not None:
-            self.owner = owner
-        if kind is not None:
-            self.kind = kind
-
-    @property
-    def url(self):
-        """Gets the url of this QConnection.  # noqa: E501
-
-
-        :return: The url of this QConnection.  # noqa: E501
-        :rtype: str
-        """
-        return self._url
-
-    @url.setter
-    def url(self, url):
-        """Sets the url of this QConnection.
-
-
-        :param url: The url of this QConnection.  # noqa: E501
-        :type: str
-        """
-
-        self._url = url
-
-    @property
-    def name(self):
-        """Gets the name of this QConnection.  # noqa: E501
-
-
-        :return: The name of this QConnection.  # noqa: E501
-        :rtype: str
-        """
-        return self._name
-
-    @name.setter
-    def name(self, name):
-        """Sets the name of this QConnection.
-
-
-        :param name: The name of this QConnection.  # noqa: E501
-        :type: str
-        """
-
-        self._name = name
-
-    @property
-    def owner(self):
-        """Gets the owner of this QConnection.  # noqa: E501
-
-
-        :return: The owner of this QConnection.  # noqa: E501
-        :rtype: str
-        """
-        return self._owner
-
-    @owner.setter
-    def owner(self, owner):
-        """Sets the owner of this QConnection.
-
-
-        :param owner: The owner of this QConnection.  # noqa: E501
-        :type: str
-        """
-
-        self._owner = owner
-
-    @property
-    def kind(self):
-        """Gets the kind of this QConnection.  # noqa: E501
-
-
-        :return: The kind of this QConnection.  # noqa: E501
-        :rtype: str
-        """
-        return self._kind
-
-    @kind.setter
-    def kind(self, kind):
-        """Sets the kind of this QConnection.
-
-
-        :param kind: The kind of this QConnection.  # noqa: E501
-        :type: str
-        """
-        allowed_values = ["REST_CONNECTION", "POSTGRES_CONNECTION", "SDK_CONNECTION"]  # noqa: E501
-        if self.local_vars_configuration.client_side_validation and kind not in allowed_values:  # noqa: E501
-            raise ValueError(
-                "Invalid value for `kind` ({0}), must be one of {1}"  # noqa: E501
-                .format(kind, allowed_values)
-            )
-
-        self._kind = kind
-
-    def to_dict(self):
-        """Returns the model properties as a dict"""
-        result = {}
-
-        for attr, _ in six.iteritems(self.openapi_types):
-            value = getattr(self, attr)
-            if isinstance(value, list):
-                result[attr] = list(map(
-                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
-                    value
-                ))
-            elif hasattr(value, "to_dict"):
-                result[attr] = value.to_dict()
-            elif isinstance(value, dict):
-                result[attr] = dict(map(
-                    lambda item: (item[0], item[1].to_dict())
-                    if hasattr(item[1], "to_dict") else item,
-                    value.items()
-                ))
-            else:
-                result[attr] = value
-
-        return result
-
-    def to_str(self):
-        """Returns the string representation of the model"""
-        return pprint.pformat(self.to_dict())
-
-    def __repr__(self):
-        """For `print` and `pprint`"""
-        return self.to_str()
-
-    def __eq__(self, other):
-        """Returns true if both objects are equal"""
-        if not isinstance(other, QConnection):
-            return False
-
-        return self.to_dict() == other.to_dict()
-
-    def __ne__(self, other):
-        """Returns true if both objects are not equal"""
-        if not isinstance(other, QConnection):
-            return True
-
-        return self.to_dict() != other.to_dict()
diff --git a/bitdotio/models/q_endpoint.py b/bitdotio/models/q_endpoint.py
deleted file mode 100644
index e11019c..0000000
--- a/bitdotio/models/q_endpoint.py
+++ /dev/null
@@ -1,204 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import pprint
-import re  # noqa: F401
-
-import six
-
-from bitdotio.configuration import Configuration
-
-
-class QEndpoint(object):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-    """
-
-    """
-    Attributes:
-      openapi_types (dict): The key is attribute name
-                            and the value is attribute type.
-      attribute_map (dict): The key is attribute name
-                            and the value is json key in definition.
-    """
-    openapi_types = {
-        'url': 'str',
-        'name': 'str',
-        'owner': 'str',
-        'kind': 'str'
-    }
-
-    attribute_map = {
-        'url': 'url',
-        'name': 'name',
-        'owner': 'owner',
-        'kind': 'kind'
-    }
-
-    def __init__(self, url=None, name=None, owner=None, kind=None, local_vars_configuration=None):  # noqa: E501
-        """QEndpoint - a model defined in OpenAPI"""  # noqa: E501
-        if local_vars_configuration is None:
-            local_vars_configuration = Configuration()
-        self.local_vars_configuration = local_vars_configuration
-
-        self._url = None
-        self._name = None
-        self._owner = None
-        self._kind = None
-        self.discriminator = None
-
-        if url is not None:
-            self.url = url
-        if name is not None:
-            self.name = name
-        if owner is not None:
-            self.owner = owner
-        if kind is not None:
-            self.kind = kind
-
-    @property
-    def url(self):
-        """Gets the url of this QEndpoint.  # noqa: E501
-
-
-        :return: The url of this QEndpoint.  # noqa: E501
-        :rtype: str
-        """
-        return self._url
-
-    @url.setter
-    def url(self, url):
-        """Sets the url of this QEndpoint.
-
-
-        :param url: The url of this QEndpoint.  # noqa: E501
-        :type: str
-        """
-
-        self._url = url
-
-    @property
-    def name(self):
-        """Gets the name of this QEndpoint.  # noqa: E501
-
-
-        :return: The name of this QEndpoint.  # noqa: E501
-        :rtype: str
-        """
-        return self._name
-
-    @name.setter
-    def name(self, name):
-        """Sets the name of this QEndpoint.
-
-
-        :param name: The name of this QEndpoint.  # noqa: E501
-        :type: str
-        """
-
-        self._name = name
-
-    @property
-    def owner(self):
-        """Gets the owner of this QEndpoint.  # noqa: E501
-
-
-        :return: The owner of this QEndpoint.  # noqa: E501
-        :rtype: str
-        """
-        return self._owner
-
-    @owner.setter
-    def owner(self, owner):
-        """Sets the owner of this QEndpoint.
-
-
-        :param owner: The owner of this QEndpoint.  # noqa: E501
-        :type: str
-        """
-
-        self._owner = owner
-
-    @property
-    def kind(self):
-        """Gets the kind of this QEndpoint.  # noqa: E501
-
-
-        :return: The kind of this QEndpoint.  # noqa: E501
-        :rtype: str
-        """
-        return self._kind
-
-    @kind.setter
-    def kind(self, kind):
-        """Sets the kind of this QEndpoint.
-
-
-        :param kind: The kind of this QEndpoint.  # noqa: E501
-        :type: str
-        """
-        allowed_values = ["EMAIL_IMPORT_ENDPOINT", "REST_IMPORT_ENDPOINT", "DB_IMPORT_ENDPOINT"]  # noqa: E501
-        if self.local_vars_configuration.client_side_validation and kind not in allowed_values:  # noqa: E501
-            raise ValueError(
-                "Invalid value for `kind` ({0}), must be one of {1}"  # noqa: E501
-                .format(kind, allowed_values)
-            )
-
-        self._kind = kind
-
-    def to_dict(self):
-        """Returns the model properties as a dict"""
-        result = {}
-
-        for attr, _ in six.iteritems(self.openapi_types):
-            value = getattr(self, attr)
-            if isinstance(value, list):
-                result[attr] = list(map(
-                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
-                    value
-                ))
-            elif hasattr(value, "to_dict"):
-                result[attr] = value.to_dict()
-            elif isinstance(value, dict):
-                result[attr] = dict(map(
-                    lambda item: (item[0], item[1].to_dict())
-                    if hasattr(item[1], "to_dict") else item,
-                    value.items()
-                ))
-            else:
-                result[attr] = value
-
-        return result
-
-    def to_str(self):
-        """Returns the string representation of the model"""
-        return pprint.pformat(self.to_dict())
-
-    def __repr__(self):
-        """For `print` and `pprint`"""
-        return self.to_str()
-
-    def __eq__(self, other):
-        """Returns true if both objects are equal"""
-        if not isinstance(other, QEndpoint):
-            return False
-
-        return self.to_dict() == other.to_dict()
-
-    def __ne__(self, other):
-        """Returns true if both objects are not equal"""
-        if not isinstance(other, QEndpoint):
-            return True
-
-        return self.to_dict() != other.to_dict()
diff --git a/bitdotio/models/q_user.py b/bitdotio/models/q_user.py
deleted file mode 100644
index 87e4b3a..0000000
--- a/bitdotio/models/q_user.py
+++ /dev/null
@@ -1,311 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import pprint
-import re  # noqa: F401
-
-import six
-
-from bitdotio.configuration import Configuration
-
-
-class QUser(object):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-    """
-
-    """
-    Attributes:
-      openapi_types (dict): The key is attribute name
-                            and the value is attribute type.
-      attribute_map (dict): The key is attribute name
-                            and the value is json key in definition.
-    """
-    openapi_types = {
-        'connections': 'list[str]',
-        'date_joined': 'datetime',
-        'first_name': 'str',
-        'last_name': 'str',
-        'profile': 'QUserProfile',
-        'repos_owned': 'list[str]',
-        'url': 'str',
-        'username': 'str'
-    }
-
-    attribute_map = {
-        'connections': 'connections',
-        'date_joined': 'date_joined',
-        'first_name': 'first_name',
-        'last_name': 'last_name',
-        'profile': 'profile',
-        'repos_owned': 'repos_owned',
-        'url': 'url',
-        'username': 'username'
-    }
-
-    def __init__(self, connections=None, date_joined=None, first_name=None, last_name=None, profile=None, repos_owned=None, url=None, username=None, local_vars_configuration=None):  # noqa: E501
-        """QUser - a model defined in OpenAPI"""  # noqa: E501
-        if local_vars_configuration is None:
-            local_vars_configuration = Configuration()
-        self.local_vars_configuration = local_vars_configuration
-
-        self._connections = None
-        self._date_joined = None
-        self._first_name = None
-        self._last_name = None
-        self._profile = None
-        self._repos_owned = None
-        self._url = None
-        self._username = None
-        self.discriminator = None
-
-        if connections is not None:
-            self.connections = connections
-        if date_joined is not None:
-            self.date_joined = date_joined
-        if first_name is not None:
-            self.first_name = first_name
-        if last_name is not None:
-            self.last_name = last_name
-        self.profile = profile
-        if repos_owned is not None:
-            self.repos_owned = repos_owned
-        if url is not None:
-            self.url = url
-        if username is not None:
-            self.username = username
-
-    @property
-    def connections(self):
-        """Gets the connections of this QUser.  # noqa: E501
-
-
-        :return: The connections of this QUser.  # noqa: E501
-        :rtype: list[str]
-        """
-        return self._connections
-
-    @connections.setter
-    def connections(self, connections):
-        """Sets the connections of this QUser.
-
-
-        :param connections: The connections of this QUser.  # noqa: E501
-        :type: list[str]
-        """
-
-        self._connections = connections
-
-    @property
-    def date_joined(self):
-        """Gets the date_joined of this QUser.  # noqa: E501
-
-
-        :return: The date_joined of this QUser.  # noqa: E501
-        :rtype: datetime
-        """
-        return self._date_joined
-
-    @date_joined.setter
-    def date_joined(self, date_joined):
-        """Sets the date_joined of this QUser.
-
-
-        :param date_joined: The date_joined of this QUser.  # noqa: E501
-        :type: datetime
-        """
-
-        self._date_joined = date_joined
-
-    @property
-    def first_name(self):
-        """Gets the first_name of this QUser.  # noqa: E501
-
-
-        :return: The first_name of this QUser.  # noqa: E501
-        :rtype: str
-        """
-        return self._first_name
-
-    @first_name.setter
-    def first_name(self, first_name):
-        """Sets the first_name of this QUser.
-
-
-        :param first_name: The first_name of this QUser.  # noqa: E501
-        :type: str
-        """
-        if (self.local_vars_configuration.client_side_validation and
-                first_name is not None and len(first_name) > 150):
-            raise ValueError("Invalid value for `first_name`, length must be less than or equal to `150`")  # noqa: E501
-
-        self._first_name = first_name
-
-    @property
-    def last_name(self):
-        """Gets the last_name of this QUser.  # noqa: E501
-
-
-        :return: The last_name of this QUser.  # noqa: E501
-        :rtype: str
-        """
-        return self._last_name
-
-    @last_name.setter
-    def last_name(self, last_name):
-        """Sets the last_name of this QUser.
-
-
-        :param last_name: The last_name of this QUser.  # noqa: E501
-        :type: str
-        """
-        if (self.local_vars_configuration.client_side_validation and
-                last_name is not None and len(last_name) > 150):
-            raise ValueError("Invalid value for `last_name`, length must be less than or equal to `150`")  # noqa: E501
-
-        self._last_name = last_name
-
-    @property
-    def profile(self):
-        """Gets the profile of this QUser.  # noqa: E501
-
-
-        :return: The profile of this QUser.  # noqa: E501
-        :rtype: QUserProfile
-        """
-        return self._profile
-
-    @profile.setter
-    def profile(self, profile):
-        """Sets the profile of this QUser.
-
-
-        :param profile: The profile of this QUser.  # noqa: E501
-        :type: QUserProfile
-        """
-        if self.local_vars_configuration.client_side_validation and profile is None:  # noqa: E501
-            raise ValueError("Invalid value for `profile`, must not be `None`")  # noqa: E501
-
-        self._profile = profile
-
-    @property
-    def repos_owned(self):
-        """Gets the repos_owned of this QUser.  # noqa: E501
-
-
-        :return: The repos_owned of this QUser.  # noqa: E501
-        :rtype: list[str]
-        """
-        return self._repos_owned
-
-    @repos_owned.setter
-    def repos_owned(self, repos_owned):
-        """Sets the repos_owned of this QUser.
-
-
-        :param repos_owned: The repos_owned of this QUser.  # noqa: E501
-        :type: list[str]
-        """
-
-        self._repos_owned = repos_owned
-
-    @property
-    def url(self):
-        """Gets the url of this QUser.  # noqa: E501
-
-
-        :return: The url of this QUser.  # noqa: E501
-        :rtype: str
-        """
-        return self._url
-
-    @url.setter
-    def url(self, url):
-        """Sets the url of this QUser.
-
-
-        :param url: The url of this QUser.  # noqa: E501
-        :type: str
-        """
-
-        self._url = url
-
-    @property
-    def username(self):
-        """Gets the username of this QUser.  # noqa: E501
-
-        Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.  # noqa: E501
-
-        :return: The username of this QUser.  # noqa: E501
-        :rtype: str
-        """
-        return self._username
-
-    @username.setter
-    def username(self, username):
-        """Sets the username of this QUser.
-
-        Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.  # noqa: E501
-
-        :param username: The username of this QUser.  # noqa: E501
-        :type: str
-        """
-
-        self._username = username
-
-    def to_dict(self):
-        """Returns the model properties as a dict"""
-        result = {}
-
-        for attr, _ in six.iteritems(self.openapi_types):
-            value = getattr(self, attr)
-            if isinstance(value, list):
-                result[attr] = list(map(
-                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
-                    value
-                ))
-            elif hasattr(value, "to_dict"):
-                result[attr] = value.to_dict()
-            elif isinstance(value, dict):
-                result[attr] = dict(map(
-                    lambda item: (item[0], item[1].to_dict())
-                    if hasattr(item[1], "to_dict") else item,
-                    value.items()
-                ))
-            else:
-                result[attr] = value
-
-        return result
-
-    def to_str(self):
-        """Returns the string representation of the model"""
-        return pprint.pformat(self.to_dict())
-
-    def __repr__(self):
-        """For `print` and `pprint`"""
-        return self.to_str()
-
-    def __eq__(self, other):
-        """Returns true if both objects are equal"""
-        if not isinstance(other, QUser):
-            return False
-
-        return self.to_dict() == other.to_dict()
-
-    def __ne__(self, other):
-        """Returns true if both objects are not equal"""
-        if not isinstance(other, QUser):
-            return True
-
-        return self.to_dict() != other.to_dict()
diff --git a/bitdotio/models/q_user_profile.py b/bitdotio/models/q_user_profile.py
deleted file mode 100644
index 0d91865..0000000
--- a/bitdotio/models/q_user_profile.py
+++ /dev/null
@@ -1,245 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import pprint
-import re  # noqa: F401
-
-import six
-
-from bitdotio.configuration import Configuration
-
-
-class QUserProfile(object):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-    """
-
-    """
-    Attributes:
-      openapi_types (dict): The key is attribute name
-                            and the value is attribute type.
-      attribute_map (dict): The key is attribute name
-                            and the value is json key in definition.
-    """
-    openapi_types = {
-        'bio': 'str',
-        'website': 'str',
-        'public_status': 'str',
-        'picture_path': 'str',
-        'freeform_location': 'str'
-    }
-
-    attribute_map = {
-        'bio': 'bio',
-        'website': 'website',
-        'public_status': 'public_status',
-        'picture_path': 'picture_path',
-        'freeform_location': 'freeform_location'
-    }
-
-    def __init__(self, bio=None, website=None, public_status=None, picture_path=None, freeform_location=None, local_vars_configuration=None):  # noqa: E501
-        """QUserProfile - a model defined in OpenAPI"""  # noqa: E501
-        if local_vars_configuration is None:
-            local_vars_configuration = Configuration()
-        self.local_vars_configuration = local_vars_configuration
-
-        self._bio = None
-        self._website = None
-        self._public_status = None
-        self._picture_path = None
-        self._freeform_location = None
-        self.discriminator = None
-
-        if bio is not None:
-            self.bio = bio
-        if website is not None:
-            self.website = website
-        if public_status is not None:
-            self.public_status = public_status
-        if picture_path is not None:
-            self.picture_path = picture_path
-        if freeform_location is not None:
-            self.freeform_location = freeform_location
-
-    @property
-    def bio(self):
-        """Gets the bio of this QUserProfile.  # noqa: E501
-
-
-        :return: The bio of this QUserProfile.  # noqa: E501
-        :rtype: str
-        """
-        return self._bio
-
-    @bio.setter
-    def bio(self, bio):
-        """Sets the bio of this QUserProfile.
-
-
-        :param bio: The bio of this QUserProfile.  # noqa: E501
-        :type: str
-        """
-        if (self.local_vars_configuration.client_side_validation and
-                bio is not None and len(bio) > 500):
-            raise ValueError("Invalid value for `bio`, length must be less than or equal to `500`")  # noqa: E501
-
-        self._bio = bio
-
-    @property
-    def website(self):
-        """Gets the website of this QUserProfile.  # noqa: E501
-
-
-        :return: The website of this QUserProfile.  # noqa: E501
-        :rtype: str
-        """
-        return self._website
-
-    @website.setter
-    def website(self, website):
-        """Sets the website of this QUserProfile.
-
-
-        :param website: The website of this QUserProfile.  # noqa: E501
-        :type: str
-        """
-        if (self.local_vars_configuration.client_side_validation and
-                website is not None and len(website) > 200):
-            raise ValueError("Invalid value for `website`, length must be less than or equal to `200`")  # noqa: E501
-        if (self.local_vars_configuration.client_side_validation and
-                website is not None and not re.search(r'^(?:[a-z0-9.+-]*):\/\/(?:[^\s:@\/]+(?::[^\s:@\/]*)?@)?(?:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|\[[0-9a-f:.]+\]|([a-z¡-￿0-9](?:[a-z¡-￿0-9-]{0,61}[a-z¡-￿0-9])?(?:\.(?!-)[a-z¡-￿0-9-]{1,63}(?<!-))*\.(?!-)(?:[a-z¡-￿-]{2,63}|xn--[a-z0-9]{1,59})(?<!-)\.?|localhost))(?::\d{2,5})?(?:[\/?#][^\s]*)?\z', website)):  # noqa: E501
-            raise ValueError(r"Invalid value for `website`, must be a follow pattern or equal to `/^(?:[a-z0-9.+-]*):\/\/(?:[^\s:@\/]+(?::[^\s:@\/]*)?@)?(?:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|\[[0-9a-f:.]+\]|([a-z¡-￿0-9](?:[a-z¡-￿0-9-]{0,61}[a-z¡-￿0-9])?(?:\.(?!-)[a-z¡-￿0-9-]{1,63}(?<!-))*\.(?!-)(?:[a-z¡-￿-]{2,63}|xn--[a-z0-9]{1,59})(?<!-)\.?|localhost))(?::\d{2,5})?(?:[\/?#][^\s]*)?\z/`")  # noqa: E501
-
-        self._website = website
-
-    @property
-    def public_status(self):
-        """Gets the public_status of this QUserProfile.  # noqa: E501
-
-
-        :return: The public_status of this QUserProfile.  # noqa: E501
-        :rtype: str
-        """
-        return self._public_status
-
-    @public_status.setter
-    def public_status(self, public_status):
-        """Sets the public_status of this QUserProfile.
-
-
-        :param public_status: The public_status of this QUserProfile.  # noqa: E501
-        :type: str
-        """
-        if (self.local_vars_configuration.client_side_validation and
-                public_status is not None and len(public_status) > 500):
-            raise ValueError("Invalid value for `public_status`, length must be less than or equal to `500`")  # noqa: E501
-
-        self._public_status = public_status
-
-    @property
-    def picture_path(self):
-        """Gets the picture_path of this QUserProfile.  # noqa: E501
-
-
-        :return: The picture_path of this QUserProfile.  # noqa: E501
-        :rtype: str
-        """
-        return self._picture_path
-
-    @picture_path.setter
-    def picture_path(self, picture_path):
-        """Sets the picture_path of this QUserProfile.
-
-
-        :param picture_path: The picture_path of this QUserProfile.  # noqa: E501
-        :type: str
-        """
-        if (self.local_vars_configuration.client_side_validation and
-                picture_path is not None and len(picture_path) > 200):
-            raise ValueError("Invalid value for `picture_path`, length must be less than or equal to `200`")  # noqa: E501
-        if (self.local_vars_configuration.client_side_validation and
-                picture_path is not None and not re.search(r'^(?:[a-z0-9.+-]*):\/\/(?:[^\s:@\/]+(?::[^\s:@\/]*)?@)?(?:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|\[[0-9a-f:.]+\]|([a-z¡-￿0-9](?:[a-z¡-￿0-9-]{0,61}[a-z¡-￿0-9])?(?:\.(?!-)[a-z¡-￿0-9-]{1,63}(?<!-))*\.(?!-)(?:[a-z¡-￿-]{2,63}|xn--[a-z0-9]{1,59})(?<!-)\.?|localhost))(?::\d{2,5})?(?:[\/?#][^\s]*)?\z', picture_path)):  # noqa: E501
-            raise ValueError(r"Invalid value for `picture_path`, must be a follow pattern or equal to `/^(?:[a-z0-9.+-]*):\/\/(?:[^\s:@\/]+(?::[^\s:@\/]*)?@)?(?:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|\[[0-9a-f:.]+\]|([a-z¡-￿0-9](?:[a-z¡-￿0-9-]{0,61}[a-z¡-￿0-9])?(?:\.(?!-)[a-z¡-￿0-9-]{1,63}(?<!-))*\.(?!-)(?:[a-z¡-￿-]{2,63}|xn--[a-z0-9]{1,59})(?<!-)\.?|localhost))(?::\d{2,5})?(?:[\/?#][^\s]*)?\z/`")  # noqa: E501
-
-        self._picture_path = picture_path
-
-    @property
-    def freeform_location(self):
-        """Gets the freeform_location of this QUserProfile.  # noqa: E501
-
-
-        :return: The freeform_location of this QUserProfile.  # noqa: E501
-        :rtype: str
-        """
-        return self._freeform_location
-
-    @freeform_location.setter
-    def freeform_location(self, freeform_location):
-        """Sets the freeform_location of this QUserProfile.
-
-
-        :param freeform_location: The freeform_location of this QUserProfile.  # noqa: E501
-        :type: str
-        """
-        if (self.local_vars_configuration.client_side_validation and
-                freeform_location is not None and len(freeform_location) > 100):
-            raise ValueError("Invalid value for `freeform_location`, length must be less than or equal to `100`")  # noqa: E501
-
-        self._freeform_location = freeform_location
-
-    def to_dict(self):
-        """Returns the model properties as a dict"""
-        result = {}
-
-        for attr, _ in six.iteritems(self.openapi_types):
-            value = getattr(self, attr)
-            if isinstance(value, list):
-                result[attr] = list(map(
-                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
-                    value
-                ))
-            elif hasattr(value, "to_dict"):
-                result[attr] = value.to_dict()
-            elif isinstance(value, dict):
-                result[attr] = dict(map(
-                    lambda item: (item[0], item[1].to_dict())
-                    if hasattr(item[1], "to_dict") else item,
-                    value.items()
-                ))
-            else:
-                result[attr] = value
-
-        return result
-
-    def to_str(self):
-        """Returns the string representation of the model"""
-        return pprint.pformat(self.to_dict())
-
-    def __repr__(self):
-        """For `print` and `pprint`"""
-        return self.to_str()
-
-    def __eq__(self, other):
-        """Returns true if both objects are equal"""
-        if not isinstance(other, QUserProfile):
-            return False
-
-        return self.to_dict() == other.to_dict()
-
-    def __ne__(self, other):
-        """Returns true if both objects are not equal"""
-        if not isinstance(other, QUserProfile):
-            return True
-
-        return self.to_dict() != other.to_dict()
diff --git a/bitdotio/models/query_result.py b/bitdotio/models/query_result.py
deleted file mode 100644
index 2ed5487..0000000
--- a/bitdotio/models/query_result.py
+++ /dev/null
@@ -1,175 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import pprint
-import re  # noqa: F401
-
-import six
-
-from bitdotio.configuration import Configuration
-
-
-class QueryResult(object):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-    """
-
-    """
-    Attributes:
-      openapi_types (dict): The key is attribute name
-                            and the value is attribute type.
-      attribute_map (dict): The key is attribute name
-                            and the value is json key in definition.
-    """
-    openapi_types = {
-        'query_string': 'str',
-        'fields': 'object',
-        'data': 'list[object]'
-    }
-
-    attribute_map = {
-        'query_string': 'query_string',
-        'fields': 'fields',
-        'data': 'data'
-    }
-
-    def __init__(self, query_string=None, fields=None, data=None, local_vars_configuration=None):  # noqa: E501
-        """QueryResult - a model defined in OpenAPI"""  # noqa: E501
-        if local_vars_configuration is None:
-            local_vars_configuration = Configuration()
-        self.local_vars_configuration = local_vars_configuration
-
-        self._query_string = None
-        self._fields = None
-        self._data = None
-        self.discriminator = None
-
-        self.query_string = query_string
-        self.fields = fields
-        self.data = data
-
-    @property
-    def query_string(self):
-        """Gets the query_string of this QueryResult.  # noqa: E501
-
-
-        :return: The query_string of this QueryResult.  # noqa: E501
-        :rtype: str
-        """
-        return self._query_string
-
-    @query_string.setter
-    def query_string(self, query_string):
-        """Sets the query_string of this QueryResult.
-
-
-        :param query_string: The query_string of this QueryResult.  # noqa: E501
-        :type: str
-        """
-        if self.local_vars_configuration.client_side_validation and query_string is None:  # noqa: E501
-            raise ValueError("Invalid value for `query_string`, must not be `None`")  # noqa: E501
-
-        self._query_string = query_string
-
-    @property
-    def fields(self):
-        """Gets the fields of this QueryResult.  # noqa: E501
-
-
-        :return: The fields of this QueryResult.  # noqa: E501
-        :rtype: object
-        """
-        return self._fields
-
-    @fields.setter
-    def fields(self, fields):
-        """Sets the fields of this QueryResult.
-
-
-        :param fields: The fields of this QueryResult.  # noqa: E501
-        :type: object
-        """
-        if self.local_vars_configuration.client_side_validation and fields is None:  # noqa: E501
-            raise ValueError("Invalid value for `fields`, must not be `None`")  # noqa: E501
-
-        self._fields = fields
-
-    @property
-    def data(self):
-        """Gets the data of this QueryResult.  # noqa: E501
-
-
-        :return: The data of this QueryResult.  # noqa: E501
-        :rtype: list[object]
-        """
-        return self._data
-
-    @data.setter
-    def data(self, data):
-        """Sets the data of this QueryResult.
-
-
-        :param data: The data of this QueryResult.  # noqa: E501
-        :type: list[object]
-        """
-        if self.local_vars_configuration.client_side_validation and data is None:  # noqa: E501
-            raise ValueError("Invalid value for `data`, must not be `None`")  # noqa: E501
-
-        self._data = data
-
-    def to_dict(self):
-        """Returns the model properties as a dict"""
-        result = {}
-
-        for attr, _ in six.iteritems(self.openapi_types):
-            value = getattr(self, attr)
-            if isinstance(value, list):
-                result[attr] = list(map(
-                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
-                    value
-                ))
-            elif hasattr(value, "to_dict"):
-                result[attr] = value.to_dict()
-            elif isinstance(value, dict):
-                result[attr] = dict(map(
-                    lambda item: (item[0], item[1].to_dict())
-                    if hasattr(item[1], "to_dict") else item,
-                    value.items()
-                ))
-            else:
-                result[attr] = value
-
-        return result
-
-    def to_str(self):
-        """Returns the string representation of the model"""
-        return pprint.pformat(self.to_dict())
-
-    def __repr__(self):
-        """For `print` and `pprint`"""
-        return self.to_str()
-
-    def __eq__(self, other):
-        """Returns true if both objects are equal"""
-        if not isinstance(other, QueryResult):
-            return False
-
-        return self.to_dict() == other.to_dict()
-
-    def __ne__(self, other):
-        """Returns true if both objects are not equal"""
-        if not isinstance(other, QueryResult):
-            return True
-
-        return self.to_dict() != other.to_dict()
diff --git a/bitdotio/models/repo.py b/bitdotio/models/repo.py
deleted file mode 100644
index 6a53eb8..0000000
--- a/bitdotio/models/repo.py
+++ /dev/null
@@ -1,543 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import pprint
-import re  # noqa: F401
-
-import six
-
-from bitdotio.configuration import Configuration
-
-
-class Repo(object):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-    """
-
-    """
-    Attributes:
-      openapi_types (dict): The key is attribute name
-                            and the value is attribute type.
-      attribute_map (dict): The key is attribute name
-                            and the value is json key in definition.
-    """
-    openapi_types = {
-        'url': 'str',
-        'name': 'str',
-        'creator': 'str',
-        'owner': 'str',
-        'description': 'str',
-        'watchers': 'list[str]',
-        'watcher_count': 'int',
-        'stars': 'list[str]',
-        'star_count': 'int',
-        'tables': 'list[str]',
-        'endpoints': 'list[str]',
-        'documentation': 'str',
-        'license': 'str',
-        'bytes': 'str',
-        'query_count': 'str',
-        'collaborators': 'list[RepoCollaborators]',
-        'is_private': 'bool'
-    }
-
-    attribute_map = {
-        'url': 'url',
-        'name': 'name',
-        'creator': 'creator',
-        'owner': 'owner',
-        'description': 'description',
-        'watchers': 'watchers',
-        'watcher_count': 'watcher_count',
-        'stars': 'stars',
-        'star_count': 'star_count',
-        'tables': 'tables',
-        'endpoints': 'endpoints',
-        'documentation': 'documentation',
-        'license': 'license',
-        'bytes': 'bytes',
-        'query_count': 'query_count',
-        'collaborators': 'collaborators',
-        'is_private': 'is_private'
-    }
-
-    def __init__(self, url=None, name=None, creator=None, owner=None, description=None, watchers=None, watcher_count=None, stars=None, star_count=None, tables=None, endpoints=None, documentation=None, license=None, bytes=None, query_count=None, collaborators=None, is_private=None, local_vars_configuration=None):  # noqa: E501
-        """Repo - a model defined in OpenAPI"""  # noqa: E501
-        if local_vars_configuration is None:
-            local_vars_configuration = Configuration()
-        self.local_vars_configuration = local_vars_configuration
-
-        self._url = None
-        self._name = None
-        self._creator = None
-        self._owner = None
-        self._description = None
-        self._watchers = None
-        self._watcher_count = None
-        self._stars = None
-        self._star_count = None
-        self._tables = None
-        self._endpoints = None
-        self._documentation = None
-        self._license = None
-        self._bytes = None
-        self._query_count = None
-        self._collaborators = None
-        self._is_private = None
-        self.discriminator = None
-
-        if url is not None:
-            self.url = url
-        self.name = name
-        if creator is not None:
-            self.creator = creator
-        if owner is not None:
-            self.owner = owner
-        if description is not None:
-            self.description = description
-        if watchers is not None:
-            self.watchers = watchers
-        if watcher_count is not None:
-            self.watcher_count = watcher_count
-        if stars is not None:
-            self.stars = stars
-        if star_count is not None:
-            self.star_count = star_count
-        if tables is not None:
-            self.tables = tables
-        if endpoints is not None:
-            self.endpoints = endpoints
-        if documentation is not None:
-            self.documentation = documentation
-        if license is not None:
-            self.license = license
-        if bytes is not None:
-            self.bytes = bytes
-        if query_count is not None:
-            self.query_count = query_count
-        if collaborators is not None:
-            self.collaborators = collaborators
-        if is_private is not None:
-            self.is_private = is_private
-
-    @property
-    def url(self):
-        """Gets the url of this Repo.  # noqa: E501
-
-
-        :return: The url of this Repo.  # noqa: E501
-        :rtype: str
-        """
-        return self._url
-
-    @url.setter
-    def url(self, url):
-        """Sets the url of this Repo.
-
-
-        :param url: The url of this Repo.  # noqa: E501
-        :type: str
-        """
-
-        self._url = url
-
-    @property
-    def name(self):
-        """Gets the name of this Repo.  # noqa: E501
-
-
-        :return: The name of this Repo.  # noqa: E501
-        :rtype: str
-        """
-        return self._name
-
-    @name.setter
-    def name(self, name):
-        """Sets the name of this Repo.
-
-
-        :param name: The name of this Repo.  # noqa: E501
-        :type: str
-        """
-        if self.local_vars_configuration.client_side_validation and name is None:  # noqa: E501
-            raise ValueError("Invalid value for `name`, must not be `None`")  # noqa: E501
-        if (self.local_vars_configuration.client_side_validation and
-                name is not None and len(name) > 200):
-            raise ValueError("Invalid value for `name`, length must be less than or equal to `200`")  # noqa: E501
-
-        self._name = name
-
-    @property
-    def creator(self):
-        """Gets the creator of this Repo.  # noqa: E501
-
-
-        :return: The creator of this Repo.  # noqa: E501
-        :rtype: str
-        """
-        return self._creator
-
-    @creator.setter
-    def creator(self, creator):
-        """Sets the creator of this Repo.
-
-
-        :param creator: The creator of this Repo.  # noqa: E501
-        :type: str
-        """
-
-        self._creator = creator
-
-    @property
-    def owner(self):
-        """Gets the owner of this Repo.  # noqa: E501
-
-
-        :return: The owner of this Repo.  # noqa: E501
-        :rtype: str
-        """
-        return self._owner
-
-    @owner.setter
-    def owner(self, owner):
-        """Sets the owner of this Repo.
-
-
-        :param owner: The owner of this Repo.  # noqa: E501
-        :type: str
-        """
-
-        self._owner = owner
-
-    @property
-    def description(self):
-        """Gets the description of this Repo.  # noqa: E501
-
-
-        :return: The description of this Repo.  # noqa: E501
-        :rtype: str
-        """
-        return self._description
-
-    @description.setter
-    def description(self, description):
-        """Sets the description of this Repo.
-
-
-        :param description: The description of this Repo.  # noqa: E501
-        :type: str
-        """
-        if (self.local_vars_configuration.client_side_validation and
-                description is not None and len(description) > 200):
-            raise ValueError("Invalid value for `description`, length must be less than or equal to `200`")  # noqa: E501
-
-        self._description = description
-
-    @property
-    def watchers(self):
-        """Gets the watchers of this Repo.  # noqa: E501
-
-
-        :return: The watchers of this Repo.  # noqa: E501
-        :rtype: list[str]
-        """
-        return self._watchers
-
-    @watchers.setter
-    def watchers(self, watchers):
-        """Sets the watchers of this Repo.
-
-
-        :param watchers: The watchers of this Repo.  # noqa: E501
-        :type: list[str]
-        """
-
-        self._watchers = watchers
-
-    @property
-    def watcher_count(self):
-        """Gets the watcher_count of this Repo.  # noqa: E501
-
-
-        :return: The watcher_count of this Repo.  # noqa: E501
-        :rtype: int
-        """
-        return self._watcher_count
-
-    @watcher_count.setter
-    def watcher_count(self, watcher_count):
-        """Sets the watcher_count of this Repo.
-
-
-        :param watcher_count: The watcher_count of this Repo.  # noqa: E501
-        :type: int
-        """
-
-        self._watcher_count = watcher_count
-
-    @property
-    def stars(self):
-        """Gets the stars of this Repo.  # noqa: E501
-
-
-        :return: The stars of this Repo.  # noqa: E501
-        :rtype: list[str]
-        """
-        return self._stars
-
-    @stars.setter
-    def stars(self, stars):
-        """Sets the stars of this Repo.
-
-
-        :param stars: The stars of this Repo.  # noqa: E501
-        :type: list[str]
-        """
-
-        self._stars = stars
-
-    @property
-    def star_count(self):
-        """Gets the star_count of this Repo.  # noqa: E501
-
-
-        :return: The star_count of this Repo.  # noqa: E501
-        :rtype: int
-        """
-        return self._star_count
-
-    @star_count.setter
-    def star_count(self, star_count):
-        """Sets the star_count of this Repo.
-
-
-        :param star_count: The star_count of this Repo.  # noqa: E501
-        :type: int
-        """
-
-        self._star_count = star_count
-
-    @property
-    def tables(self):
-        """Gets the tables of this Repo.  # noqa: E501
-
-
-        :return: The tables of this Repo.  # noqa: E501
-        :rtype: list[str]
-        """
-        return self._tables
-
-    @tables.setter
-    def tables(self, tables):
-        """Sets the tables of this Repo.
-
-
-        :param tables: The tables of this Repo.  # noqa: E501
-        :type: list[str]
-        """
-
-        self._tables = tables
-
-    @property
-    def endpoints(self):
-        """Gets the endpoints of this Repo.  # noqa: E501
-
-
-        :return: The endpoints of this Repo.  # noqa: E501
-        :rtype: list[str]
-        """
-        return self._endpoints
-
-    @endpoints.setter
-    def endpoints(self, endpoints):
-        """Sets the endpoints of this Repo.
-
-
-        :param endpoints: The endpoints of this Repo.  # noqa: E501
-        :type: list[str]
-        """
-
-        self._endpoints = endpoints
-
-    @property
-    def documentation(self):
-        """Gets the documentation of this Repo.  # noqa: E501
-
-
-        :return: The documentation of this Repo.  # noqa: E501
-        :rtype: str
-        """
-        return self._documentation
-
-    @documentation.setter
-    def documentation(self, documentation):
-        """Sets the documentation of this Repo.
-
-
-        :param documentation: The documentation of this Repo.  # noqa: E501
-        :type: str
-        """
-
-        self._documentation = documentation
-
-    @property
-    def license(self):
-        """Gets the license of this Repo.  # noqa: E501
-
-
-        :return: The license of this Repo.  # noqa: E501
-        :rtype: str
-        """
-        return self._license
-
-    @license.setter
-    def license(self, license):
-        """Sets the license of this Repo.
-
-
-        :param license: The license of this Repo.  # noqa: E501
-        :type: str
-        """
-
-        self._license = license
-
-    @property
-    def bytes(self):
-        """Gets the bytes of this Repo.  # noqa: E501
-
-
-        :return: The bytes of this Repo.  # noqa: E501
-        :rtype: str
-        """
-        return self._bytes
-
-    @bytes.setter
-    def bytes(self, bytes):
-        """Sets the bytes of this Repo.
-
-
-        :param bytes: The bytes of this Repo.  # noqa: E501
-        :type: str
-        """
-
-        self._bytes = bytes
-
-    @property
-    def query_count(self):
-        """Gets the query_count of this Repo.  # noqa: E501
-
-
-        :return: The query_count of this Repo.  # noqa: E501
-        :rtype: str
-        """
-        return self._query_count
-
-    @query_count.setter
-    def query_count(self, query_count):
-        """Sets the query_count of this Repo.
-
-
-        :param query_count: The query_count of this Repo.  # noqa: E501
-        :type: str
-        """
-
-        self._query_count = query_count
-
-    @property
-    def collaborators(self):
-        """Gets the collaborators of this Repo.  # noqa: E501
-
-
-        :return: The collaborators of this Repo.  # noqa: E501
-        :rtype: list[RepoCollaborators]
-        """
-        return self._collaborators
-
-    @collaborators.setter
-    def collaborators(self, collaborators):
-        """Sets the collaborators of this Repo.
-
-
-        :param collaborators: The collaborators of this Repo.  # noqa: E501
-        :type: list[RepoCollaborators]
-        """
-
-        self._collaborators = collaborators
-
-    @property
-    def is_private(self):
-        """Gets the is_private of this Repo.  # noqa: E501
-
-
-        :return: The is_private of this Repo.  # noqa: E501
-        :rtype: bool
-        """
-        return self._is_private
-
-    @is_private.setter
-    def is_private(self, is_private):
-        """Sets the is_private of this Repo.
-
-
-        :param is_private: The is_private of this Repo.  # noqa: E501
-        :type: bool
-        """
-
-        self._is_private = is_private
-
-    def to_dict(self):
-        """Returns the model properties as a dict"""
-        result = {}
-
-        for attr, _ in six.iteritems(self.openapi_types):
-            value = getattr(self, attr)
-            if isinstance(value, list):
-                result[attr] = list(map(
-                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
-                    value
-                ))
-            elif hasattr(value, "to_dict"):
-                result[attr] = value.to_dict()
-            elif isinstance(value, dict):
-                result[attr] = dict(map(
-                    lambda item: (item[0], item[1].to_dict())
-                    if hasattr(item[1], "to_dict") else item,
-                    value.items()
-                ))
-            else:
-                result[attr] = value
-
-        return result
-
-    def to_str(self):
-        """Returns the string representation of the model"""
-        return pprint.pformat(self.to_dict())
-
-    def __repr__(self):
-        """For `print` and `pprint`"""
-        return self.to_str()
-
-    def __eq__(self, other):
-        """Returns true if both objects are equal"""
-        if not isinstance(other, Repo):
-            return False
-
-        return self.to_dict() == other.to_dict()
-
-    def __ne__(self, other):
-        """Returns true if both objects are not equal"""
-        if not isinstance(other, Repo):
-            return True
-
-        return self.to_dict() != other.to_dict()
diff --git a/bitdotio/models/repo_collaborators.py b/bitdotio/models/repo_collaborators.py
deleted file mode 100644
index 1d72999..0000000
--- a/bitdotio/models/repo_collaborators.py
+++ /dev/null
@@ -1,173 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import pprint
-import re  # noqa: F401
-
-import six
-
-from bitdotio.configuration import Configuration
-
-
-class RepoCollaborators(object):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-    """
-
-    """
-    Attributes:
-      openapi_types (dict): The key is attribute name
-                            and the value is attribute type.
-      attribute_map (dict): The key is attribute name
-                            and the value is json key in definition.
-    """
-    openapi_types = {
-        'role': 'str',
-        'role_display': 'str',
-        'user': 'str'
-    }
-
-    attribute_map = {
-        'role': 'role',
-        'role_display': 'role_display',
-        'user': 'user'
-    }
-
-    def __init__(self, role=None, role_display=None, user=None, local_vars_configuration=None):  # noqa: E501
-        """RepoCollaborators - a model defined in OpenAPI"""  # noqa: E501
-        if local_vars_configuration is None:
-            local_vars_configuration = Configuration()
-        self.local_vars_configuration = local_vars_configuration
-
-        self._role = None
-        self._role_display = None
-        self._user = None
-        self.discriminator = None
-
-        self.role = role
-        if role_display is not None:
-            self.role_display = role_display
-        if user is not None:
-            self.user = user
-
-    @property
-    def role(self):
-        """Gets the role of this RepoCollaborators.  # noqa: E501
-
-
-        :return: The role of this RepoCollaborators.  # noqa: E501
-        :rtype: str
-        """
-        return self._role
-
-    @role.setter
-    def role(self, role):
-        """Sets the role of this RepoCollaborators.
-
-
-        :param role: The role of this RepoCollaborators.  # noqa: E501
-        :type: str
-        """
-        if self.local_vars_configuration.client_side_validation and role is None:  # noqa: E501
-            raise ValueError("Invalid value for `role`, must not be `None`")  # noqa: E501
-
-        self._role = role
-
-    @property
-    def role_display(self):
-        """Gets the role_display of this RepoCollaborators.  # noqa: E501
-
-
-        :return: The role_display of this RepoCollaborators.  # noqa: E501
-        :rtype: str
-        """
-        return self._role_display
-
-    @role_display.setter
-    def role_display(self, role_display):
-        """Sets the role_display of this RepoCollaborators.
-
-
-        :param role_display: The role_display of this RepoCollaborators.  # noqa: E501
-        :type: str
-        """
-
-        self._role_display = role_display
-
-    @property
-    def user(self):
-        """Gets the user of this RepoCollaborators.  # noqa: E501
-
-
-        :return: The user of this RepoCollaborators.  # noqa: E501
-        :rtype: str
-        """
-        return self._user
-
-    @user.setter
-    def user(self, user):
-        """Sets the user of this RepoCollaborators.
-
-
-        :param user: The user of this RepoCollaborators.  # noqa: E501
-        :type: str
-        """
-
-        self._user = user
-
-    def to_dict(self):
-        """Returns the model properties as a dict"""
-        result = {}
-
-        for attr, _ in six.iteritems(self.openapi_types):
-            value = getattr(self, attr)
-            if isinstance(value, list):
-                result[attr] = list(map(
-                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
-                    value
-                ))
-            elif hasattr(value, "to_dict"):
-                result[attr] = value.to_dict()
-            elif isinstance(value, dict):
-                result[attr] = dict(map(
-                    lambda item: (item[0], item[1].to_dict())
-                    if hasattr(item[1], "to_dict") else item,
-                    value.items()
-                ))
-            else:
-                result[attr] = value
-
-        return result
-
-    def to_str(self):
-        """Returns the string representation of the model"""
-        return pprint.pformat(self.to_dict())
-
-    def __repr__(self):
-        """For `print` and `pprint`"""
-        return self.to_str()
-
-    def __eq__(self, other):
-        """Returns true if both objects are equal"""
-        if not isinstance(other, RepoCollaborators):
-            return False
-
-        return self.to_dict() == other.to_dict()
-
-    def __ne__(self, other):
-        """Returns true if both objects are not equal"""
-        if not isinstance(other, RepoCollaborators):
-            return True
-
-        return self.to_dict() != other.to_dict()
diff --git a/bitdotio/models/table.py b/bitdotio/models/table.py
deleted file mode 100644
index 4918c4a..0000000
--- a/bitdotio/models/table.py
+++ /dev/null
@@ -1,305 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import pprint
-import re  # noqa: F401
-
-import six
-
-from bitdotio.configuration import Configuration
-
-
-class Table(object):
-    """NOTE: This class is auto generated by OpenAPI Generator.
-    Ref: https://openapi-generator.tech
-
-    Do not edit the class manually.
-    """
-
-    """
-    Attributes:
-      openapi_types (dict): The key is attribute name
-                            and the value is attribute type.
-      attribute_map (dict): The key is attribute name
-                            and the value is json key in definition.
-    """
-    openapi_types = {
-        'url': 'str',
-        'current_name': 'str',
-        'description': 'str',
-        'columns': 'list[str]',
-        'num_records': 'int',
-        'bytes': 'str',
-        'repo': 'str',
-        'documentation': 'str'
-    }
-
-    attribute_map = {
-        'url': 'url',
-        'current_name': 'current_name',
-        'description': 'description',
-        'columns': 'columns',
-        'num_records': 'num_records',
-        'bytes': 'bytes',
-        'repo': 'repo',
-        'documentation': 'documentation'
-    }
-
-    def __init__(self, url=None, current_name=None, description=None, columns=None, num_records=None, bytes=None, repo=None, documentation=None, local_vars_configuration=None):  # noqa: E501
-        """Table - a model defined in OpenAPI"""  # noqa: E501
-        if local_vars_configuration is None:
-            local_vars_configuration = Configuration()
-        self.local_vars_configuration = local_vars_configuration
-
-        self._url = None
-        self._current_name = None
-        self._description = None
-        self._columns = None
-        self._num_records = None
-        self._bytes = None
-        self._repo = None
-        self._documentation = None
-        self.discriminator = None
-
-        if url is not None:
-            self.url = url
-        if current_name is not None:
-            self.current_name = current_name
-        if description is not None:
-            self.description = description
-        if columns is not None:
-            self.columns = columns
-        if num_records is not None:
-            self.num_records = num_records
-        if bytes is not None:
-            self.bytes = bytes
-        if repo is not None:
-            self.repo = repo
-        if documentation is not None:
-            self.documentation = documentation
-
-    @property
-    def url(self):
-        """Gets the url of this Table.  # noqa: E501
-
-
-        :return: The url of this Table.  # noqa: E501
-        :rtype: str
-        """
-        return self._url
-
-    @url.setter
-    def url(self, url):
-        """Sets the url of this Table.
-
-
-        :param url: The url of this Table.  # noqa: E501
-        :type: str
-        """
-
-        self._url = url
-
-    @property
-    def current_name(self):
-        """Gets the current_name of this Table.  # noqa: E501
-
-
-        :return: The current_name of this Table.  # noqa: E501
-        :rtype: str
-        """
-        return self._current_name
-
-    @current_name.setter
-    def current_name(self, current_name):
-        """Sets the current_name of this Table.
-
-
-        :param current_name: The current_name of this Table.  # noqa: E501
-        :type: str
-        """
-
-        self._current_name = current_name
-
-    @property
-    def description(self):
-        """Gets the description of this Table.  # noqa: E501
-
-
-        :return: The description of this Table.  # noqa: E501
-        :rtype: str
-        """
-        return self._description
-
-    @description.setter
-    def description(self, description):
-        """Sets the description of this Table.
-
-
-        :param description: The description of this Table.  # noqa: E501
-        :type: str
-        """
-        if (self.local_vars_configuration.client_side_validation and
-                description is not None and len(description) > 400):
-            raise ValueError("Invalid value for `description`, length must be less than or equal to `400`")  # noqa: E501
-
-        self._description = description
-
-    @property
-    def columns(self):
-        """Gets the columns of this Table.  # noqa: E501
-
-
-        :return: The columns of this Table.  # noqa: E501
-        :rtype: list[str]
-        """
-        return self._columns
-
-    @columns.setter
-    def columns(self, columns):
-        """Sets the columns of this Table.
-
-
-        :param columns: The columns of this Table.  # noqa: E501
-        :type: list[str]
-        """
-
-        self._columns = columns
-
-    @property
-    def num_records(self):
-        """Gets the num_records of this Table.  # noqa: E501
-
-
-        :return: The num_records of this Table.  # noqa: E501
-        :rtype: int
-        """
-        return self._num_records
-
-    @num_records.setter
-    def num_records(self, num_records):
-        """Sets the num_records of this Table.
-
-
-        :param num_records: The num_records of this Table.  # noqa: E501
-        :type: int
-        """
-
-        self._num_records = num_records
-
-    @property
-    def bytes(self):
-        """Gets the bytes of this Table.  # noqa: E501
-
-
-        :return: The bytes of this Table.  # noqa: E501
-        :rtype: str
-        """
-        return self._bytes
-
-    @bytes.setter
-    def bytes(self, bytes):
-        """Sets the bytes of this Table.
-
-
-        :param bytes: The bytes of this Table.  # noqa: E501
-        :type: str
-        """
-
-        self._bytes = bytes
-
-    @property
-    def repo(self):
-        """Gets the repo of this Table.  # noqa: E501
-
-
-        :return: The repo of this Table.  # noqa: E501
-        :rtype: str
-        """
-        return self._repo
-
-    @repo.setter
-    def repo(self, repo):
-        """Sets the repo of this Table.
-
-
-        :param repo: The repo of this Table.  # noqa: E501
-        :type: str
-        """
-
-        self._repo = repo
-
-    @property
-    def documentation(self):
-        """Gets the documentation of this Table.  # noqa: E501
-
-
-        :return: The documentation of this Table.  # noqa: E501
-        :rtype: str
-        """
-        return self._documentation
-
-    @documentation.setter
-    def documentation(self, documentation):
-        """Sets the documentation of this Table.
-
-
-        :param documentation: The documentation of this Table.  # noqa: E501
-        :type: str
-        """
-
-        self._documentation = documentation
-
-    def to_dict(self):
-        """Returns the model properties as a dict"""
-        result = {}
-
-        for attr, _ in six.iteritems(self.openapi_types):
-            value = getattr(self, attr)
-            if isinstance(value, list):
-                result[attr] = list(map(
-                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
-                    value
-                ))
-            elif hasattr(value, "to_dict"):
-                result[attr] = value.to_dict()
-            elif isinstance(value, dict):
-                result[attr] = dict(map(
-                    lambda item: (item[0], item[1].to_dict())
-                    if hasattr(item[1], "to_dict") else item,
-                    value.items()
-                ))
-            else:
-                result[attr] = value
-
-        return result
-
-    def to_str(self):
-        """Returns the string representation of the model"""
-        return pprint.pformat(self.to_dict())
-
-    def __repr__(self):
-        """For `print` and `pprint`"""
-        return self.to_str()
-
-    def __eq__(self, other):
-        """Returns true if both objects are equal"""
-        if not isinstance(other, Table):
-            return False
-
-        return self.to_dict() == other.to_dict()
-
-    def __ne__(self, other):
-        """Returns true if both objects are not equal"""
-        if not isinstance(other, Table):
-            return True
-
-        return self.to_dict() != other.to_dict()
diff --git a/bitdotio/rest.py b/bitdotio/rest.py
deleted file mode 100644
index 7ebf370..0000000
--- a/bitdotio/rest.py
+++ /dev/null
@@ -1,292 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import io
-import json
-import logging
-import re
-import ssl
-from urllib.parse import urlencode
-
-import urllib3
-
-from bitdotio.exceptions import ApiException, UnauthorizedException, ForbiddenException, NotFoundException, ServiceException, ApiValueError
-
-
-logger = logging.getLogger(__name__)
-
-
-class RESTResponse(io.IOBase):
-
-    def __init__(self, resp):
-        self.urllib3_response = resp
-        self.status = resp.status
-        self.reason = resp.reason
-        self.data = resp.data
-
-    def getheaders(self):
-        """Returns a dictionary of the response headers."""
-        return self.urllib3_response.getheaders()
-
-    def getheader(self, name, default=None):
-        """Returns a given response header."""
-        return self.urllib3_response.getheader(name, default)
-
-
-class RESTClientObject(object):
-
-    def __init__(self, configuration, pools_size=4, maxsize=None):
-        # urllib3.PoolManager will pass all kw parameters to connectionpool
-        # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/poolmanager.py#L75  # noqa: E501
-        # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/connectionpool.py#L680  # noqa: E501
-        # maxsize is the number of requests to host that are allowed in parallel  # noqa: E501
-        # Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html  # noqa: E501
-
-        # cert_reqs
-        if configuration.verify_ssl:
-            cert_reqs = ssl.CERT_REQUIRED
-        else:
-            cert_reqs = ssl.CERT_NONE
-
-        addition_pool_args = {}
-        if configuration.assert_hostname is not None:
-            addition_pool_args['assert_hostname'] = configuration.assert_hostname  # noqa: E501
-
-        if configuration.retries is not None:
-            addition_pool_args['retries'] = configuration.retries
-
-        if configuration.socket_options is not None:
-            addition_pool_args['socket_options'] = configuration.socket_options
-
-        if maxsize is None:
-            if configuration.connection_pool_maxsize is not None:
-                maxsize = configuration.connection_pool_maxsize
-            else:
-                maxsize = 4
-
-        # https pool manager
-        if configuration.proxy:
-            self.pool_manager = urllib3.ProxyManager(
-                num_pools=pools_size,
-                maxsize=maxsize,
-                cert_reqs=cert_reqs,
-                ca_certs=configuration.ssl_ca_cert,
-                cert_file=configuration.cert_file,
-                key_file=configuration.key_file,
-                proxy_url=configuration.proxy,
-                proxy_headers=configuration.proxy_headers,
-                **addition_pool_args
-            )
-        else:
-            self.pool_manager = urllib3.PoolManager(
-                num_pools=pools_size,
-                maxsize=maxsize,
-                cert_reqs=cert_reqs,
-                ca_certs=configuration.ssl_ca_cert,
-                cert_file=configuration.cert_file,
-                key_file=configuration.key_file,
-                **addition_pool_args
-            )
-
-    def request(self, method, url, query_params=None, headers=None,
-                body=None, post_params=None, _preload_content=True,
-                _request_timeout=None):
-        """Perform requests.
-
-        :param method: http request method
-        :param url: http request url
-        :param query_params: query parameters in the url
-        :param headers: http request headers
-        :param body: request json body, for `application/json`
-        :param post_params: request post parameters,
-                            `application/x-www-form-urlencoded`
-                            and `multipart/form-data`
-        :param _preload_content: if False, the urllib3.HTTPResponse object will
-                                 be returned without reading/decoding response
-                                 data. Default is True.
-        :param _request_timeout: timeout setting for this request. If one
-                                 number provided, it will be total request
-                                 timeout. It can also be a pair (tuple) of
-                                 (connection, read) timeouts.
-        """
-        method = method.upper()
-        assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT',
-                          'PATCH', 'OPTIONS']
-
-        if post_params and body:
-            raise ApiValueError(
-                "body parameter cannot be used with post_params parameter."
-            )
-
-        post_params = post_params or {}
-        headers = headers or {}
-
-        timeout = None
-        if _request_timeout:
-            if isinstance(_request_timeout, (int, float)):  # noqa: E501,F821
-                timeout = urllib3.Timeout(total=_request_timeout)
-            elif (isinstance(_request_timeout, tuple) and
-                  len(_request_timeout) == 2):
-                timeout = urllib3.Timeout(
-                    connect=_request_timeout[0], read=_request_timeout[1])
-
-        if 'Content-Type' not in headers:
-            headers['Content-Type'] = 'application/json'
-
-        try:
-            # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`
-            if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:
-                if query_params:
-                    url += '?' + urlencode(query_params)
-                if re.search('json', headers['Content-Type'], re.IGNORECASE):
-                    request_body = None
-                    if body is not None:
-                        request_body = json.dumps(body)
-                    r = self.pool_manager.request(
-                        method, url,
-                        body=request_body,
-                        preload_content=_preload_content,
-                        timeout=timeout,
-                        headers=headers)
-                elif headers['Content-Type'] == 'application/x-www-form-urlencoded':  # noqa: E501
-                    r = self.pool_manager.request(
-                        method, url,
-                        fields=post_params,
-                        encode_multipart=False,
-                        preload_content=_preload_content,
-                        timeout=timeout,
-                        headers=headers)
-                elif headers['Content-Type'] == 'multipart/form-data':
-                    # must del headers['Content-Type'], or the correct
-                    # Content-Type which generated by urllib3 will be
-                    # overwritten.
-                    del headers['Content-Type']
-                    r = self.pool_manager.request(
-                        method, url,
-                        fields=post_params,
-                        encode_multipart=True,
-                        preload_content=_preload_content,
-                        timeout=timeout,
-                        headers=headers)
-                # Pass a `string` parameter directly in the body to support
-                # other content types than Json when `body` argument is
-                # provided in serialized form
-                elif isinstance(body, str) or isinstance(body, bytes):
-                    request_body = body
-                    r = self.pool_manager.request(
-                        method, url,
-                        body=request_body,
-                        preload_content=_preload_content,
-                        timeout=timeout,
-                        headers=headers)
-                else:
-                    # Cannot generate the request from given parameters
-                    msg = """Cannot prepare a request message for provided
-                             arguments. Please check that your arguments match
-                             declared content type."""
-                    raise ApiException(status=0, reason=msg)
-            # For `GET`, `HEAD`
-            else:
-                r = self.pool_manager.request(method, url,
-                                              fields=query_params,
-                                              preload_content=_preload_content,
-                                              timeout=timeout,
-                                              headers=headers)
-        except urllib3.exceptions.SSLError as e:
-            msg = "{0}\n{1}".format(type(e).__name__, str(e))
-            raise ApiException(status=0, reason=msg)
-
-        if _preload_content:
-            r = RESTResponse(r)
-
-            # log response body
-            logger.debug("response body: %s", r.data)
-
-        if not 200 <= r.status <= 299:
-            if r.status == 401:
-                raise UnauthorizedException(http_resp=r)
-
-            if r.status == 403:
-                raise ForbiddenException(http_resp=r)
-
-            if r.status == 404:
-                raise NotFoundException(http_resp=r)
-
-            if 500 <= r.status <= 599:
-                raise ServiceException(http_resp=r)
-
-            raise ApiException(http_resp=r)
-
-        return r
-
-    def GET(self, url, headers=None, query_params=None, _preload_content=True,
-            _request_timeout=None):
-        return self.request("GET", url,
-                            headers=headers,
-                            _preload_content=_preload_content,
-                            _request_timeout=_request_timeout,
-                            query_params=query_params)
-
-    def HEAD(self, url, headers=None, query_params=None, _preload_content=True,
-             _request_timeout=None):
-        return self.request("HEAD", url,
-                            headers=headers,
-                            _preload_content=_preload_content,
-                            _request_timeout=_request_timeout,
-                            query_params=query_params)
-
-    def OPTIONS(self, url, headers=None, query_params=None, post_params=None,
-                body=None, _preload_content=True, _request_timeout=None):
-        return self.request("OPTIONS", url,
-                            headers=headers,
-                            query_params=query_params,
-                            post_params=post_params,
-                            _preload_content=_preload_content,
-                            _request_timeout=_request_timeout,
-                            body=body)
-
-    def DELETE(self, url, headers=None, query_params=None, body=None,
-               _preload_content=True, _request_timeout=None):
-        return self.request("DELETE", url,
-                            headers=headers,
-                            query_params=query_params,
-                            _preload_content=_preload_content,
-                            _request_timeout=_request_timeout,
-                            body=body)
-
-    def POST(self, url, headers=None, query_params=None, post_params=None,
-             body=None, _preload_content=True, _request_timeout=None):
-        return self.request("POST", url,
-                            headers=headers,
-                            query_params=query_params,
-                            post_params=post_params,
-                            _preload_content=_preload_content,
-                            _request_timeout=_request_timeout,
-                            body=body)
-
-    def PUT(self, url, headers=None, query_params=None, post_params=None,
-            body=None, _preload_content=True, _request_timeout=None):
-        return self.request("PUT", url,
-                            headers=headers,
-                            query_params=query_params,
-                            post_params=post_params,
-                            _preload_content=_preload_content,
-                            _request_timeout=_request_timeout,
-                            body=body)
-
-    def PATCH(self, url, headers=None, query_params=None, post_params=None,
-              body=None, _preload_content=True, _request_timeout=None):
-        return self.request("PATCH", url,
-                            headers=headers,
-                            query_params=query_params,
-                            post_params=post_params,
-                            _preload_content=_preload_content,
-                            _request_timeout=_request_timeout,
-                            body=body)
diff --git a/bitdotio/utils.py b/bitdotio/utils.py
new file mode 100644
index 0000000..b753ba5
--- /dev/null
+++ b/bitdotio/utils.py
@@ -0,0 +1,22 @@
+import re
+
+
+_RE_TOKEN = re.compile(r"^v2_\w+$")
+_RE_DB_NAME = re.compile(r"^\w.{0,37}?/.{1,23}$")
+
+
+def validate_token(token: str):
+    if _RE_TOKEN.fullmatch(token) is None:
+        raise ValueError("Invalid access token")
+
+
+def validate_database_name(db_name: str):
+    if _RE_DB_NAME.fullmatch(db_name) is None:
+        raise ValueError("Invalid database name")
+
+
+def validate_min_max_conn(min_conn: int, max_conn: int):
+    if min_conn < 0 or max_conn < 0:
+        raise ValueError("min_conn and max_conn must both be greater than or equal to zero")
+    if min_conn >= max_conn:
+        raise ValueError("min_conn must be strictly less than max_conn")
diff --git a/docs/ApiBitdotio.md b/docs/ApiBitdotio.md
deleted file mode 100644
index ce0b529..0000000
--- a/docs/ApiBitdotio.md
+++ /dev/null
@@ -1,884 +0,0 @@
-# bitdotio.ApiBitdotio
-
-All URIs are relative to *https://api.bit.io/api/v1beta*
-
-Method | HTTP request | Description
-------------- | ------------- | -------------
-[**create_import_file**](ApiBitdotio.md#create_import_file) | **POST** /import/file/ | 
-[**create_import_json**](ApiBitdotio.md#create_import_json) | **POST** /import/json/ | 
-[**create_import_url**](ApiBitdotio.md#create_import_url) | **POST** /import/url/ | 
-[**create_query**](ApiBitdotio.md#create_query) | **POST** /query/ | 
-[**create_repo**](ApiBitdotio.md#create_repo) | **POST** /repos/ | 
-[**destroy_repo**](ApiBitdotio.md#destroy_repo) | **DELETE** /repos/{name}/ | 
-[**list_repos**](ApiBitdotio.md#list_repos) | **GET** /repos/ | 
-[**partial_update_repo**](ApiBitdotio.md#partial_update_repo) | **PATCH** /repos/{name}/ | 
-[**retrieve_ingestor_job**](ApiBitdotio.md#retrieve_ingestor_job) | **GET** /import/status/{q_uuid}/ | 
-[**retrieve_repo**](ApiBitdotio.md#retrieve_repo) | **GET** /repos/{name}/ | 
-[**update_repo**](ApiBitdotio.md#update_repo) | **PUT** /repos/{name}/ | 
-
-
-# **create_import_file**
-> IngestionResult create_import_file(file_to_import, repo_name)
-
-
-
-### Example
-
-* Bearer Authentication (bearerAuth):
-```python
-import time
-import bitdotio
-from bitdotio.api import api_bitdotio
-from bitdotio.model.ingestion_result import IngestionResult
-from pprint import pprint
-# Defining the host is optional and defaults to https://api.bit.io/api/v1beta
-# See configuration.py for a list of all supported configuration parameters.
-configuration = bitdotio.Configuration(
-    host = "https://api.bit.io/api/v1beta"
-)
-
-# The client must configure the authentication and authorization parameters
-# in accordance with the API server security policy.
-# Examples for each auth method are provided below, use the example that
-# satisfies your auth use case.
-
-# Configure Bearer authorization: bearerAuth
-configuration = bitdotio.Configuration(
-    access_token = 'YOUR_BEARER_TOKEN'
-)
-
-# Enter a context with an instance of the API client
-with bitdotio.ApiClient(configuration) as api_client:
-    # Create an instance of the API class
-    api_instance = api_bitdotio.ApiBitdotio(api_client)
-    file_to_import = open('/path/to/file', 'rb') # file_type | 
-    repo_name = "repo_name_example" # str | 
-    table_name = "table_name_example" # str |  (optional)
-    create_table_if_not_exists = True # bool |  (optional) if omitted the server will use the default value of True
-
-    # example passing only required values which don't have defaults set
-    try:
-        api_response = api_instance.create_import_file(file_to_import, repo_name)
-        pprint(api_response)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->create_import_file: %s\n" % e)
-
-    # example passing only required values which don't have defaults set
-    # and optional values
-    try:
-        api_response = api_instance.create_import_file(file_to_import, repo_name, table_name=table_name, create_table_if_not_exists=create_table_if_not_exists)
-        pprint(api_response)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->create_import_file: %s\n" % e)
-```
-
-
-### Parameters
-
-Name | Type | Description  | Notes
-------------- | ------------- | ------------- | -------------
- **file_to_import** | **file_type**|  |
- **repo_name** | **str**|  |
- **table_name** | **str**|  | [optional]
- **create_table_if_not_exists** | **bool**|  | [optional] if omitted the server will use the default value of True
-
-### Return type
-
-[**IngestionResult**](IngestionResult.md)
-
-### Authorization
-
-[bearerAuth](../README.md#bearerAuth)
-
-### HTTP request headers
-
- - **Content-Type**: multipart/form-data
- - **Accept**: application/json
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-**201** |  |  -  |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
-# **create_import_json**
-> IngestionResult create_import_json()
-
-
-
-### Example
-
-* Bearer Authentication (bearerAuth):
-```python
-import time
-import bitdotio
-from bitdotio.api import api_bitdotio
-from bitdotio.model.ingestion_result import IngestionResult
-from bitdotio.model.import_json import ImportJson
-from pprint import pprint
-# Defining the host is optional and defaults to https://api.bit.io/api/v1beta
-# See configuration.py for a list of all supported configuration parameters.
-configuration = bitdotio.Configuration(
-    host = "https://api.bit.io/api/v1beta"
-)
-
-# The client must configure the authentication and authorization parameters
-# in accordance with the API server security policy.
-# Examples for each auth method are provided below, use the example that
-# satisfies your auth use case.
-
-# Configure Bearer authorization: bearerAuth
-configuration = bitdotio.Configuration(
-    access_token = 'YOUR_BEARER_TOKEN'
-)
-
-# Enter a context with an instance of the API client
-with bitdotio.ApiClient(configuration) as api_client:
-    # Create an instance of the API class
-    api_instance = api_bitdotio.ApiBitdotio(api_client)
-    import_json = ImportJson(
-        data="data_example",
-        table_name="table_name_example",
-        repo_name="repo_name_example",
-        create_table_if_not_exists=True,
-    ) # ImportJson |  (optional)
-
-    # example passing only required values which don't have defaults set
-    # and optional values
-    try:
-        api_response = api_instance.create_import_json(import_json=import_json)
-        pprint(api_response)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->create_import_json: %s\n" % e)
-```
-
-
-### Parameters
-
-Name | Type | Description  | Notes
-------------- | ------------- | ------------- | -------------
- **import_json** | [**ImportJson**](ImportJson.md)|  | [optional]
-
-### Return type
-
-[**IngestionResult**](IngestionResult.md)
-
-### Authorization
-
-[bearerAuth](../README.md#bearerAuth)
-
-### HTTP request headers
-
- - **Content-Type**: application/json, application/x-www-form-urlencoded, multipart/form-data
- - **Accept**: application/json
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-**201** |  |  -  |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
-# **create_import_url**
-> IngestionResult create_import_url()
-
-
-
-### Example
-
-* Bearer Authentication (bearerAuth):
-```python
-import time
-import bitdotio
-from bitdotio.api import api_bitdotio
-from bitdotio.model.ingestion_result import IngestionResult
-from bitdotio.model.import_url import ImportUrl
-from pprint import pprint
-# Defining the host is optional and defaults to https://api.bit.io/api/v1beta
-# See configuration.py for a list of all supported configuration parameters.
-configuration = bitdotio.Configuration(
-    host = "https://api.bit.io/api/v1beta"
-)
-
-# The client must configure the authentication and authorization parameters
-# in accordance with the API server security policy.
-# Examples for each auth method are provided below, use the example that
-# satisfies your auth use case.
-
-# Configure Bearer authorization: bearerAuth
-configuration = bitdotio.Configuration(
-    access_token = 'YOUR_BEARER_TOKEN'
-)
-
-# Enter a context with an instance of the API client
-with bitdotio.ApiClient(configuration) as api_client:
-    # Create an instance of the API class
-    api_instance = api_bitdotio.ApiBitdotio(api_client)
-    import_url = ImportUrl(
-        url="url_example",
-        table_name="table_name_example",
-        repo_name="repo_name_example",
-        create_table_if_not_exists=True,
-    ) # ImportUrl |  (optional)
-
-    # example passing only required values which don't have defaults set
-    # and optional values
-    try:
-        api_response = api_instance.create_import_url(import_url=import_url)
-        pprint(api_response)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->create_import_url: %s\n" % e)
-```
-
-
-### Parameters
-
-Name | Type | Description  | Notes
-------------- | ------------- | ------------- | -------------
- **import_url** | [**ImportUrl**](ImportUrl.md)|  | [optional]
-
-### Return type
-
-[**IngestionResult**](IngestionResult.md)
-
-### Authorization
-
-[bearerAuth](../README.md#bearerAuth)
-
-### HTTP request headers
-
- - **Content-Type**: application/json, application/x-www-form-urlencoded, multipart/form-data
- - **Accept**: application/json
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-**201** |  |  -  |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
-# **create_query**
-> Query create_query()
-
-
-
-### Example
-
-* Bearer Authentication (bearerAuth):
-```python
-import time
-import bitdotio
-from bitdotio.api import api_bitdotio
-from bitdotio.model.query import Query
-from pprint import pprint
-# Defining the host is optional and defaults to https://api.bit.io/api/v1beta
-# See configuration.py for a list of all supported configuration parameters.
-configuration = bitdotio.Configuration(
-    host = "https://api.bit.io/api/v1beta"
-)
-
-# The client must configure the authentication and authorization parameters
-# in accordance with the API server security policy.
-# Examples for each auth method are provided below, use the example that
-# satisfies your auth use case.
-
-# Configure Bearer authorization: bearerAuth
-configuration = bitdotio.Configuration(
-    access_token = 'YOUR_BEARER_TOKEN'
-)
-
-# Enter a context with an instance of the API client
-with bitdotio.ApiClient(configuration) as api_client:
-    # Create an instance of the API class
-    api_instance = api_bitdotio.ApiBitdotio(api_client)
-    query = Query(
-        query_string="query_string_example",
-    ) # Query |  (optional)
-
-    # example passing only required values which don't have defaults set
-    # and optional values
-    try:
-        api_response = api_instance.create_query(query=query)
-        pprint(api_response)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->create_query: %s\n" % e)
-```
-
-
-### Parameters
-
-Name | Type | Description  | Notes
-------------- | ------------- | ------------- | -------------
- **query** | [**Query**](Query.md)|  | [optional]
-
-### Return type
-
-[**Query**](Query.md)
-
-### Authorization
-
-[bearerAuth](../README.md#bearerAuth)
-
-### HTTP request headers
-
- - **Content-Type**: application/json, application/x-www-form-urlencoded, multipart/form-data
- - **Accept**: application/json
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-**201** |  |  -  |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
-# **create_repo**
-> Repo create_repo()
-
-
-
-Create a repository owned by the authenticated user. The request body must contain the required fields for the repository.
-
-### Example
-
-* Bearer Authentication (bearerAuth):
-```python
-import time
-import bitdotio
-from bitdotio.api import api_bitdotio
-from bitdotio.model.repo import Repo
-from pprint import pprint
-# Defining the host is optional and defaults to https://api.bit.io/api/v1beta
-# See configuration.py for a list of all supported configuration parameters.
-configuration = bitdotio.Configuration(
-    host = "https://api.bit.io/api/v1beta"
-)
-
-# The client must configure the authentication and authorization parameters
-# in accordance with the API server security policy.
-# Examples for each auth method are provided below, use the example that
-# satisfies your auth use case.
-
-# Configure Bearer authorization: bearerAuth
-configuration = bitdotio.Configuration(
-    access_token = 'YOUR_BEARER_TOKEN'
-)
-
-# Enter a context with an instance of the API client
-with bitdotio.ApiClient(configuration) as api_client:
-    # Create an instance of the API class
-    api_instance = api_bitdotio.ApiBitdotio(api_client)
-    repo = Repo(
-        name="name_example",
-        description="description_example",
-        documentation="documentation_example",
-        is_private=True,
-    ) # Repo |  (optional)
-
-    # example passing only required values which don't have defaults set
-    # and optional values
-    try:
-        api_response = api_instance.create_repo(repo=repo)
-        pprint(api_response)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->create_repo: %s\n" % e)
-```
-
-
-### Parameters
-
-Name | Type | Description  | Notes
-------------- | ------------- | ------------- | -------------
- **repo** | [**Repo**](Repo.md)|  | [optional]
-
-### Return type
-
-[**Repo**](Repo.md)
-
-### Authorization
-
-[bearerAuth](../README.md#bearerAuth)
-
-### HTTP request headers
-
- - **Content-Type**: application/json, application/x-www-form-urlencoded, multipart/form-data
- - **Accept**: application/json
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-**201** |  |  -  |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
-# **destroy_repo**
-> destroy_repo(name)
-
-
-
-Delete the given repo.
-
-### Example
-
-* Bearer Authentication (bearerAuth):
-```python
-import time
-import bitdotio
-from bitdotio.api import api_bitdotio
-from pprint import pprint
-# Defining the host is optional and defaults to https://api.bit.io/api/v1beta
-# See configuration.py for a list of all supported configuration parameters.
-configuration = bitdotio.Configuration(
-    host = "https://api.bit.io/api/v1beta"
-)
-
-# The client must configure the authentication and authorization parameters
-# in accordance with the API server security policy.
-# Examples for each auth method are provided below, use the example that
-# satisfies your auth use case.
-
-# Configure Bearer authorization: bearerAuth
-configuration = bitdotio.Configuration(
-    access_token = 'YOUR_BEARER_TOKEN'
-)
-
-# Enter a context with an instance of the API client
-with bitdotio.ApiClient(configuration) as api_client:
-    # Create an instance of the API class
-    api_instance = api_bitdotio.ApiBitdotio(api_client)
-    name = "name_example" # str | 
-
-    # example passing only required values which don't have defaults set
-    try:
-        api_instance.destroy_repo(name)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->destroy_repo: %s\n" % e)
-```
-
-
-### Parameters
-
-Name | Type | Description  | Notes
-------------- | ------------- | ------------- | -------------
- **name** | **str**|  |
-
-### Return type
-
-void (empty response body)
-
-### Authorization
-
-[bearerAuth](../README.md#bearerAuth)
-
-### HTTP request headers
-
- - **Content-Type**: Not defined
- - **Accept**: Not defined
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-**204** |  |  -  |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
-# **list_repos**
-> [Repo] list_repos()
-
-
-
-Retrieve a list of the repositories that the currently logged-in user can access in some way.
-
-### Example
-
-* Bearer Authentication (bearerAuth):
-```python
-import time
-import bitdotio
-from bitdotio.api import api_bitdotio
-from bitdotio.model.repo import Repo
-from pprint import pprint
-# Defining the host is optional and defaults to https://api.bit.io/api/v1beta
-# See configuration.py for a list of all supported configuration parameters.
-configuration = bitdotio.Configuration(
-    host = "https://api.bit.io/api/v1beta"
-)
-
-# The client must configure the authentication and authorization parameters
-# in accordance with the API server security policy.
-# Examples for each auth method are provided below, use the example that
-# satisfies your auth use case.
-
-# Configure Bearer authorization: bearerAuth
-configuration = bitdotio.Configuration(
-    access_token = 'YOUR_BEARER_TOKEN'
-)
-
-# Enter a context with an instance of the API client
-with bitdotio.ApiClient(configuration) as api_client:
-    # Create an instance of the API class
-    api_instance = api_bitdotio.ApiBitdotio(api_client)
-
-    # example, this endpoint has no required or optional parameters
-    try:
-        api_response = api_instance.list_repos()
-        pprint(api_response)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->list_repos: %s\n" % e)
-```
-
-
-### Parameters
-This endpoint does not need any parameter.
-
-### Return type
-
-[**[Repo]**](Repo.md)
-
-### Authorization
-
-[bearerAuth](../README.md#bearerAuth)
-
-### HTTP request headers
-
- - **Content-Type**: Not defined
- - **Accept**: application/json
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-**200** |  |  -  |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
-# **partial_update_repo**
-> Repo partial_update_repo(name)
-
-
-
-Given a repo name, update one or more field's value in the given repo.
-
-### Example
-
-* Bearer Authentication (bearerAuth):
-```python
-import time
-import bitdotio
-from bitdotio.api import api_bitdotio
-from bitdotio.model.repo import Repo
-from pprint import pprint
-# Defining the host is optional and defaults to https://api.bit.io/api/v1beta
-# See configuration.py for a list of all supported configuration parameters.
-configuration = bitdotio.Configuration(
-    host = "https://api.bit.io/api/v1beta"
-)
-
-# The client must configure the authentication and authorization parameters
-# in accordance with the API server security policy.
-# Examples for each auth method are provided below, use the example that
-# satisfies your auth use case.
-
-# Configure Bearer authorization: bearerAuth
-configuration = bitdotio.Configuration(
-    access_token = 'YOUR_BEARER_TOKEN'
-)
-
-# Enter a context with an instance of the API client
-with bitdotio.ApiClient(configuration) as api_client:
-    # Create an instance of the API class
-    api_instance = api_bitdotio.ApiBitdotio(api_client)
-    name = "name_example" # str | 
-    repo = Repo(
-        name="name_example",
-        description="description_example",
-        documentation="documentation_example",
-        is_private=True,
-    ) # Repo |  (optional)
-
-    # example passing only required values which don't have defaults set
-    try:
-        api_response = api_instance.partial_update_repo(name)
-        pprint(api_response)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->partial_update_repo: %s\n" % e)
-
-    # example passing only required values which don't have defaults set
-    # and optional values
-    try:
-        api_response = api_instance.partial_update_repo(name, repo=repo)
-        pprint(api_response)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->partial_update_repo: %s\n" % e)
-```
-
-
-### Parameters
-
-Name | Type | Description  | Notes
-------------- | ------------- | ------------- | -------------
- **name** | **str**|  |
- **repo** | [**Repo**](Repo.md)|  | [optional]
-
-### Return type
-
-[**Repo**](Repo.md)
-
-### Authorization
-
-[bearerAuth](../README.md#bearerAuth)
-
-### HTTP request headers
-
- - **Content-Type**: application/json, application/x-www-form-urlencoded, multipart/form-data
- - **Accept**: application/json
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-**200** |  |  -  |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
-# **retrieve_ingestor_job**
-> IngestorJob retrieve_ingestor_job(q_uuid)
-
-
-
-### Example
-
-* Bearer Authentication (bearerAuth):
-```python
-import time
-import bitdotio
-from bitdotio.api import api_bitdotio
-from bitdotio.model.ingestor_job import IngestorJob
-from pprint import pprint
-# Defining the host is optional and defaults to https://api.bit.io/api/v1beta
-# See configuration.py for a list of all supported configuration parameters.
-configuration = bitdotio.Configuration(
-    host = "https://api.bit.io/api/v1beta"
-)
-
-# The client must configure the authentication and authorization parameters
-# in accordance with the API server security policy.
-# Examples for each auth method are provided below, use the example that
-# satisfies your auth use case.
-
-# Configure Bearer authorization: bearerAuth
-configuration = bitdotio.Configuration(
-    access_token = 'YOUR_BEARER_TOKEN'
-)
-
-# Enter a context with an instance of the API client
-with bitdotio.ApiClient(configuration) as api_client:
-    # Create an instance of the API class
-    api_instance = api_bitdotio.ApiBitdotio(api_client)
-    q_uuid = "q_uuid_example" # str | 
-
-    # example passing only required values which don't have defaults set
-    try:
-        api_response = api_instance.retrieve_ingestor_job(q_uuid)
-        pprint(api_response)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->retrieve_ingestor_job: %s\n" % e)
-```
-
-
-### Parameters
-
-Name | Type | Description  | Notes
-------------- | ------------- | ------------- | -------------
- **q_uuid** | **str**|  |
-
-### Return type
-
-[**IngestorJob**](IngestorJob.md)
-
-### Authorization
-
-[bearerAuth](../README.md#bearerAuth)
-
-### HTTP request headers
-
- - **Content-Type**: Not defined
- - **Accept**: application/json
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-**200** |  |  -  |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
-# **retrieve_repo**
-> Repo retrieve_repo(name)
-
-
-
-Given a repo name, get the given repo's fields and values of those fields.
-
-### Example
-
-* Bearer Authentication (bearerAuth):
-```python
-import time
-import bitdotio
-from bitdotio.api import api_bitdotio
-from bitdotio.model.repo import Repo
-from pprint import pprint
-# Defining the host is optional and defaults to https://api.bit.io/api/v1beta
-# See configuration.py for a list of all supported configuration parameters.
-configuration = bitdotio.Configuration(
-    host = "https://api.bit.io/api/v1beta"
-)
-
-# The client must configure the authentication and authorization parameters
-# in accordance with the API server security policy.
-# Examples for each auth method are provided below, use the example that
-# satisfies your auth use case.
-
-# Configure Bearer authorization: bearerAuth
-configuration = bitdotio.Configuration(
-    access_token = 'YOUR_BEARER_TOKEN'
-)
-
-# Enter a context with an instance of the API client
-with bitdotio.ApiClient(configuration) as api_client:
-    # Create an instance of the API class
-    api_instance = api_bitdotio.ApiBitdotio(api_client)
-    name = "name_example" # str | 
-
-    # example passing only required values which don't have defaults set
-    try:
-        api_response = api_instance.retrieve_repo(name)
-        pprint(api_response)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->retrieve_repo: %s\n" % e)
-```
-
-
-### Parameters
-
-Name | Type | Description  | Notes
-------------- | ------------- | ------------- | -------------
- **name** | **str**|  |
-
-### Return type
-
-[**Repo**](Repo.md)
-
-### Authorization
-
-[bearerAuth](../README.md#bearerAuth)
-
-### HTTP request headers
-
- - **Content-Type**: Not defined
- - **Accept**: application/json
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-**200** |  |  -  |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
-# **update_repo**
-> Repo update_repo(name)
-
-
-
-Given a repo name, update the values of all fields in the given repo.
-
-### Example
-
-* Bearer Authentication (bearerAuth):
-```python
-import time
-import bitdotio
-from bitdotio.api import api_bitdotio
-from bitdotio.model.repo import Repo
-from pprint import pprint
-# Defining the host is optional and defaults to https://api.bit.io/api/v1beta
-# See configuration.py for a list of all supported configuration parameters.
-configuration = bitdotio.Configuration(
-    host = "https://api.bit.io/api/v1beta"
-)
-
-# The client must configure the authentication and authorization parameters
-# in accordance with the API server security policy.
-# Examples for each auth method are provided below, use the example that
-# satisfies your auth use case.
-
-# Configure Bearer authorization: bearerAuth
-configuration = bitdotio.Configuration(
-    access_token = 'YOUR_BEARER_TOKEN'
-)
-
-# Enter a context with an instance of the API client
-with bitdotio.ApiClient(configuration) as api_client:
-    # Create an instance of the API class
-    api_instance = api_bitdotio.ApiBitdotio(api_client)
-    name = "name_example" # str | 
-    repo = Repo(
-        name="name_example",
-        description="description_example",
-        documentation="documentation_example",
-        is_private=True,
-    ) # Repo |  (optional)
-
-    # example passing only required values which don't have defaults set
-    try:
-        api_response = api_instance.update_repo(name)
-        pprint(api_response)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->update_repo: %s\n" % e)
-
-    # example passing only required values which don't have defaults set
-    # and optional values
-    try:
-        api_response = api_instance.update_repo(name, repo=repo)
-        pprint(api_response)
-    except bitdotio.ApiException as e:
-        print("Exception when calling ApiBitdotio->update_repo: %s\n" % e)
-```
-
-
-### Parameters
-
-Name | Type | Description  | Notes
-------------- | ------------- | ------------- | -------------
- **name** | **str**|  |
- **repo** | [**Repo**](Repo.md)|  | [optional]
-
-### Return type
-
-[**Repo**](Repo.md)
-
-### Authorization
-
-[bearerAuth](../README.md#bearerAuth)
-
-### HTTP request headers
-
- - **Content-Type**: application/json, application/x-www-form-urlencoded, multipart/form-data
- - **Accept**: application/json
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-**200** |  |  -  |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
diff --git a/docs/Column.md b/docs/Column.md
deleted file mode 100644
index 8ee12b2..0000000
--- a/docs/Column.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Column
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**url** | **str** |  | [optional] [readonly] 
-**current_name** | **str** |  | [optional] [readonly] 
-**data_type** | **str** |  | [optional] 
-**description** | **str** |  | [optional] 
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/ImportFile.md b/docs/ImportFile.md
deleted file mode 100644
index db5d4de..0000000
--- a/docs/ImportFile.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# ImportFile
-
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**file_to_import** | **file_type** |  | 
-**repo_name** | **str** |  | 
-**table_name** | **str** |  | [optional] 
-**create_table_if_not_exists** | **bool** |  | [optional]  if omitted the server will use the default value of True
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/ImportJson.md b/docs/ImportJson.md
deleted file mode 100644
index aafac5b..0000000
--- a/docs/ImportJson.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# ImportJson
-
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**data** | **str** |  | 
-**table_name** | **str** |  | 
-**repo_name** | **str** |  | 
-**create_table_if_not_exists** | **bool** |  | [optional]  if omitted the server will use the default value of True
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/ImportUrl.md b/docs/ImportUrl.md
deleted file mode 100644
index c1c7815..0000000
--- a/docs/ImportUrl.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# ImportUrl
-
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**url** | **str** |  | 
-**table_name** | **str** |  | 
-**repo_name** | **str** |  | 
-**create_table_if_not_exists** | **bool** |  | [optional]  if omitted the server will use the default value of True
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/IngestionResult.md b/docs/IngestionResult.md
deleted file mode 100644
index 7a49d6a..0000000
--- a/docs/IngestionResult.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# IngestionResult
-
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**result** | **str** |  | 
-**message** | **str** |  | 
-**table_name** | **str** |  | 
-**repo_name** | **str** |  | 
-**job_id** | **str** |  | 
-**file_name** | **str** |  | [optional] 
-**url** | **str** |  | [optional] 
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/IngestorJob.md b/docs/IngestorJob.md
deleted file mode 100644
index e7fb08e..0000000
--- a/docs/IngestorJob.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# IngestorJob
-
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**job_id** | **str** |  | 
-**state** | **str** |  | 
-**status_message** | **str** |  | 
-**retries** | **int** |  | 
-**file_type** | **str, none_type** |  | [optional] 
-**original_filename** | **str** |  | [optional] 
-**repo_name** | **str** |  | [optional] 
-**table_name** | **str** |  | [optional] 
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/QConnection.md b/docs/QConnection.md
deleted file mode 100644
index 6be83e5..0000000
--- a/docs/QConnection.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# QConnection
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**url** | **str** |  | [optional] [readonly] 
-**name** | **str** |  | [optional] [readonly] 
-**owner** | **str** |  | [optional] [readonly] 
-**kind** | **str** |  | [optional] [readonly] 
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/QEndpoint.md b/docs/QEndpoint.md
deleted file mode 100644
index 8371f55..0000000
--- a/docs/QEndpoint.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# QEndpoint
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**url** | **str** |  | [optional] [readonly] 
-**name** | **str** |  | [optional] [readonly] 
-**owner** | **str** |  | [optional] [readonly] 
-**kind** | **str** |  | [optional] [readonly] 
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/QUser.md b/docs/QUser.md
deleted file mode 100644
index 08b4d1b..0000000
--- a/docs/QUser.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# QUser
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**connections** | **list[str]** |  | [optional] [readonly] 
-**date_joined** | **datetime** |  | [optional] [readonly] 
-**first_name** | **str** |  | [optional] 
-**last_name** | **str** |  | [optional] 
-**profile** | [**QUserProfile**](QUserProfile.md) |  | 
-**repos_owned** | **list[str]** |  | [optional] [readonly] 
-**url** | **str** |  | [optional] [readonly] 
-**username** | **str** | Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. | [optional] [readonly] 
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/QUserProfile.md b/docs/QUserProfile.md
deleted file mode 100644
index d03062f..0000000
--- a/docs/QUserProfile.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# QUserProfile
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**bio** | **str** |  | [optional] 
-**website** | **str** |  | [optional] 
-**public_status** | **str** |  | [optional] 
-**picture_path** | **str** |  | [optional] 
-**freeform_location** | **str** |  | [optional] 
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/Query.md b/docs/Query.md
deleted file mode 100644
index 75221f6..0000000
--- a/docs/Query.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Query
-
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**query_string** | **str** |  | 
-**fields** | **{str: (bool, date, datetime, dict, float, int, list, str, none_type)}** |  | [optional] [readonly] 
-**data** | **[bool, date, datetime, dict, float, int, list, str, none_type]** |  | [optional] [readonly] 
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/QueryResult.md b/docs/QueryResult.md
deleted file mode 100644
index c4c854a..0000000
--- a/docs/QueryResult.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# QueryResult
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**query_string** | **str** |  | 
-**fields** | [**object**](.md) |  | 
-**data** | **list[object]** |  | 
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/Repo.md b/docs/Repo.md
deleted file mode 100644
index a7f11cf..0000000
--- a/docs/Repo.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Repo
-
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**name** | **str** |  | 
-**url** | **str** |  | [optional] [readonly] 
-**description** | **str** |  | [optional] 
-**documentation** | **str** |  | [optional] 
-**bytes** | **int** |  | [optional] [readonly] 
-**is_private** | **bool** |  | [optional] 
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/RepoCollaborators.md b/docs/RepoCollaborators.md
deleted file mode 100644
index bc46233..0000000
--- a/docs/RepoCollaborators.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# RepoCollaborators
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**role** | **str** |  | 
-**role_display** | **str** |  | [optional] [readonly] 
-**user** | **str** |  | [optional] [readonly] 
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/docs/Table.md b/docs/Table.md
deleted file mode 100644
index a0c3f74..0000000
--- a/docs/Table.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# Table
-
-## Properties
-Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
-**url** | **str** |  | [optional] [readonly] 
-**current_name** | **str** |  | [optional] [readonly] 
-**description** | **str** |  | [optional] 
-**columns** | **list[str]** |  | [optional] [readonly] 
-**num_records** | **int** |  | [optional] [readonly] 
-**bytes** | **str** |  | [optional] [readonly] 
-**repo** | **str** |  | [optional] [readonly] 
-**documentation** | **str** |  | [optional] 
-
-[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
-
-
diff --git a/requirements.txt b/requirements.txt
index 7767c60..823a295 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,3 @@
-certifi >= 14.05.14
-future; python_version<="2.7"
-six >= 1.10
-python_dateutil >= 2.5.3
-setuptools >= 21.0.0
-urllib3 >= 1.15.1
+click >= 8.0.1
 psycopg2 >= 2.8.6
+requests >= 2.28.1
diff --git a/setup.py b/setup.py
index 297692b..28d3747 100644
--- a/setup.py
+++ b/setup.py
@@ -1,16 +1,23 @@
 # coding: utf-8
+import os
+import re
+from setuptools import setup, find_packages  # noqa: H301
 
-"""
-    bit.io REST API
 
-    bit.io API  # noqa: E501
-"""
+NAME = "bitdotio"
+VERSIONFILE = os.path.join(NAME, "_version.py")
+RE_VERSION = re.compile(r'^__version__ = "(?P<version>.+?)"$')
 
 
-from setuptools import setup, find_packages  # noqa: H301
+def get_version():
+    with open(VERSIONFILE, "r") as f:
+        match = RE_VERSION.match(f.read().strip())
+        if match:
+            return match.group("version")
+
+        raise ValueError("Unable to parse version file")
+
 
-NAME = "bitdotio"
-VERSION = "2.0.0b"
 # To install the library, run the following
 #
 # python setup.py install
@@ -18,7 +25,7 @@
 # prerequisite: setuptools
 # http://pypi.python.org/pypi/setuptools
 
-REQUIRES = ["urllib3 >= 1.15", "six >= 1.10", "certifi", "python-dateutil", "click >= 8.0.1"]
+REQUIRES = ["requests >= 2.28.1", "click >= 8.0.1"]
 
 EXTRAS = {
     "psycopg2": [
@@ -35,7 +42,7 @@
 
 setup(
     name=NAME,
-    version=VERSION,
+    version=get_version(),
     description="bit.io Python SDK and CLI",
     author="bit.io",
     author_email="python@bit.io",
@@ -56,8 +63,8 @@
     ],
     python_requires=">=3.7",
     entry_points={
-        'console_scripts': [
-            'bit = bit.bit:main',
+        "console_scripts": [
+            "bit = bit.bit:main",
         ]
     },
 )


Test patch:
diff --git a/test/test_api_bitdotio.py b/test/test_api_bitdotio.py
deleted file mode 100644
index 786fe9a..0000000
--- a/test/test_api_bitdotio.py
+++ /dev/null
@@ -1,94 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import unittest
-
-import bitdotio
-from bitdotio.api.api_bitdotio import ApiBitdotio  # noqa: E501
-
-
-class TestApiBitdotio(unittest.TestCase):
-    """ApiBitdotio unit test stubs"""
-
-    def setUp(self):
-        self.api = ApiBitdotio()  # noqa: E501
-
-    def tearDown(self):
-        pass
-
-    def test_create_import_file(self):
-        """Test case for create_import_file
-
-        """
-        pass
-
-    def test_create_import_json(self):
-        """Test case for create_import_json
-
-        """
-        pass
-
-    def test_create_import_url(self):
-        """Test case for create_import_url
-
-        """
-        pass
-
-    def test_create_query(self):
-        """Test case for create_query
-
-        """
-        pass
-
-    def test_create_repo(self):
-        """Test case for create_repo
-
-        """
-        pass
-
-    def test_destroy_repo(self):
-        """Test case for destroy_repo
-
-        """
-        pass
-
-    def test_list_repos(self):
-        """Test case for list_repos
-
-        """
-        pass
-
-    def test_partial_update_repo(self):
-        """Test case for partial_update_repo
-
-        """
-        pass
-
-    def test_retrieve_ingestor_job(self):
-        """Test case for retrieve_ingestor_job
-
-        """
-        pass
-
-    def test_retrieve_repo(self):
-        """Test case for retrieve_repo
-
-        """
-        pass
-
-    def test_update_repo(self):
-        """Test case for update_repo
-
-        """
-        pass
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_api_client.py b/test/test_api_client.py
new file mode 100644
index 0000000..e7fa3fd
--- /dev/null
+++ b/test/test_api_client.py
@@ -0,0 +1,75 @@
+import unittest
+
+from unittest.mock import Mock, patch
+
+from bitdotio.api_client import ApiClient
+from bitdotio._bitdotio import API_VERSION
+
+
+class TestApiClient(unittest.TestCase):
+    token = "v2_testtoken"
+
+    def setUp(self) -> None:
+        self.api_client = ApiClient(self.token, API_VERSION)
+
+    def test_init(self) -> None:
+        self.assertEqual(self.api_client._access_token, self.token)
+        self.assertEqual(self.api_client._api_version, API_VERSION)
+        self.assertIsNotNone(self.api_client._session)
+        headers = self.api_client._session.headers
+        self.assertEqual(headers["Accept"], "application/json")
+        self.assertEqual(headers["Content-Type"], "application/json")
+        self.assertEqual(headers["Authorization"], f"Bearer {self.token}")
+
+    def test_url(self) -> None:
+        expected = f"https://api.bit.io/{API_VERSION}/foo/bar"
+        result = self.api_client._url("/foo/bar")
+        self.assertEqual(result, expected)
+
+    @patch("bitdotio.api_client.Session.request")
+    def test_request(self, mock_request: Mock) -> None:
+        url = "/foo"
+        expected_url = f"https://api.bit.io/{API_VERSION}/foo"
+        test_cases = [
+            ("GET", None),
+            ("POST", {"foo": "bar"}),
+            ("PATCH", {"foo": "bar"}),
+            ("DELETE", None),
+        ]
+        for method, body in test_cases:
+            self.api_client.request(method, url, json=body)
+            mock_request.assert_called_with(method, expected_url, json=body)
+
+    @patch("bitdotio.api_client.Session.request")
+    def test_get(self, mock_request: Mock) -> None:
+        url = "/foo"
+        expected_method = "GET"
+        expected_url = f"https://api.bit.io/{API_VERSION}/foo"
+        self.api_client.get(url)
+        mock_request.assert_called_once_with(expected_method, expected_url)
+
+    @patch("bitdotio.api_client.Session.request")
+    def test_post(self, mock_request: Mock) -> None:
+        url = "/foo"
+        expected_method = "POST"
+        expected_url = f"https://api.bit.io/{API_VERSION}/foo"
+        body = {"foo": "bar"}
+        self.api_client.post(url, json=body)
+        mock_request.assert_called_once_with(expected_method, expected_url, json=body)
+
+    @patch("bitdotio.api_client.Session.request")
+    def test_patch(self, mock_request: Mock) -> None:
+        url = "/foo"
+        expected_method = "PATCH"
+        expected_url = f"https://api.bit.io/{API_VERSION}/foo"
+        body = {"foo": "bar"}
+        self.api_client.patch(url, json=body)
+        mock_request.assert_called_once_with(expected_method, expected_url, json=body)
+
+    @patch("bitdotio.api_client.Session.request")
+    def test_delete(self, mock_request: Mock) -> None:
+        url = "/foo"
+        expected_method = "DELETE"
+        expected_url = f"https://api.bit.io/{API_VERSION}/foo"
+        self.api_client.delete(url)
+        mock_request.assert_called_once_with(expected_method, expected_url)
diff --git a/test/test_api_methods.py b/test/test_api_methods.py
new file mode 100644
index 0000000..656cfca
--- /dev/null
+++ b/test/test_api_methods.py
@@ -0,0 +1,175 @@
+import unittest
+from unittest.mock import Mock, patch
+
+from bitdotio import bitdotio
+from bitdotio._bitdotio import ApiError
+
+
+class TestApiMethods(unittest.TestCase):
+    token = "v2_testtoken"
+
+    def setUp(self) -> None:
+        self.b = bitdotio(self.token)
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_query_ok(self, mock_request: Mock) -> None:
+        db_name = "my/db"
+        query_str = "SELECT 1"
+        data_format = "objects"
+        expected = {"foo": "bar"}
+        mock_request.return_value.ok = True
+        mock_request.return_value.status_code = 200
+        mock_request.return_value.json.return_value = expected
+
+        result = self.b.query("my/db", "SELECT 1")
+
+        # Test without data_format
+        self.assertEqual(result, expected)
+        mock_request.assert_called_once_with(
+            "POST",
+            "/query",
+            json={"database_name": db_name, "query_string": query_str},
+        )
+
+        mock_request.reset_mock()
+
+        # Test with data_format
+        result = self.b.query("my/db", "SELECT 1", data_format=data_format)
+        self.assertEqual(result, expected)
+        mock_request.assert_called_once_with(
+            "POST",
+            f"/query?data_format={data_format}",
+            json={"database_name": db_name, "query_string": query_str},
+        )
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_query_error(self, mock_request: Mock) -> None:
+        status_code = 400
+        error_data = {"error": "whoops"}
+        mock_request.return_value.ok = False
+        mock_request.return_value.status_code = status_code
+        mock_request.return_value.json.return_value = error_data
+        with self.assertRaises(ApiError) as cm:
+            self.b.query("my/db", "SELECT 1")
+            self.assertEqual(cm.exception.status_code, status_code)
+            self.assertEqual(cm.exception.data, error_data)
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_list_databases_ok(self, mock_request: Mock) -> None:
+        expected = ["foo", "bar"]
+        mock_request.return_value.ok = True
+        mock_request.return_value.status_code = 200
+        mock_request.return_value.json.return_value = {"databases": expected}
+        result = self.b.list_databases()
+        self.assertEqual(result, expected)
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_list_databases_error(self, mock_request: Mock) -> None:
+        status_code = 400
+        error_data = {"error": "whoops"}
+        mock_request.return_value.ok = False
+        mock_request.return_value.status_code = status_code
+        mock_request.return_value.json.return_value = error_data
+        with self.assertRaises(ApiError) as cm:
+            self.b.list_databases()
+            self.assertEqual(cm.exception.status_code, status_code)
+            self.assertEqual(cm.exception.data, error_data)
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_create_database_ok(self, mock_request: Mock) -> None:
+        expected = {"foo", "bar"}
+        mock_request.return_value.ok = True
+        mock_request.return_value.status_code = 201
+        mock_request.return_value.json.return_value = expected
+        result = self.b.create_database("my-db")
+        self.assertEqual(result, expected)
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_create_database_error(self, mock_request: Mock) -> None:
+        status_code = 400
+        error_data = {"error": "whoops"}
+        mock_request.return_value.ok = False
+        mock_request.return_value.status_code = status_code
+        mock_request.return_value.json.return_value = error_data
+        with self.assertRaises(ApiError) as cm:
+            self.b.create_database("my-db")
+            self.assertEqual(cm.exception.status_code, status_code)
+            self.assertEqual(cm.exception.data, error_data)
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_get_database_ok(self, mock_request: Mock) -> None:
+        expected = {"foo", "bar"}
+        mock_request.return_value.ok = True
+        mock_request.return_value.status_code = 201
+        mock_request.return_value.json.return_value = expected
+        result = self.b.get_database("my/db")
+        self.assertEqual(result, expected)
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_get_database_invalid_db_name(self, _: Mock) -> None:
+        with self.assertRaises(ValueError):
+            self.b.get_database("mydb")
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_get_database_error(self, mock_request: Mock) -> None:
+        status_code = 401
+        error_data = {"error": "whoops"}
+        mock_request.return_value.ok = False
+        mock_request.return_value.status_code = status_code
+        mock_request.return_value.json.return_value = error_data
+        with self.assertRaises(ApiError) as cm:
+            self.b.get_database("my/db")
+            self.assertEqual(cm.exception.status_code, status_code)
+            self.assertEqual(cm.exception.data, error_data)
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_update_database_ok(self, mock_request: Mock) -> None:
+        expected = {"foo", "bar"}
+        mock_request.return_value.ok = True
+        mock_request.return_value.status_code = 200
+        mock_request.return_value.json.return_value = expected
+        result = self.b.update_database("my/db", is_private=False)
+        self.assertEqual(result, expected)
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_update_database_invalid_db_name(self, _: Mock) -> None:
+        with self.assertRaises(ValueError):
+            self.b.update_database("mydb", is_private=False)
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_update_database_error(self, mock_request: Mock) -> None:
+        status_code = 400
+        error_data = {"error": "whoops"}
+        mock_request.return_value.ok = False
+        mock_request.return_value.status_code = status_code
+        mock_request.return_value.json.return_value = error_data
+        with self.assertRaises(ApiError) as cm:
+            self.b.update_database("my/db", is_private=False)
+            self.assertEqual(cm.exception.status_code, status_code)
+            self.assertEqual(cm.exception.data, error_data)
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_delete_database_ok(self, mock_request: Mock) -> None:
+        expected = {"foo", "bar"}
+        mock_request.return_value.ok = True
+        mock_request.return_value.status_code = 200
+        mock_request.return_value.json.return_value = expected
+        result = self.b.delete_database("my/db")
+        self.assertEqual(result, expected)
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_delete_database_invalid_db_name(self, _: Mock) -> None:
+        with self.assertRaises(ValueError):
+            self.b.delete_database("mydb")
+
+    @patch("bitdotio.api_client.ApiClient.request")
+    def test_delet_database_error(self, mock_request: Mock) -> None:
+        status_code = 400
+        error_data = {"error": "whoops"}
+        mock_request.return_value.ok = False
+        mock_request.return_value.status_code = status_code
+        mock_request.return_value.json.return_value = error_data
+        with self.assertRaises(ApiError) as cm:
+            self.b.delete_database("my/db")
+            self.assertEqual(cm.exception.status_code, status_code)
+            self.assertEqual(cm.exception.data, error_data)
diff --git a/test/test_cli.py b/test/test_cli.py
new file mode 100644
index 0000000..9cd3660
--- /dev/null
+++ b/test/test_cli.py
@@ -0,0 +1,153 @@
+import os
+import unittest
+import tempfile
+from unittest.mock import Mock, patch
+
+from bit.bit import bitio
+from click.testing import CliRunner
+
+"""
+click.testing.CliRunner is not thread safe! This will likely cause
+future tests affecting interpreter state to fail.
+
+`bitio.params[0].required = True` in teardown addresses the case where
+a test of '--help' functionality without a key changes the bitio 'key'
+parameter requirement to "False," causing later tests of the key
+requirement to fail.
+"""
+
+
+@patch.dict(os.environ, {"BITIO_KEY": ""})
+class TestCLI(unittest.TestCase):
+    # Test token that passes regex validation
+    token = "v2_testtoken"
+
+    def setUp(self) -> None:
+        self.runner = CliRunner()
+
+    def tearDown(self) -> None:
+        bitio.params[0].required = True
+
+    def cmd(self, *args):
+        return ["-k", self.token, *args]
+
+    def test_help(self):
+        result = self.runner.invoke(bitio, ["--help", "bitio"])
+        self.assertEqual(result.exit_code, 0)
+
+    def test_no_args(self):
+        """Test that bit with no arguments returns same as with --help"""
+        res1 = self.runner.invoke(bitio)
+        res2 = self.runner.invoke(bitio, ["--help", "bitio"])
+        self.assertEqual(res1.output, res2.output)
+
+    def test_help_no_key(self):
+        """Test that help for query, import, repo commands are accessible without key"""
+        query_result = self.runner.invoke(bitio, ["query", "--help", "bitio"])
+        db_result = self.runner.invoke(bitio, ["db", "--help", "bitio"])
+
+        self.assertEqual(query_result.exit_code, 0)
+        self.assertEqual(db_result.exit_code, 0)
+
+    @patch("bitdotio._bitdotio._BitV2.get_database", return_value={})
+    def test_bitio_key_env_var(self, mock_get_database: Mock):
+        # Check that we can omit -k/--key and use BITIO_KEY env var instead. Use db
+        # info command for this purpose since it's the simplest.
+        os.environ["BITIO_KEY"] = self.token
+        cmd = ["db", "info", "-d", "my/db"]
+        result = self.runner.invoke(bitio, cmd)
+        self.assertEqual(result.exit_code, 0)
+        mock_get_database.assert_called_once()
+        del os.environ["BITIO_KEY"]
+
+    @patch("bitdotio._bitdotio._BitV2.query", return_value={})
+    def test_query_ok_query_str(self, mock_query: Mock):
+        cmd = self.cmd("query", "-d", "my/db", "-q", "select 1")
+        result = self.runner.invoke(bitio, cmd)
+        self.assertEqual(result.exit_code, 0)
+        mock_query.assert_called_once_with("my/db", "select 1")
+
+    @patch("bitdotio._bitdotio._BitV2.query", return_value={})
+    def test_query_ok_query_file(self, mock_query: Mock):
+        query = "select 1"
+        with tempfile.TemporaryDirectory() as temp_path:
+            file_path = os.path.join(temp_path, "query.sql")
+            with open(file_path, "w+") as f:
+                f.write(query)
+
+            cmd = self.cmd("query", "-d", "my/db", "-qf", file_path, "-o")
+            result = self.runner.invoke(bitio, cmd)
+            self.assertEqual(result.exit_code, 0)
+            mock_query.assert_called_once_with(
+                "my/db", "select 1", data_format="objects"
+            )
+
+    def test_query_error(self):
+        test_cases = [("-d", "my/db"), ("-q", "select 1", "-o"), ("-qf", "file.sql")]
+        for test_case in test_cases:
+            cmd = self.cmd("query", *test_case)
+            result = self.runner.invoke(bitio, cmd)
+            self.assertNotEqual(result.exit_code, 0)
+
+    @patch("bitdotio._bitdotio._BitV2.list_databases", return_value=[])
+    def test_db_list_ok(self, mock_list_databases: Mock):
+        cmd = self.cmd("db", "list")
+        result = self.runner.invoke(bitio, cmd)
+        self.assertEqual(result.exit_code, 0)
+        mock_list_databases.assert_called_once()
+
+    @patch("bitdotio._bitdotio._BitV2.create_database", return_value=[])
+    def test_db_create_ok(self, mock_create_database: Mock):
+        cmd = self.cmd("db", "create", "-n", "my/db", "-p", "false")
+        result = self.runner.invoke(bitio, cmd)
+        self.assertEqual(result.exit_code, 0)
+        mock_create_database.assert_called_once_with("my/db", is_private=False)
+
+    def test_db_create_error(self):
+        cmd = self.cmd("db", "create", "-p", "false")
+        result = self.runner.invoke(bitio, cmd)
+        self.assertNotEqual(result.exit_code, 0)
+
+    @patch("bitdotio._bitdotio._BitV2.get_database", return_value=[])
+    def test_db_info_ok(self, mock_get_database: Mock):
+        cmd = self.cmd("db", "info", "-d", "my/db")
+        result = self.runner.invoke(bitio, cmd)
+        self.assertEqual(result.exit_code, 0)
+        mock_get_database.assert_called_once_with("my/db")
+
+    def test_db_info_error(self):
+        cmd = self.cmd("db", "info")
+        result = self.runner.invoke(bitio, cmd)
+        self.assertNotEqual(result.exit_code, 0)
+
+    @patch("bitdotio._bitdotio._BitV2.update_database", return_value=[])
+    def test_db_update_ok(self, mock_update_database: Mock):
+        test_cases = [
+            [],
+            ("-p", "false"),
+            ("-n", "your/db"),
+            ("-n", "your/db", "-p", "false"),
+        ]
+        for test_case in test_cases:
+            cmd = self.cmd("db", "update", "-d", "my/db", *test_case)
+            result = self.runner.invoke(bitio, cmd)
+            self.assertEqual(result.exit_code, 0)
+            mock_update_database.assert_called_once()
+            mock_update_database.reset_mock()
+
+    def test_db_update_error(self):
+        cmd = self.cmd("db", "update", "-p", "false")
+        result = self.runner.invoke(bitio, cmd)
+        self.assertNotEqual(result.exit_code, 0)
+
+    @patch("bitdotio._bitdotio._BitV2.delete_database", return_value=[])
+    def test_db_delete_ok(self, mock_delete_database: Mock):
+        cmd = self.cmd("db", "delete", "-d", "my/db")
+        result = self.runner.invoke(bitio, cmd)
+        self.assertEqual(result.exit_code, 0)
+        mock_delete_database.assert_called_once_with("my/db")
+
+    def test_db_delete_error(self):
+        cmd = self.cmd("db", "delete")
+        result = self.runner.invoke(bitio, cmd)
+        self.assertNotEqual(result.exit_code, 0)
diff --git a/test/test_cli_help.py b/test/test_cli_help.py
deleted file mode 100644
index a9efc52..0000000
--- a/test/test_cli_help.py
+++ /dev/null
@@ -1,53 +0,0 @@
-import os
-import unittest
-from unittest import mock
-
-from bit.bit import bitio
-from click.testing import CliRunner
-
-"""
-click.testing.CliRunner is not thread safe! This will likely cause
-future tests affecting interpreter state to fail.
-
-`bitio.params[0].required = True` in teardown addresses the case where
-a test of '--help' functionality without a key changes the bitio 'key'
-parameter requirement to "False," causing later tests of the key
-requirement to fail.
-"""
-
-
-@mock.patch.dict(os.environ, {"BITIO_KEY": ""})
-class TestBitHelp(unittest.TestCase):
-    def setUp(self) -> None:
-        return super().setUp()
-
-    def tearDown(self) -> None:
-        bitio.params[0].required = True
-        return super().tearDown()
-
-    def test_help(self):
-        runner = CliRunner()
-        result = runner.invoke(bitio, ["--help", "bitio"])
-        assert result.exit_code == 0
-
-    def test_no_args(self):
-        """Test that bit with no arguments returns same as with --help"""
-        runner = CliRunner()
-        res1 = runner.invoke(bitio)
-        res2 = runner.invoke(bitio, ["--help", "bitio"])
-        assert res1.output == res2.output
-
-    def test_help_no_key(self):
-        """Test that help for query, import, repo commands are accessible without key"""
-        runner = CliRunner()
-        query_result = runner.invoke(bitio, ["query", "--help", "bitio"])
-        import_result = runner.invoke(bitio, ["import", "--help", "bitio"])
-        repo_result = runner.invoke(bitio, ["repo", "--help", "bitio"])
-
-        assert query_result.exit_code == 0
-        assert import_result.exit_code == 0
-        assert repo_result.exit_code == 0
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/test/test_cli_import.py b/test/test_cli_import.py
deleted file mode 100644
index 33605d6..0000000
--- a/test/test_cli_import.py
+++ /dev/null
@@ -1,117 +0,0 @@
-import os
-import unittest
-from unittest import mock
-from unittest.mock import Mock, patch
-
-import bitdotio
-from bit.bit import bitio
-from click.testing import CliRunner
-
-"""
-click.testing.CliRunner is not thread safe! This will likely cause
-future tests affecting interpreter state to fail.
-
-`bitio.params[0].required = True` in teardown addresses the case where
-a test of '--help' functionality without a key changes the bitio 'key'
-parameter requirement to "False," causing later tests of the key
-requirement to fail.
-"""
-
-
-@mock.patch.dict(os.environ, {"BITIO_KEY": ""})
-class TestBitQuery(unittest.TestCase):
-    def setUp(self) -> None:
-        return super().setUp()
-
-    def tearDown(self) -> None:
-        bitio.params[0].required = True
-        return super().tearDown()
-
-    def test_import_url(self):
-        """Test that `bit import url` calls bitdotio.model.import_url"""
-        with patch.object(bitdotio.model.import_url, "ImportUrl") as mock_import:
-            runner = CliRunner()
-            result = runner.invoke(
-                bitio,
-                [
-                    "-k",
-                    "<API_KEY>",
-                    "import",
-                    "url",
-                    "-r",
-                    "some_repo",
-                    "-t",
-                    "some_table",
-                    "-u",
-                    "some_url",
-                ],
-            )
-            mock_import.assert_called_once()
-            mock_import.assert_called_with("some_url", "some_table", "some_repo")
-
-    def test_import_url_no_key(self):
-        """Test that `bit import url` fails without a key"""
-        with patch.object(bitdotio.model.import_url, "ImportUrl") as mock_import_no_key:
-            runner = CliRunner()
-            result = runner.invoke(
-                bitio,
-                [
-                    "import",
-                    "url",
-                    "-r",
-                    "some_repo",
-                    "-t",
-                    "some_table",
-                    "-u",
-                    "some_url",
-                ],
-            )
-            mock_import_no_key.assert_not_called()
-            assert result.exception
-
-    def test_import_json(self):
-        """Test that `bit import json-data` calls bitdotio.model.import_json"""
-
-        with patch.object(bitdotio.model.import_json, "ImportJson") as mock_import:
-            runner = CliRunner()
-            result = runner.invoke(
-                bitio,
-                [
-                    "-k",
-                    "<API_KEY>",
-                    "import",
-                    "json-data",
-                    "-r",
-                    "some_repo",
-                    "-t",
-                    "some_table",
-                ],
-                input='{"some_json":1}',
-            )
-            mock_import.assert_called_once()
-            mock_import.assert_called_with('{"some_json":1}', "some_table", "some_repo")
-
-    @patch("bitdotio.bitdotio")
-    def test_import_file(self, mock_bitdotio):
-        runner = CliRunner()
-        runner.invoke(
-            bitio,
-            [
-                "-k",
-                "<API_KEY>",
-                "import",
-                "json-data",
-                "-r",
-                "some_repo",
-                "-t",
-                "some_table",
-                "-f",
-                "some_file",
-            ],
-        )
-        mock_bitdotio.assert_called_once()
-        mock_bitdotio.assert_called_with("<API_KEY>")
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/test/test_cli_query.py b/test/test_cli_query.py
deleted file mode 100644
index b1ae258..0000000
--- a/test/test_cli_query.py
+++ /dev/null
@@ -1,48 +0,0 @@
-import os
-import unittest
-from unittest import mock
-from unittest.mock import Mock, patch
-
-import bitdotio
-from bit.bit import bitio
-from click.testing import CliRunner
-
-"""
-click.testing.CliRunner is not thread safe! This will likely cause
-future tests affecting interpreter state to fail.
-
-`bitio.params[0].required = True` in teardown addresses the case where
-a test of '--help' functionality without a key changes the bitio 'key'
-parameter requirement to "False," causing later tests of the key
-requirement to fail.
-"""
-
-
-@mock.patch.dict(os.environ, {"BITIO_KEY": ""})
-class TestBitQuery(unittest.TestCase):
-    def setUp(self) -> None:
-        return super().setUp()
-
-    def tearDown(self) -> None:
-        bitio.params[0].required = True
-        return super().tearDown()
-
-    def test_query(self):
-        with patch.object(bitdotio.model.query, "Query") as mock_query:
-            runner = CliRunner()
-            runner.invoke(
-                bitio, ["-k", "<API_KEY>", "query", "--query", "Some Query Text"]
-            )
-            mock_query.assert_called_once()
-            mock_query.assert_called_with(query_string="Some Query Text")
-
-    def test_query_no_key(self):
-        with patch.object(bitdotio.model.query, "Query") as mock_query:
-            runner = CliRunner()
-            result = runner.invoke(bitio, ["query", "--query", "Some Query Text"])
-            mock_query.assert_not_called()
-            assert result.exception
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/test/test_cli_repo.py b/test/test_cli_repo.py
deleted file mode 100644
index 73464d8..0000000
--- a/test/test_cli_repo.py
+++ /dev/null
@@ -1,41 +0,0 @@
-import os
-import unittest
-from unittest import mock
-from unittest.mock import Mock, patch
-import bit
-from bit.bit import bitio
-from click.testing import CliRunner
-
-
-FAKE_KEY = '1234'
-
-
-@mock.patch.dict(os.environ, {"BITIO_KEY": ""})
-class TestBitHelp(unittest.TestCase):
-    def setUp(self) -> None:
-        return super().setUp()
-
-    def tearDown(self) -> None:
-        return super().tearDown()
-
-    @patch('bit.bit.print_json_model_list')
-    @patch('bitdotio.bitdotio')
-    def test_list_repos(self, mock_bitdotio, mock_print_json):
-        runner = CliRunner()
-        result = runner.invoke(bitio, ["-k", FAKE_KEY, "repo", "list"])
-        mock_bitdotio.assert_called_once()
-        mock_print_json.assert_called_once()
-
-
-    @patch('bit.bit.print_json_model')
-    @patch('bitdotio.bitdotio')
-    def test_retrieve_repo(self, mock_bitdotio, mock_print_json):
-        runner = CliRunner()
-        result = runner.invoke(bitio, ["-k", FAKE_KEY, "repo", "retrieve", "-r", "repo_name"])
-        mock_bitdotio.assert_called_once()
-        mock_print_json.assert_called_once()
-
-
-if __name__ == "__main__":
-    unittest.main()
-
diff --git a/test/test_column.py b/test/test_column.py
deleted file mode 100644
index eaff861..0000000
--- a/test/test_column.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-from __future__ import absolute_import
-
-import unittest
-import datetime
-
-import bitdotio
-from bitdotio.models.column import Column  # noqa: E501
-from bitdotio.rest import ApiException
-
-class TestColumn(unittest.TestCase):
-    """Column unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def make_instance(self, include_optional):
-        """Test Column
-            include_option is a boolean, when False only required
-            params are included, when True both required and
-            optional params are included """
-        # model = bitdotio.models.column.Column()  # noqa: E501
-        if include_optional :
-            return Column(
-                url = '0', 
-                current_name = '0', 
-                data_type = 'BIGINT', 
-                description = '0'
-            )
-        else :
-            return Column(
-        )
-
-    def testColumn(self):
-        """Test Column"""
-        inst_req_only = self.make_instance(include_optional=False)
-        inst_req_and_optional = self.make_instance(include_optional=True)
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_connect.py b/test/test_connect.py
new file mode 100644
index 0000000..82bafae
--- /dev/null
+++ b/test/test_connect.py
@@ -0,0 +1,85 @@
+import unittest
+from unittest.mock import Mock, patch
+
+from bitdotio import bitdotio
+
+
+class TestConnect(unittest.TestCase):
+    token = "v2_testtoken"
+
+    def setUp(self) -> None:
+        self.b = bitdotio(self.token)
+
+    def test_min_max_conn_validation(
+        self,
+    ) -> None:
+        test_cases = [(-1, 0), (0, -1), (0, 0), (1, 0)]
+        for min_conn, max_conn in test_cases:
+            with self.assertRaises(ValueError):
+                bitdotio(self.token, min_conn=min_conn, max_conn=max_conn)
+
+    @patch("bitdotio._bitdotio._BitV2._create_pool")
+    def test_connect(self, mock_create_pool: Mock) -> None:
+        db_1, db_2 = "my/db1", "my/db2"
+        with self.b.pooled_connection(db_1):
+            pass
+
+        # get/put should be called and there should be one pool after connecting once
+        self.assertEqual(len(self.b._pools), 1)
+        mock_create_pool.return_value.getconn.assert_called_once()
+        mock_create_pool.return_value.putconn.assert_called_once()
+
+        mock_create_pool.return_value.getconn.reset_mock()
+        mock_create_pool.return_value.putconn.reset_mock()
+        with self.b.pooled_connection(db_1):
+            pass
+
+        # get/put should be called and there should be one pool after connecting to the
+        # same database the second time.
+        self.assertEqual(len(self.b._pools), 1)
+        mock_create_pool.return_value.getconn.assert_called_once()
+        mock_create_pool.return_value.putconn.assert_called_once()
+
+        mock_create_pool.return_value.getconn.reset_mock()
+        mock_create_pool.return_value.putconn.reset_mock()
+        with self.b.pooled_connection(db_2):
+            pass
+
+        # get/put should be called and there should be two pools after connecting to
+        # the second database.
+        self.assertEqual(len(self.b._pools), 2)
+        mock_create_pool.return_value.getconn.assert_called_once()
+        mock_create_pool.return_value.putconn.assert_called_once()
+
+    @patch("bitdotio._bitdotio._BitV2._create_pool")
+    def test_cursor(self, mock_create_pool: Mock) -> None:
+        db_1, db_2 = "my/db1", "my/db2"
+        with self.b.pooled_cursor(db_1):
+            pass
+
+        # get/put should be called and there should be one pool after connecting once
+        self.assertEqual(len(self.b._pools), 1)
+        mock_create_pool.return_value.getconn.assert_called_once()
+        mock_create_pool.return_value.putconn.assert_called_once()
+
+        mock_create_pool.return_value.getconn.reset_mock()
+        mock_create_pool.return_value.putconn.reset_mock()
+        with self.b.pooled_cursor(db_1):
+            pass
+
+        # get/put should be called and there should be one pool after connecting to the
+        # same database the second time.
+        self.assertEqual(len(self.b._pools), 1)
+        mock_create_pool.return_value.getconn.assert_called_once()
+        mock_create_pool.return_value.putconn.assert_called_once()
+
+        mock_create_pool.return_value.getconn.reset_mock()
+        mock_create_pool.return_value.putconn.reset_mock()
+        with self.b.pooled_cursor(db_2):
+            pass
+
+        # get/put should be called and there should be two pools after connecting to
+        # the second database.
+        self.assertEqual(len(self.b._pools), 2)
+        mock_create_pool.return_value.getconn.assert_called_once()
+        mock_create_pool.return_value.putconn.assert_called_once()
diff --git a/test/test_import_file.py b/test/test_import_file.py
deleted file mode 100644
index e5eafc6..0000000
--- a/test/test_import_file.py
+++ /dev/null
@@ -1,35 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import sys
-import unittest
-
-import bitdotio
-from bitdotio.model.import_file import ImportFile
-
-
-class TestImportFile(unittest.TestCase):
-    """ImportFile unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def testImportFile(self):
-        """Test ImportFile"""
-        # FIXME: construct object with mandatory attributes with example values
-        # model = ImportFile()  # noqa: E501
-        pass
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_import_json.py b/test/test_import_json.py
deleted file mode 100644
index c034469..0000000
--- a/test/test_import_json.py
+++ /dev/null
@@ -1,35 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import sys
-import unittest
-
-import bitdotio
-from bitdotio.model.import_json import ImportJson
-
-
-class TestImportJson(unittest.TestCase):
-    """ImportJson unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def testImportJson(self):
-        """Test ImportJson"""
-        # FIXME: construct object with mandatory attributes with example values
-        # model = ImportJson()  # noqa: E501
-        pass
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_import_url.py b/test/test_import_url.py
deleted file mode 100644
index cbd2f7a..0000000
--- a/test/test_import_url.py
+++ /dev/null
@@ -1,35 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import sys
-import unittest
-
-import bitdotio
-from bitdotio.model.import_url import ImportUrl
-
-
-class TestImportUrl(unittest.TestCase):
-    """ImportUrl unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def testImportUrl(self):
-        """Test ImportUrl"""
-        # FIXME: construct object with mandatory attributes with example values
-        # model = ImportUrl()  # noqa: E501
-        pass
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_ingestion_result.py b/test/test_ingestion_result.py
deleted file mode 100644
index ddc50ff..0000000
--- a/test/test_ingestion_result.py
+++ /dev/null
@@ -1,35 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import sys
-import unittest
-
-import bitdotio
-from bitdotio.model.ingestion_result import IngestionResult
-
-
-class TestIngestionResult(unittest.TestCase):
-    """IngestionResult unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def testIngestionResult(self):
-        """Test IngestionResult"""
-        # FIXME: construct object with mandatory attributes with example values
-        # model = IngestionResult()  # noqa: E501
-        pass
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_ingestor_job.py b/test/test_ingestor_job.py
deleted file mode 100644
index 34c5335..0000000
--- a/test/test_ingestor_job.py
+++ /dev/null
@@ -1,35 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import sys
-import unittest
-
-import bitdotio
-from bitdotio.model.ingestor_job import IngestorJob
-
-
-class TestIngestorJob(unittest.TestCase):
-    """IngestorJob unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def testIngestorJob(self):
-        """Test IngestorJob"""
-        # FIXME: construct object with mandatory attributes with example values
-        # model = IngestorJob()  # noqa: E501
-        pass
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_q_connection.py b/test/test_q_connection.py
deleted file mode 100644
index 63ae1a9..0000000
--- a/test/test_q_connection.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-from __future__ import absolute_import
-
-import unittest
-import datetime
-
-import bitdotio
-from bitdotio.models.q_connection import QConnection  # noqa: E501
-from bitdotio.rest import ApiException
-
-class TestQConnection(unittest.TestCase):
-    """QConnection unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def make_instance(self, include_optional):
-        """Test QConnection
-            include_option is a boolean, when False only required
-            params are included, when True both required and
-            optional params are included """
-        # model = bitdotio.models.q_connection.QConnection()  # noqa: E501
-        if include_optional :
-            return QConnection(
-                url = '0', 
-                name = '0', 
-                owner = '0', 
-                kind = 'REST_CONNECTION'
-            )
-        else :
-            return QConnection(
-        )
-
-    def testQConnection(self):
-        """Test QConnection"""
-        inst_req_only = self.make_instance(include_optional=False)
-        inst_req_and_optional = self.make_instance(include_optional=True)
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_q_endpoint.py b/test/test_q_endpoint.py
deleted file mode 100644
index 699b35b..0000000
--- a/test/test_q_endpoint.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-from __future__ import absolute_import
-
-import unittest
-import datetime
-
-import bitdotio
-from bitdotio.models.q_endpoint import QEndpoint  # noqa: E501
-from bitdotio.rest import ApiException
-
-class TestQEndpoint(unittest.TestCase):
-    """QEndpoint unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def make_instance(self, include_optional):
-        """Test QEndpoint
-            include_option is a boolean, when False only required
-            params are included, when True both required and
-            optional params are included """
-        # model = bitdotio.models.q_endpoint.QEndpoint()  # noqa: E501
-        if include_optional :
-            return QEndpoint(
-                url = '0', 
-                name = '0', 
-                owner = '0', 
-                kind = 'EMAIL_IMPORT_ENDPOINT'
-            )
-        else :
-            return QEndpoint(
-        )
-
-    def testQEndpoint(self):
-        """Test QEndpoint"""
-        inst_req_only = self.make_instance(include_optional=False)
-        inst_req_and_optional = self.make_instance(include_optional=True)
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_q_user.py b/test/test_q_user.py
deleted file mode 100644
index 9e362a7..0000000
--- a/test/test_q_user.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-from __future__ import absolute_import
-
-import unittest
-import datetime
-
-import bitdotio
-from bitdotio.models.q_user import QUser  # noqa: E501
-from bitdotio.rest import ApiException
-
-class TestQUser(unittest.TestCase):
-    """QUser unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def make_instance(self, include_optional):
-        """Test QUser
-            include_option is a boolean, when False only required
-            params are included, when True both required and
-            optional params are included """
-        # model = bitdotio.models.q_user.QUser()  # noqa: E501
-        if include_optional :
-            return QUser(
-                connections = [
-                    '0'
-                    ], 
-                date_joined = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), 
-                first_name = '0', 
-                last_name = '0', 
-                profile = bitdotio.models.q_user_profile.QUser_profile(
-                    bio = '0', 
-                    website = 'a', 
-                    public_status = '0', 
-                    picture_path = 'a', 
-                    freeform_location = '0', ), 
-                repos_owned = [
-                    '0'
-                    ], 
-                url = '0', 
-                username = '0'
-            )
-        else :
-            return QUser(
-                profile = bitdotio.models.q_user_profile.QUser_profile(
-                    bio = '0', 
-                    website = 'a', 
-                    public_status = '0', 
-                    picture_path = 'a', 
-                    freeform_location = '0', ),
-        )
-
-    def testQUser(self):
-        """Test QUser"""
-        # inst_req_only = self.make_instance(include_optional=False)
-        # inst_req_and_optional = self.make_instance(include_optional=True)
-        pass
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_q_user_profile.py b/test/test_q_user_profile.py
deleted file mode 100644
index 637ffb8..0000000
--- a/test/test_q_user_profile.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-from __future__ import absolute_import
-
-import unittest
-import datetime
-
-import bitdotio
-from bitdotio.models.q_user_profile import QUserProfile  # noqa: E501
-from bitdotio.rest import ApiException
-
-class TestQUserProfile(unittest.TestCase):
-    """QUserProfile unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def make_instance(self, include_optional):
-        """Test QUserProfile
-            include_option is a boolean, when False only required
-            params are included, when True both required and
-            optional params are included """
-        # model = bitdotio.models.q_user_profile.QUserProfile()  # noqa: E501
-        if include_optional :
-            return QUserProfile(
-                bio = '0', 
-                website = 'a', 
-                public_status = '0', 
-                picture_path = 'a', 
-                freeform_location = '0'
-            )
-        else :
-            return QUserProfile(
-        )
-
-    def testQUserProfile(self):
-        """Test QUserProfile"""
-        # inst_req_only = self.make_instance(include_optional=False)
-        # inst_req_and_optional = self.make_instance(include_optional=True)
-        pass
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_query.py b/test/test_query.py
deleted file mode 100644
index 6aa8800..0000000
--- a/test/test_query.py
+++ /dev/null
@@ -1,35 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import sys
-import unittest
-
-import bitdotio
-from bitdotio.model.query import Query
-
-
-class TestQuery(unittest.TestCase):
-    """Query unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def testQuery(self):
-        """Test Query"""
-        # FIXME: construct object with mandatory attributes with example values
-        # model = Query()  # noqa: E501
-        pass
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_query_result.py b/test/test_query_result.py
deleted file mode 100644
index 4e0725b..0000000
--- a/test/test_query_result.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-from __future__ import absolute_import
-
-import unittest
-import datetime
-
-import bitdotio
-from bitdotio.models.query_result import QueryResult  # noqa: E501
-from bitdotio.rest import ApiException
-
-class TestQueryResult(unittest.TestCase):
-    """QueryResult unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def make_instance(self, include_optional):
-        """Test QueryResult
-            include_option is a boolean, when False only required
-            params are included, when True both required and
-            optional params are included """
-        # model = bitdotio.models.query_result.QueryResult()  # noqa: E501
-        if include_optional :
-            return QueryResult(
-                query_string = '0', 
-                fields = None, 
-                data = [
-                    None
-                    ]
-            )
-        else :
-            return QueryResult(
-                query_string = '0',
-                fields = None,
-                data = [
-                    None
-                    ],
-        )
-
-    def testQueryResult(self):
-        """Test QueryResult"""
-        # inst_req_only = self.make_instance(include_optional=False)
-        # inst_req_and_optional = self.make_instance(include_optional=True)
-        pass
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_repo.py b/test/test_repo.py
deleted file mode 100644
index e188f37..0000000
--- a/test/test_repo.py
+++ /dev/null
@@ -1,35 +0,0 @@
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-import sys
-import unittest
-
-import bitdotio
-from bitdotio.model.repo import Repo
-
-
-class TestRepo(unittest.TestCase):
-    """Repo unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def testRepo(self):
-        """Test Repo"""
-        # FIXME: construct object with mandatory attributes with example values
-        # model = Repo()  # noqa: E501
-        pass
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_repo_collaborators.py b/test/test_repo_collaborators.py
deleted file mode 100644
index 41ea6e6..0000000
--- a/test/test_repo_collaborators.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-from __future__ import absolute_import
-
-import unittest
-import datetime
-
-import bitdotio
-from bitdotio.models.repo_collaborators import RepoCollaborators  # noqa: E501
-from bitdotio.rest import ApiException
-
-class TestRepoCollaborators(unittest.TestCase):
-    """RepoCollaborators unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def make_instance(self, include_optional):
-        """Test RepoCollaborators
-            include_option is a boolean, when False only required
-            params are included, when True both required and
-            optional params are included """
-        # model = bitdotio.models.repo_collaborators.RepoCollaborators()  # noqa: E501
-        if include_optional :
-            return RepoCollaborators(
-                role = '0', 
-                role_display = '0', 
-                user = '0'
-            )
-        else :
-            return RepoCollaborators(
-                role = '0',
-        )
-
-    def testRepoCollaborators(self):
-        """Test RepoCollaborators"""
-        inst_req_only = self.make_instance(include_optional=False)
-        inst_req_and_optional = self.make_instance(include_optional=True)
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_table.py b/test/test_table.py
deleted file mode 100644
index 78aa8a1..0000000
--- a/test/test_table.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# coding: utf-8
-
-"""
-    bit.io REST API
-
-    bit.io API  # noqa: E501
-
-    The version of the OpenAPI document: 1.0.0b
-    Generated by: https://openapi-generator.tech
-"""
-
-
-from __future__ import absolute_import
-
-import unittest
-import datetime
-
-import bitdotio
-from bitdotio.models.table import Table  # noqa: E501
-from bitdotio.rest import ApiException
-
-class TestTable(unittest.TestCase):
-    """Table unit test stubs"""
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    def make_instance(self, include_optional):
-        """Test Table
-            include_option is a boolean, when False only required
-            params are included, when True both required and
-            optional params are included """
-        # model = bitdotio.models.table.Table()  # noqa: E501
-        if include_optional :
-            return Table(
-                url = '0', 
-                current_name = '0', 
-                description = '0', 
-                columns = [
-                    '0'
-                    ], 
-                num_records = 56, 
-                bytes = '0', 
-                repo = '0', 
-                documentation = '0'
-            )
-        else :
-            return Table(
-        )
-
-    def testTable(self):
-        """Test Table"""
-        inst_req_only = self.make_instance(include_optional=False)
-        inst_req_and_optional = self.make_instance(include_optional=True)
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/test/test_utils.py b/test/test_utils.py
new file mode 100644
index 0000000..103adb3
--- /dev/null
+++ b/test/test_utils.py
@@ -0,0 +1,34 @@
+import unittest
+
+from bitdotio.utils import validate_database_name, validate_token
+
+
+class TestUtils(unittest.TestCase):
+    def test_validate_token_ok(self) -> None:
+        validate_token("v2_testtoken")
+
+    def test_validate_token_error(self) -> None:
+        test_cases = ["v2_", "v1_testtoken", "v2__.--_--", "v2testtoken", "testtoken"]
+        for test_case in test_cases:
+            with self.assertRaises(ValueError):
+                validate_token(test_case)
+
+    def test_validate_database_name_ok(self) -> None:
+        validate_database_name("my/db")
+        validate_database_name("m/d")
+        validate_database_name("my/db/with/some/slashes")
+        validate_database_name("my/db/with.some+other$things")
+
+    def test_validate_database_name_error(self) -> None:
+        test_cases = [
+            "/mydb",
+            "mydb",
+            "myExtremelyLongUserNameWhichIsDefinitelyWayTooLong/db",
+            "me/myExtremelyLongDatabaseNameWhichIsDefinitelyWayTooLong",
+            "-/db",
+            "./db",
+            "me/",
+        ]
+        for test_case in test_cases:
+            with self.assertRaises(ValueError):
+                validate_database_name(test_case)
diff --git a/test/test_v2_config.py b/test/test_v2_config.py
deleted file mode 100644
index 0e22ed7..0000000
--- a/test/test_v2_config.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import os
-import unittest
-
-import bitdotio
-from bitdotio.bitdotio import _Bit, _BitV2
-
-"""
-Tests automatic SDK configuration based on token version and v1-only attribute messages.
-"""
-
-
-class TestTokenVersionConfig(unittest.TestCase):
-
-    def test_v1_token(self):
-        """Test that v1 formatted token causes v1 object construction"""
-        b = bitdotio.bitdotio("3UPuN_fakeTOKENDDPEBNp7Cux7gy")
-        self.assertIsInstance(b, _Bit)
-
-    def test_v2_token(self):
-        """Test that v2 formatted token causes v2 object construction"""
-        b = bitdotio.bitdotio("v2_5_fakeTOKENWxwNLWZvWCXi6c")
-        self.assertIsInstance(b, _BitV2)
-
-    def test_invalid_token(self):
-        """Test that invalid token format raises value error"""
-        with self.assertRaises(ValueError):
-            b = bitdotio.bitdotio("v2_5_fakeTOKENWx_wNLWZvWCXi6c")
-            self.assertIsInstance(b, _BitV2)    
-
-class TestAttributeMessages(unittest.TestCase):
-    """Test that attempt to access a v1-only attribute causes an attribute error"""
-    def test_v1_only_attribute_with_v2(self):
-        b = bitdotio.bitdotio("v2_5_fakeTOKENWxwNLWZvWCXi6c")
-        with self.assertRaises(AttributeError) as e:
-            b.list_repos()
-        self.assertIn("You have configured the SDK with a v2 token, and", str(e.exception))
-
-    """Test that attempt to access invalid attribute raises normal attribute error"""
-    def test_invalid_attribute_with_v2(self):
-        b = bitdotio.bitdotio("v2_5_fakeTOKENWxwNLWZvWCXi6c")
-        with self.assertRaises(AttributeError) as e:
-            b.fake_method()
-        self.assertIn("'_BitV2' object has no attribute 'fake_method'", str(e.exception))
-
-
-if __name__ == "__main__":
-    unittest.main()