# Buggy code
def ParseArguments(self):
    """Parses the command line arguments.

    Returns:
      A boolean value indicating the arguments were successfully parsed.
    """
    logging.basicConfig(level=logging.INFO, format="[%(levelname)s] %(message)s")

    argument_parser = argparse.ArgumentParser(
        description=self.DESCRIPTION, epilog=self.EPILOG, add_help=False
    )

    self.AddBasicOptions(argument_parser)
    self.AddInformationalOptions(argument_parser)
    self.AddDataOptions(argument_parser)

    argument_parser.add_argument(
        "-w",
        "--write",
        action="store",
        dest="path",
        type=unicode,
        metavar="PATH",
        default="export",
        help=("The directory in which extracted files should be stored."),
    )

    argument_parser.add_argument(
        "-f",
        "--filter",
        action="store",
        dest="filter",
        type=unicode,
        metavar="FILTER_FILE",
        help=(
            "Full path to the file that contains the collection filter, "
            "the file can use variables that are defined in preprocesing, "
            "just like any other log2timeline/plaso collection filter."
        ),
    )

    argument_parser.add_argument(
        "--date-filter",
        "--date_filter",
        action="append",
        type=unicode,
        dest="date_filters",
        metavar="TYPE_START_END",
        default=None,
        help=(
            "Filter based on file entry date and time ranges. This parameter "
            'is formatted as "TIME_VALUE,START_DATE_TIME,END_DATE_TIME" where '
            "TIME_VALUE defines which file entry timestamp the filter applies "
            "to e.g. atime, ctime, crtime, bkup, etc. START_DATE_TIME and "
            "END_DATE_TIME define respectively the start and end of the date "
            "time range. A date time range requires at minimum start or end "
            "to time of the boundary and END defines the end time. Both "
            "timestamps be set. The date time values are formatted as: "
            "YYYY-MM-DD hh:mm:ss.######[+-]##:## Where # are numeric digits "
            "ranging from 0 to 9 and the seconds fraction can be either 3 "
            "or 6 digits. The time of day, seconds fraction and timezone "
            'offset are optional. The default timezone is UTC. E.g. "atime, '
            '2013-01-01 23:12:14, 2013-02-23". This parameter can be repeated '
            "as needed to add additional date date boundaries, eg: once for "
            "atime, once for crtime, etc."
        ),
    )

    argument_parser.add_argument(
        "-x",
        "--extensions",
        dest="extensions_string",
        action="store",
        type=unicode,
        metavar="EXTENSIONS",
        help=(
            "Filter based on file name extensions. This option accepts "
            'multiple multiple comma separated values e.g. "csv,docx,pst".'
        ),
    )

    argument_parser.add_argument(
        "--names",
        dest="names_string",
        action="store",
        type=str,
        metavar="NAMES",
        help=(
            "If the purpose is to find all files given a certain names "
            "this options should be used. This option accepts a comma "
            "separated string denoting all file names, eg: -x "
            '"NTUSER.DAT,UsrClass.dat".'
        ),
    )

    argument_parser.add_argument(
        "--signatures",
        dest="signature_identifiers",
        action="store",
        type=unicode,
        metavar="IDENTIFIERS",
        help=(
            "Filter based on file format signature identifiers. This option "
            'accepts multiple comma separated values e.g. "esedb,lnk". '
            'Use "list" to show an overview of the supported file format '
            "signatures."
        ),
    )

    argument_parser.add_argument(
        "--include_duplicates",
        dest="include_duplicates",
        action="store_true",
        default=False,
        help=(
            "If extraction from VSS is enabled, by default a digest hash "
            "is calcuted for each file. These hases are compared to the "
            "previously exported files and duplicates are skipped. Use "
            "this option to include duplicate files in the export."
        ),
    )

    self.AddStorageMediaImageOptions(argument_parser)
    self.AddVssProcessingOptions(argument_parser)

    argument_parser.add_argument(
        "image",
        nargs="?",
        action="store",
        metavar="IMAGE",
        default=None,
        type=unicode,
        help=(
            "The full path to the image file that we are about to extract "
            "files from, it should be a raw image or another image that "
            "plaso supports."
        ),
    )

    try:
        options = argument_parser.parse_args()
    except UnicodeEncodeError:
        # If we get here we are attempting to print help in a non-Unicode
        # terminal.
        self._output_writer.Write("")
        self._output_writer.Write(argument_parser.format_help())
        return False

    try:
        self.ParseOptions(options)
    except errors.BadConfigOption as exception:
        logging.error("{0:s}".format(exception))

        self._output_writer.Write("")
        self._output_writer.Write(argument_parser.format_help())

        return False

    return True


# Traceback (AttributeError)
./tools/image_export.py --help
Traceback (most recent call last):
File "./tools/image_export.py", line 312, in <module>
if not Main():
File "./tools/image_export.py", line 281, in Main
if not tool.ParseArguments():
File "./tools/image_export.py", line 94, in ParseArguments
self.AddDataOptions(argument_parser)
AttributeError: 'ImageExportTool' object has no attribute 'AddDataOptions'

