text: #!/usr/bin/env python
  # coding: utf-8
  import os
  import re
  import csv
  import sys
  import glob
  import struct
  import logging
  import argparse
  
  from dbfread import DBF
  
  from . import __version__
  
  from io import open
  from builtins import str
  
  def get_args():
      """Get CLI arguments and options"""
      parser = argparse.ArgumentParser(
          prog='dbf2csv',
          description='small utility to convert simple *.DBF files to *.CSV'
      )
      parser.add_argument('input')
      parser.add_argument('output', nargs='?', default=None)
  
      parser.add_argument('-ie', '--input-encoding',
                          default='cp850',
                          help='charset of *.dbf files (default: cp850)')
      parser.add_argument('-oe', '--output-encoding',
                          default='utf8',
                          help='charset of *.csv files (default: utf8)')
      parser.add_argument('-q', '--quoting-mode',
                          choices=('minimal', 'all', 'non-numeric', 'none'),
                          default='minimal',
                          help='quoting mode for csv files (default: minimal)')
      parser.add_argument('-d', '--delimiter-char',
                          default=',',
                          help='delimiter char for csv files (default: ",")')
      parser.add_argument('-e', '--escape-char',
                          default='\\',
                          help='escape char for csv files (default: "\\")')
      parser.add_argument('--version', action='version',
                          version='%(prog)s {version}'.format(version=__version__))
      return parser.parse_args()
  
  
  def __convert(input_file_path, output_file, args):
  
      def encode_decode(x):
          """
          DBF returns a unicode string encoded as args.input_encoding.
          We convert that back into bytes and then decode as args.output_encoding.
          """
          if not isinstance(x, str):
              # DBF converts columns into non-str like int, float
              x = str(x) if x is not None else ''
          return x.encode(args.input_encoding).decode(args.output_encoding)
  
      try:
          input_reader = DBF(input_file_path,
                             encoding=args.input_encoding,
                             ignore_missing_memofile=True)
  
          output_writer = csv.DictWriter(output_file,
                                     quoting=args.quoting,
                                     escapechar=args.escape_char,
                                     delimiter=args.delimiter_char,
                                     fieldnames=[encode_decode(x) for x in input_reader.field_names])
  
          output_writer.writeheader()
          for record in input_reader:
              row = {encode_decode(k):encode_decode(v) for k,v in record.items()}
              output_writer.writerow(row)
  
      except (UnicodeDecodeError, LookupError):
          log.error('Error: Unknown encoding\n')
          exit(0)
      except UnicodeEncodeError:
          log.error('Error: Can\'t encode to output encoding: {}\n'.format(
              args.to_charset))
          exit(0)
      except struct.error:
          log.error('Error: Bad input file format: {}\n'.format(
              os.path.basename(input_file_path))
          )
          exit(0)
  
  
  def process_directory(input_dir_path, output_dir_path, args):
      if not output_dir_path:
          output_dir_path = input_dir_path
  
      input_files = [f for f in glob.glob('{}/*'.format(input_dir_path)) if re.match('^.*\.dbf$', f, flags=re.IGNORECASE)]
  
      if not input_files:
          exit(0)
  
      if output_dir_path != input_dir_path:
          if not os.path.exists(output_dir_path):
              os.makedirs(output_dir_path)
  
      for input_file_path in input_files:
          output_file_path = '{}/{}.csv'.format(
              output_dir_path,
              os.path.splitext(os.path.basename(input_file_path))[0]
          )
          process_file(input_file_path, output_file_path, args)
  
  
  def process_file(input_file_path, output_file_path, args):
      if output_file_path:
          with open(output_file_path, 'w', encoding=args.output_encoding) as output_file:
              __convert(input_file_path, output_file, args)
      else:
          __convert(input_file_path, sys.stdout, args)
  
  
  def main():
      sys.tracebacklimit = 0
  
      args = get_args()
  
      if args.quoting_mode == 'minimal':
          args.quoting = csv.QUOTE_MINIMAL
      elif args.quoting_mode == 'all':
          args.quoting = csv.QUOTE_ALL
      elif args.quoting_mode == 'non-numeric':
          args.quoting = csv.QUOTE_NONNUMERIC
      elif args.quoting_mode == 'none':
          args.quoting = csv.QUOTE_NONE
  
      if os.path.isdir(args.input):
          process_directory(args.input, args.output, args)
      elif os.path.isfile(args.input):
          process_file(args.input, args.output, args)
  
  
  if __name__ == '__main__':
      log = logging.getLogger()
      log.setLevel(logging.DEBUG)
      log.addHandler(logging.StreamHandler())
  
      try:
          main()
      except KeyboardInterrupt:
          pass
  