from behave.configuration import Configuration
from behave.formatter._registry import make_formatters
from behave.runner import Runner, Context
from behave.runner_util import parse_features, print_undefined_step_snippets
from behave.model import Examples, ScenarioOutline, Table
from lxml import etree


class DQRunner(Runner):
    def run_with_paths(self):

        self.context = Context(self)
        self.load_hooks()
        self.load_step_definitions()

        # -- ENSURE: context.execute_steps() works in weird cases (hooks, ...)
        # self.setup_capture()
        # self.run_hook('before_all', self.context)

        # -- STEP: Parse all feature files (by using their file location).
        feature_locations = [ filename for filename in self.feature_locations()
                                    if not self.config.exclude(filename) ]
        features = parse_features(feature_locations, language=self.config.lang)

        doc = self.context.config.userdata['doc']
        organisations = doc.xpath('//iati-organisation')
        if len(organisations) > 0:
            self.context.filetype = 'org'
            # if this looks like an org file, set the organisation
            self.context.organisation = organisations[0]
            self.context.activities = []
        else:
            self.context.filetype = 'activity'
            # otherwise, set the activities
            self.context.activities = doc.xpath('//iati-activity')
            self.context.organisation = None

            activities = self.context.activities
            rows = [['Activity {}'.format(idx)] for idx, _ in enumerate(activities)]
            table = Table(
                ['activity name'],
                line=0,
                rows=rows,
            )
            examples = Examples('', 0, 'Example', 'Activity', table=table)
            # Hack to run the scenario once for each activity
            for feature in features:
                for scenario in feature.scenarios:
                    if type(scenario) is ScenarioOutline:
                        scenario.examples.append(examples)
        self.features.extend(features)

        # -- STEP: Run all features.
        stream_openers = self.config.outputs
        self.formatters = make_formatters(self.config, stream_openers)
        return self.run_model()

def main(args=[]):
    if len(args) > 0 and len(args[0]) > 0 and args[0][0] != '-':
        filepath = args.pop(0)
    else:
        filepath = None

    # hack. We use the existing arg parser, then
    # attempt to extract the XML file from the
    # parsed args.

    # eventually we can add our own arg parser here.
    config = Configuration(args)
    if not config.format:
        config.format = [config.default_format]

    if not filepath:
        print('Please provide an XML file to test')
        return 1

    try:
        doc = etree.parse(filepath)
    except OSError:
        print('{} is not a valid XML file'.format(filepath))
        return 1
    except etree.XMLSyntaxError as e:
        print('Failed trying to parse {}'.format(filepath))
        print('\n  ' + str(e))
        return 1

    config.userdata = {
        'doc': doc,
    }

    runner = DQRunner(config)
    failed = runner.run()

    if config.show_snippets and runner.undefined_steps:
        print_undefined_step_snippets(runner.undefined_steps,
                                      colored=config.color)

    return 1 if failed else 0

@@ -333,67 +333,1188 @@
 def 
-run_with_paths(self):%0A%0A        self.context = Context(self)
+__init__(self, args=%5B%5D):%0A        # hack. We use the existing arg parser, then%0A        # attempt to extract the XML file from the%0A        # parsed args.%0A%0A        # eventually we can add our own arg parser here.%0A        config = Configuration(args)%0A        if not config.format:%0A            config.format = %5Bconfig.default_format%5D%0A%0A        super(DQRunner, self).__init__(config)%0A%0A    def run_file(self, filepath):%0A        if not filepath:%0A            raise Exception('Please provide an XML file to test')%0A%0A        try:%0A            doc = etree.parse(filepath)%0A        except OSError:%0A            raise Exception('%7B%7D is not a valid XML file'.format(filepath))%0A        except etree.XMLSyntaxError as e:%0A            raise Exception('Failed trying to parse %7B%7D'.format(filepath))%0A        self.context = Context(self)%0A        self.context.doc = doc%0A%0A        failed = self.run()%0A%0A        if self.config.show_snippets and self.undefined_steps:%0A            print_undefined_step_snippets(self.undefined_steps,%0A                                          colored=self.config.color)%0A%0A        if failed:%0A            raise Exception%0A%0A        return self.context.score%0A%0A    def run_with_paths(self):%0A
 %0A   
@@ -2079,30 +2079,11 @@
 ext.
-config.userdata%5B'
 doc
-'%5D
 %0A   
@@ -3583,947 +3583,127 @@
     
-# hack. We use the existing arg parser, then%0A    # attempt to extract the XML file from the%0A    # parsed args.%0A%0A    # eventually we can add our own arg parser here.%0A    config = Configuration(args)%0A    if not config.format:%0A        config.format = %5Bconfig.default_format%5D%0A%0A    if not filepath:%0A        print('Please provide an XML file to test')%0A        return 1%0A%0A    try:%0A        doc = etree.parse(filepath)%0A    except OSError:%0A        print('%7B%7D is not a valid XML file'.format(filepath))%0A        return 1%0A    except etree.XMLSyntaxError as e:%0A        print('Failed trying to parse %7B%7D'.format(filepath))%0A        print('%5Cn  ' + str(e))%0A        return 1%0A%0A    config.userdata = %7B%0A        'doc': doc,%0A    %7D%0A%0A    runner = DQRunner(config)%0A    failed = runner.run()%0A%0A    if config.show_snippets and runner.undefined_steps:%0A        print_undefined_step_snippets(runner.undefined_steps,%0A                                      colored=config.color)
+runner = DQRunner(args)%0A    failed = False%0A    try:%0A        runner.run_file(filepath)%0A    except:%0A        failed = True
 %0A%0A  

Refactor a bit