# Fixed code
def ParseArguments(self):
    """Parses the command line arguments.

    Returns:
      A boolean value indicating the arguments were successfully parsed.
    """
    logging.basicConfig(level=logging.INFO, format="[%(levelname)s] %(message)s")

    argument_parser = argparse.ArgumentParser(
        description=self.DESCRIPTION, epilog=self.EPILOG, add_help=False
    )

    self.AddBasicOptions(argument_parser)
    self.AddInformationalOptions(argument_parser)
    self.AddDataLocationOption(argument_parser)

    argument_parser.add_argument(
        "-w",
        "--write",
        action="store",
        dest="path",
        type=unicode,
        metavar="PATH",
        default="export",
        help=("The directory in which extracted files should be stored."),
    )

    argument_parser.add_argument(
        "-f",
        "--filter",
        action="store",
        dest="filter",
        type=unicode,
        metavar="FILTER_FILE",
        help=(
            "Full path to the file that contains the collection filter, "
            "the file can use variables that are defined in preprocessing, "
            "just like any other log2timeline/plaso collection filter."
        ),
    )

    argument_parser.add_argument(
        "--date-filter",
        "--date_filter",
        action="append",
        type=unicode,
        dest="date_filters",
        metavar="TYPE_START_END",
        default=None,
        help=(
            "Filter based on file entry date and time ranges. This parameter "
            'is formatted as "TIME_VALUE,START_DATE_TIME,END_DATE_TIME" where '
            "TIME_VALUE defines which file entry timestamp the filter applies "
            "to e.g. atime, ctime, crtime, bkup, etc. START_DATE_TIME and "
            "END_DATE_TIME define respectively the start and end of the date "
            "time range. A date time range requires at minimum start or end "
            "to time of the boundary and END defines the end time. Both "
            "timestamps be set. The date time values are formatted as: "
            "YYYY-MM-DD hh:mm:ss.######[+-]##:## Where # are numeric digits "
            "ranging from 0 to 9 and the seconds fraction can be either 3 "
            "or 6 digits. The time of day, seconds fraction and timezone "
            'offset are optional. The default timezone is UTC. E.g. "atime, '
            '2013-01-01 23:12:14, 2013-02-23". This parameter can be repeated '
            "as needed to add additional date date boundaries, eg: once for "
            "atime, once for crtime, etc."
        ),
    )

    argument_parser.add_argument(
        "-x",
        "--extensions",
        dest="extensions_string",
        action="store",
        type=unicode,
        metavar="EXTENSIONS",
        help=(
            "Filter based on file name extensions. This option accepts "
            'multiple multiple comma separated values e.g. "csv,docx,pst".'
        ),
    )

    argument_parser.add_argument(
        "--names",
        dest="names_string",
        action="store",
        type=str,
        metavar="NAMES",
        help=(
            "If the purpose is to find all files given a certain names "
            "this options should be used. This option accepts a comma "
            "separated string denoting all file names, eg: -x "
            '"NTUSER.DAT,UsrClass.dat".'
        ),
    )

    argument_parser.add_argument(
        "--signatures",
        dest="signature_identifiers",
        action="store",
        type=unicode,
        metavar="IDENTIFIERS",
        help=(
            "Filter based on file format signature identifiers. This option "
            'accepts multiple comma separated values e.g. "esedb,lnk". '
            'Use "list" to show an overview of the supported file format '
            "signatures."
        ),
    )

    argument_parser.add_argument(
        "--include_duplicates",
        dest="include_duplicates",
        action="store_true",
        default=False,
        help=(
            "If extraction from VSS is enabled, by default a digest hash "
            "is calcuted for each file. These hases are compared to the "
            "previously exported files and duplicates are skipped. Use "
            "this option to include duplicate files in the export."
        ),
    )

    self.AddStorageMediaImageOptions(argument_parser)
    self.AddVssProcessingOptions(argument_parser)

    argument_parser.add_argument(
        "image",
        nargs="?",
        action="store",
        metavar="IMAGE",
        default=None,
        type=unicode,
        help=(
            "The full path to the image file that we are about to extract "
            "files from, it should be a raw image or another image that "
            "plaso supports."
        ),
    )

    try:
        options = argument_parser.parse_args()
    except UnicodeEncodeError:
        # If we get here we are attempting to print help in a non-Unicode
        # terminal.
        self._output_writer.Write("")
        self._output_writer.Write(argument_parser.format_help())
        return False

    try:
        self.ParseOptions(options)
    except errors.BadConfigOption as exception:
        logging.error("{0:s}".format(exception))

        self._output_writer.Write("")
        self._output_writer.Write(argument_parser.format_help())

        return False

    return True