text: from __future__ import absolute_import
  
  import click
  from .utils import (
      LoadCsvError,
      LookupTable,
      PathOrURL,
      add_index,
      apply_dates_and_datetimes,
      apply_shape,
      best_fts_version,
      csvs_from_paths,
      generate_and_populate_fts,
      load_csv,
      refactor_dataframes,
      table_exists,
      table_outdated,
      update_csv_meta,
      drop_table,
      to_sql_with_foreign_keys,
  )
  import os
  import sqlite3
  
  
  @click.command()
  @click.argument("paths", type=PathOrURL(exists=True), nargs=-1, required=True)
  @click.argument("dbname", nargs=1)
  @click.option("--separator", "-s", default=",", help="Field separator in input .csv")
  @click.option(
      "--quoting",
      "-q",
      default=0,
      help="Control field quoting behavior per csv.QUOTE_* constants. Use one of QUOTE_MINIMAL (0), QUOTE_ALL (1), QUOTE_NONNUMERIC (2) or QUOTE_NONE (3).",
  )
  @click.option(
      "--skip-errors",
      is_flag=True,
      help="Skip lines with too many fields instead of stopping the import",
  )
  @click.option(
      "--replace-tables", is_flag=True, help="Replace tables if they already exist"
  )
  @click.option(
      "--update-tables",
      is_flag=True,
      help=(
          "Manages an extra table .csvs-meta that keeps "
          "track of each CSV file and the checksum of the "
          "file. On subsequent runs, the CSVs will be "
          "compared against the checksum in the table "
          "to see what has updated, and only those "
          "specific tables will be replaced."
      ),
  )
  @click.option(
      "--table", "-t", help="Table to use (instead of using CSV filename)", default=None
  )
  @click.option(
      "--extract-column",
      "-c",
      multiple=True,
      help=(
          "One or more columns to 'extract' into a separate lookup table. "
          "If you pass a simple column name that column will be replaced "
          "with integer foreign key references to a new table of that "
          "name. You can customize the name of the table like so:\n"
          "    state:States:state_name\n\n"
          "This will pull unique values from the 'state' column and use "
          "them to populate a new 'States' table, with an id column "
          "primary key and a state_name column containing the strings "
          "from the original column."
      ),
  )
  @click.option(
      "--date",
      "-d",
      multiple=True,
      help=("One or more columns to parse into ISO formatted dates"),
  )
  @click.option(
      "--datetime",
      "-dt",
      multiple=True,
      help=("One or more columns to parse into ISO formatted datetimes"),
  )
  @click.option(
      "--datetime-format",
      "-df",
      multiple=True,
      help=("One or more custom date format strings to try when parsing dates/datetimes"),
  )
  @click.option(
      "--primary-key",
      "-pk",
      multiple=True,
      help=("One or more columns to use as the primary key"),
  )
  @click.option(
      "--fts",
      "-f",
      multiple=True,
      help=("One or more columns to use to populate a full-text index"),
  )
  @click.option(
      "--index",
      "-i",
      multiple=True,
      help=("Add index on this column (or a compound index with -i col1,col2)"),
  )
  @click.option(
      "--shape",
      help="Custom shape for the DB table - format is csvcol:dbcol(TYPE),...",
      default=None,
  )
  @click.option(
      "--filename-column",
      help="Add a column with this name and populate with CSV file name",
      default=None,
  )
  @click.option(
      "fixed_columns",
      "--fixed-column",
      type=(str, str),
      multiple=True,
      help="Populate column with a fixed string",
      default=None,
  )
  @click.option(
      "fixed_columns_int",
      "--fixed-column-int",
      type=(str, int),
      multiple=True,
      help="Populate column with a fixed integer",
      default=None,
  )
  @click.option(
      "fixed_columns_float",
      "--fixed-column-float",
      type=(str, float),
      multiple=True,
      help="Populate column with a fixed float",
      default=None,
  )
  @click.option(
      "--no-index-fks",
      "no_index_fks",
      is_flag=True,
      help="Skip adding index to foreign key columns created using --extract-column (default is to add them)",
  )
  @click.option(
      "--no-fulltext-fks",
      "no_fulltext_fks",
      is_flag=True,
      help="Skip adding full-text index on values extracted using --extract-column (default is to add them)",
  )
  @click.option(
      "--just-strings",
      is_flag=True,
      help="Import all columns as text strings by default (and, if specified, still obey --shape, --date/datetime, and --datetime-format)",
  )
  @click.version_option()
  def cli(
      paths,
      dbname,
      separator,
      quoting,
      skip_errors,
      replace_tables,
      update_tables,
      table,
      extract_column,
      date,
      datetime,
      datetime_format,
      primary_key,
      fts,
      index,
      shape,
      filename_column,
      fixed_columns,
      fixed_columns_int,
      fixed_columns_float,
      no_index_fks,
      no_fulltext_fks,
      just_strings,
  ):
      """
      PATHS: paths to individual .csv files or to directories containing .csvs
  
      DBNAME: name of the SQLite database file to create
      """
      # make plural for more readable code:
      extract_columns = extract_column
      del extract_column
  
      if extract_columns:
          click.echo("extract_columns={}".format(extract_columns))
      if dbname.endswith(".csv"):
          raise click.BadParameter("dbname must not end with .csv")
      if "." not in dbname:
          dbname += ".db"
  
      db_existed = os.path.exists(dbname)
  
      conn = sqlite3.connect(dbname)
  
      dataframes = []
      csvs = csvs_from_paths(paths)
      sql_type_overrides = None
      for name, path in csvs.items():
          try:
              if not update_tables or table_outdated(conn, path):
                  df = load_csv(
                      path, separator, skip_errors, quoting, shape, just_strings=just_strings
                  )
                  df.table_name = table or name
                  if filename_column:
                      df[filename_column] = name
                      if shape:
                          shape += ",{}".format(filename_column)
                  if fixed_columns:
                      for colname, value in fixed_columns:
                          df[colname] = value
                          if shape:
                              shape += ",{}".format(colname)
                  if fixed_columns_int:
                      for colname, value in fixed_columns_int:
                          df[colname] = value
                          if shape:
                              shape += ",{}".format(colname)
                  if fixed_columns_float:
                      for colname, value in fixed_columns_float:
                          df[colname] = value
                          if shape:
                              shape += ",{}".format(colname)
                  sql_type_overrides = apply_shape(df, shape)
                  apply_dates_and_datetimes(df, date, datetime, datetime_format)
                  dataframes.append(df)
  
                  if update_tables:
                      update_csv_meta(conn, path)
          except LoadCsvError as e:
              click.echo("Could not load {}: {}".format(path, e), err=True)
  
      click.echo("Loaded {} dataframes".format(len(dataframes)))
  
      # Use extract_columns to build a column:(table,label) dictionary
      foreign_keys = {}
      for col in extract_columns:
          bits = col.split(":")
          if len(bits) == 3:
              foreign_keys[bits[0]] = (bits[1], bits[2])
          elif len(bits) == 2:
              foreign_keys[bits[0]] = (bits[1], "value")
          else:
              foreign_keys[bits[0]] = (bits[0], "value")
  
      # Now we have loaded the dataframes, we can refactor them
      created_tables = {}
      refactored = refactor_dataframes(
          conn, dataframes, foreign_keys, not no_fulltext_fks
      )
      for df in refactored:
          # This is a bit trickier because we need to
          # create the table with extra SQL for foreign keys
          if (replace_tables or update_tables) and table_exists(conn, df.table_name):
              drop_table(conn, df.table_name)
          if table_exists(conn, df.table_name):
              df.to_sql(df.table_name, conn, if_exists="append", index=False)
          else:
              to_sql_with_foreign_keys(
                  conn,
                  df,
                  df.table_name,
                  foreign_keys,
                  sql_type_overrides,
                  primary_keys=primary_key,
                  index_fks=not no_index_fks,
              )
              created_tables[df.table_name] = df
          if index:
              for index_defn in index:
                  add_index(conn, df.table_name, index_defn)
  
      # Create FTS tables
      if fts:
          fts_version = best_fts_version()
          if not fts_version:
              conn.close()
              raise click.BadParameter(
                  "Your SQLite version does not support any variant of FTS"
              )
          # Check that columns make sense
          for table, df in created_tables.items():
              for fts_column in fts:
                  if fts_column not in df.columns:
                      raise click.BadParameter(
                          'FTS column "{}" does not exist'.format(fts_column)
                      )
  
          generate_and_populate_fts(conn, created_tables.keys(), fts, foreign_keys)
  
      conn.close()
  
      if db_existed and not update_tables:
          click.echo(
              "Added {} CSV file{} to {}".format(
                  len(csvs), "" if len(csvs) == 1 else "s", dbname
              )
          )
      elif db_existed and update_tables:
          click.echo(
              "Updated {} CSV file{} in {}".format(
                  len(dataframes), "" if len(dataframes) == 1 else "s", dbname
              )
          )
      else:
          click.echo(
              "Created {} from {} CSV file{}".format(
                  dbname, len(csvs), "" if len(csvs) == 1 else "s"
              )
          )
  