Commit 37d5a910 by Chris Morgan

Assorted bits of code cleanup; mainly better PEP8.

- Insert blank lines where missing
- Remove surplus blank lines
- Remove some unused imports
- Remove the use of the ``string`` module from lettuce.strings (work on the ``str`` objects directly which is just what ``string`` does - it's mostly obsolete now)
- Reshuffled a few bits of code to use ``all()`` or ``any()`` where appropriate and *not* use them where inappropriate

No functionality changes. (All tests still pass.)
parent 7436c4bf
......@@ -32,6 +32,7 @@ from lettuce.exceptions import LettuceSyntaxError
fs = FileSystem()
class HashList(list):
__base_msg = 'The step "%s" have no table defined, so ' \
'that you can\'t use step.hashes.%s'
......@@ -64,6 +65,7 @@ class HashList(list):
raise AssertionError(self.__base_msg % (self.step.sentence, 'last'))
class Language(object):
code = 'en'
name = 'English'
......@@ -73,6 +75,7 @@ class Language(object):
examples = 'Examples|Scenarios'
scenario_outline = 'Scenario Outline'
scenario_separator = 'Scenario( Outline)?'
def __init__(self, code=u'en'):
self.code = code
for attr, value in languages.LANGUAGES[code].items():
......@@ -98,6 +101,7 @@ class Language(object):
return instance
class StepDefinition(object):
"""A step definition is a wrapper for user-defined callbacks. It
gets a few metadata from file, such as filename and line number"""
......@@ -122,6 +126,7 @@ class StepDefinition(object):
return ret
class StepDescription(object):
"""A simple object that holds filename and line number of a step
description (step within feature file)"""
......@@ -132,6 +137,7 @@ class StepDescription(object):
self.line = line
class ScenarioDescription(object):
"""A simple object that holds filename and line number of a scenario
description (scenario within feature file)"""
......@@ -146,6 +152,7 @@ class ScenarioDescription(object):
self.line = pline + 1
break
class FeatureDescription(object):
"""A simple object that holds filename and line number of a feature
description"""
......@@ -168,6 +175,7 @@ class FeatureDescription(object):
self.description_at = tuple(described_at)
class Step(object):
""" Object that represents each step on feature files."""
has_definition = False
......@@ -198,8 +206,8 @@ class Step(object):
method_name = sentence
groups = [
('"', re.compile(r'("[^"]+")')), # double quotes
("'", re.compile(r"('[^']+')")), # single quotes
('"', re.compile(r'("[^"]+")')), # double quotes
("'", re.compile(r"('[^']+')")), # single quotes
]
attribute_names = []
......@@ -217,14 +225,11 @@ class Step(object):
method_name = method_name.replace(match, group_name)
attribute_names.append(group_name)
method_name = unicodedata.normalize('NFKD', method_name) \
.encode('ascii', 'ignore')
method_name = '%s(step%s)' % (
"_".join(re.findall("\w+", method_name)).lower(),
attribute_names and (", %s" % ", ".join(attribute_names)) or ""
)
attribute_names and (", %s" % ", ".join(attribute_names)) or "")
return method_name, sentence
......@@ -232,6 +237,7 @@ class Step(object):
sentence = self.sentence
hashes = self.hashes[:] # deep copy
for k, v in data.items():
def evaluate(stuff):
return stuff.replace(u'<%s>' % unicode(k), unicode(v))
......@@ -387,7 +393,7 @@ class Step(object):
return True
@staticmethod
def run_all(steps, outline = None, run_callbacks = False, ignore_case = True):
def run_all(steps, outline=None, run_callbacks=False, ignore_case=True):
"""Runs each step in the given list of steps.
Returns a tuple of five lists:
......@@ -434,7 +440,7 @@ class Step(object):
return (all_steps, steps_passed, steps_failed, steps_undefined, reasons_to_fail)
@classmethod
def many_from_lines(klass, lines, filename = None, original_string = None):
def many_from_lines(klass, lines, filename=None, original_string=None):
"""Parses a set of steps from lines of input.
This will correctly parse and produce a list of steps from lines without
......@@ -652,9 +658,8 @@ class Scenario(object):
steps_skipped = filter(skip, all_steps)
if outline:
call_hook(
'outline', 'scenario', self, order, outline, reasons_to_fail
)
call_hook('outline', 'scenario', self, order, outline,
reasons_to_fail)
return ScenarioResult(
self,
......@@ -662,8 +667,7 @@ class Scenario(object):
steps_failed,
steps_skipped,
steps_undefined,
True
)
True)
if self.outlines:
first = True
......@@ -757,14 +761,15 @@ class Scenario(object):
with_file=with_file,
original_string=original_string,
language=language,
tags=tags
)
tags=tags)
return scenario
class Feature(object):
""" Object that represents a feature."""
described_at = None
def __init__(self, name, remaining_lines, with_file, original_string,
language=None, tags=None):
......@@ -778,8 +783,7 @@ class Feature(object):
self.scenarios, self.description = self._parse_remaining_lines(
remaining_lines,
original_string,
with_file
)
with_file)
self.original_string = original_string
......@@ -841,17 +845,12 @@ class Feature(object):
found = len(re.findall(r'%s:[ ]*\w+' % language.feature, "\n".join(lines), re.U))
if found > 1:
raise LettuceSyntaxError(
with_file,
'A feature file must contain ONLY ONE feature!'
)
raise LettuceSyntaxError(with_file,
'A feature file must contain ONLY ONE feature!')
elif found == 0:
raise LettuceSyntaxError(
with_file,
'Features must have a name. e.g: "Feature: This is my name"'
)
raise LettuceSyntaxError(with_file,
'Features must have a name. e.g: "Feature: This is my name"')
while lines:
matched = re.search(r'%s:(.*)' % language.feature, lines[0], re.I)
......@@ -898,15 +897,12 @@ class Feature(object):
parts = strings.split_scenarios(lines, scenario_prefix)
scenario_strings = [
u"%s" % (s) for s in parts if s.strip()
]
scenario_strings = [u"%s" % (s) for s in parts if s.strip()]
kw = dict(
original_string=original_string,
with_file=with_file,
language=self.language,
tags=self.tags
)
tags=self.tags)
scenarios = [Scenario.from_string(s, **kw) for s in scenario_strings]
......@@ -932,6 +928,7 @@ class Feature(object):
call_hook('after_each', 'feature', self)
return FeatureResult(self, *scenarios_ran)
class FeatureResult(object):
"""Object that holds results of each scenario ran from within a feature"""
def __init__(self, feature, *scenario_results):
......@@ -942,6 +939,7 @@ class FeatureResult(object):
def passed(self):
return all([result.passed for result in self.scenario_results])
class ScenarioResult(object):
"""Object that holds results of each step ran from within a scenario"""
def __init__(self, scenario, steps_passed, steps_failed, steps_skipped,
......@@ -966,6 +964,7 @@ class ScenarioResult(object):
def failed(self):
return len(self.steps_failed) > 0
class TotalResult(object):
def __init__(self, feature_results):
self.feature_results = feature_results
......@@ -973,7 +972,7 @@ class TotalResult(object):
self.steps_passed = 0
self.steps_failed = 0
self.steps_skipped = 0
self.steps_undefined= 0
self.steps_undefined = 0
self._proposed_definitions = []
self.steps = 0
for feature_result in self.feature_results:
......@@ -986,7 +985,6 @@ class TotalResult(object):
self.steps += scenario_result.total_steps
self._proposed_definitions.extend(scenario_result.steps_undefined)
def _filter_proposed_definitions(self):
sentences = []
for step in self._proposed_definitions:
......
......@@ -18,6 +18,7 @@ import re
from lettuce.core import STEP_REGISTRY
from lettuce.exceptions import StepLoadingError
def step(regex):
"""Decorates a function, so that it will become a new step
definition.
......
......@@ -19,11 +19,13 @@ from os.path import join, dirname
from django.utils.importlib import import_module
from django.conf import settings
def _filter_bultins(module):
"returns only those apps that are not builtin django.contrib"
name = module.__name__
return not name.startswith("django.contrib") and name != 'lettuce.django'
def _filter_configured_apps(module):
"returns only those apps that are in django.conf.settings.LETTUCE_APPS"
app_found = True
......@@ -35,6 +37,7 @@ def _filter_configured_apps(module):
return app_found
def _filter_configured_avoids(module):
"returns apps that are not within django.conf.settings.LETTUCE_AVOID_APPS"
run_app = False
......@@ -45,9 +48,11 @@ def _filter_configured_avoids(module):
return not run_app
def get_apps():
return map(import_module, settings.INSTALLED_APPS)
def harvest_lettuces(only_the_apps=None, avoid_apps=None, path="features"):
"""gets all installed apps that are not from django.contrib
returns a list of tuples with (path_to_app, app_module)
......@@ -56,6 +61,7 @@ def harvest_lettuces(only_the_apps=None, avoid_apps=None, path="features"):
apps = get_apps()
if isinstance(only_the_apps, tuple) and any(only_the_apps):
def _filter_only_specified(module):
return module.__name__ in only_the_apps
apps = filter(_filter_only_specified, apps)
......@@ -65,6 +71,7 @@ def harvest_lettuces(only_the_apps=None, avoid_apps=None, path="features"):
apps = filter(_filter_configured_avoids, apps)
if isinstance(avoid_apps, tuple) and any(avoid_apps):
def _filter_avoid(module):
return module.__name__ not in avoid_apps
......
......@@ -28,6 +28,7 @@ from lettuce import registry
from lettuce.django import server
from lettuce.django import harvest_lettuces
class Command(BaseCommand):
help = u'Run lettuce tests all along installed apps'
args = '[PATH to feature file or folder]'
......@@ -59,6 +60,7 @@ class Command(BaseCommand):
make_option('--xunit-file', action='store', dest='xunit_file', default=None,
help='Write JUnit XML to this file. Defaults to lettucetests.xml'),
)
def stopserver(self, failed=False):
raise SystemExit(int(failed))
......@@ -71,7 +73,7 @@ class Command(BaseCommand):
else:
paths = args
else:
paths = harvest_lettuces(apps_to_run, apps_to_avoid) # list of tuples with (path, app_module)
paths = harvest_lettuces(apps_to_run, apps_to_avoid) # list of tuples with (path, app_module)
return paths
......
......@@ -128,18 +128,12 @@ class ThreadedServer(multiprocessing.Process):
self.lock.acquire()
def should_serve_static_files(self):
conditions = [
StaticFilesHandler is not None,
getattr(settings, 'STATIC_URL', False),
]
return all(conditions)
return (StaticFilesHandler is not None and
getattr(settings, 'STATIC_URL', False))
def should_serve_admin_media(self):
conditions = [
'django.contrib.admin' in settings.INSTALLED_APPS,
getattr(settings, 'LETTUCE_SERVE_ADMIN_MEDIA', False),
]
return any(conditions)
return ('django.contrib.admin' in settings.INSTALLED_APPS or
getattr(settings, 'LETTUCE_SERVE_ADMIN_MEDIA', False))
def run(self):
self.lock.acquire()
......
......@@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import traceback
class NoDefinitionFound(Exception):
""" Exception raised by lettuce.core.Step, when trying to solve a
Step, but does not find a suitable step definition.
......@@ -26,8 +27,8 @@ class NoDefinitionFound(Exception):
def __init__(self, step):
self.step = step
super(NoDefinitionFound, self).__init__(
'The step r"%s" is not defined' % self.step.sentence
)
'The step r"%s" is not defined' % self.step.sentence)
class ReasonToFail(object):
""" Exception that contains detailed information about a
......@@ -39,6 +40,7 @@ class ReasonToFail(object):
self.cause = unicode(exc)
self.traceback = traceback.format_exc(exc)
class LettuceSyntaxError(SyntaxError):
def __init__(self, filename, string):
self.filename = filename
......
......@@ -25,6 +25,7 @@ import zipfile
from glob import glob
from os.path import abspath, join, dirname, curdir, exists
class FeatureLoader(object):
"""Loader class responsible for findind features and step
definitions along a given path on filesystem"""
......@@ -47,13 +48,14 @@ class FeatureLoader(object):
else:
raise e
reload(module) # always take fresh meat :)
reload(module) # always take fresh meat :)
sys.path.remove(root)
def find_feature_files(self):
paths = FileSystem.locate(self.base_dir, "*.feature")
return paths
class FileSystem(object):
"""File system abstraction, mainly used for indirection, so that
lettuce can be well unit-tested :)
......@@ -229,4 +231,3 @@ class FileSystem(object):
path = cls.current_dir(name)
return open(path, mode)
......@@ -21,12 +21,12 @@ import optparse
import lettuce
def main(args=sys.argv[1:]):
base_path = os.path.join(os.path.dirname(os.curdir), 'features')
parser = optparse.OptionParser(
usage="%prog or type %prog -h (--help) for help",
version=lettuce.version
)
version=lettuce.version)
parser.add_option("-v", "--verbosity",
dest="verbosity",
......@@ -74,7 +74,7 @@ def main(args=sys.argv[1:]):
verbosity=options.verbosity,
enable_xunit=options.enable_xunit,
xunit_filename=options.xunit_file,
run_controller = run_controller)
run_controller=run_controller)
result = runner.run()
if not result or result.steps != result.steps_passed:
......
......@@ -17,8 +17,6 @@
import os
import re
import sys
import platform
import struct
from lettuce import core
from lettuce import strings
......@@ -27,12 +25,15 @@ from lettuce import terminal
from lettuce.terrain import after
from lettuce.terrain import before
def wrt(what):
sys.stdout.write(what.encode('utf-8'))
def wrap_file_and_line(string, start, end):
return re.sub(r'([#] [^:]+[:]\d+)', '%s\g<1>%s' % (start, end), string)
def wp(l):
if l.startswith("\033[1;32m"):
l = l.replace(" |", "\033[1;37m |\033[1;32m")
......@@ -47,9 +48,11 @@ def wp(l):
return l
def write_out(what):
wrt(wp(what))
@before.each_step
def print_step_running(step):
if not step.defined_at:
......@@ -67,6 +70,7 @@ def print_step_running(step):
for line in step.represent_hashes().splitlines():
write_out("\033[1;30m%s\033[0m\n" % line)
@after.each_step
def print_step_ran(step):
if step.scenario.outlines:
......@@ -80,7 +84,6 @@ def print_step_ran(step):
if not step.failed:
string = wrap_file_and_line(string, '\033[1;30m', '\033[0m')
prefix = '\033[A'
width, height = terminal.get_size()
lines_up = len(string) / float(width)
......@@ -123,12 +126,14 @@ def print_step_ran(step):
wrt("\033[0m\n")
@before.each_scenario
def print_scenario_running(scenario):
string = scenario.represented()
string = wrap_file_and_line(string, '\033[1;30m', '\033[0m')
write_out("\n\033[1;37m%s" % string)
@after.outline
def print_outline(scenario, order, outline, reasons_to_fail):
table = strings.dicts_to_string(scenario.outlines, scenario.keys)
......@@ -155,6 +160,7 @@ def print_outline(scenario, order, outline, reasons_to_fail):
wrt("\033[0m\n")
@before.each_feature
def print_feature_running(feature):
string = feature.represented()
......@@ -165,6 +171,7 @@ def print_feature_running(feature):
line = wrap_file_and_line(line, '\033[1;30m', '\033[0m')
write_out("\033[1;37m%s\n" % line)
@after.all
def print_end(total):
write_out("\n")
......@@ -179,9 +186,7 @@ def print_end(total):
total.features_ran,
word,
color,
total.features_passed
)
)
total.features_passed))
color = "\033[1;32m"
if total.scenarios_passed is 0:
......@@ -192,9 +197,7 @@ def print_end(total):
total.scenarios_ran,
word,
color,
total.scenarios_passed
)
)
total.scenarios_passed))
steps_details = []
kinds_and_colors = {
......@@ -203,14 +206,11 @@ def print_end(total):
'undefined': '\033[0;33m'
}
for kind, color in kinds_and_colors.items():
attr = 'steps_%s' % kind
stotal = getattr(total, attr)
if stotal:
steps_details.append(
"%s%d %s" % (color, stotal, kind)
)
steps_details.append("%s%d %s" % (color, stotal, kind))
steps_details.append("\033[1;32m%d passed\033[1;37m" % total.steps_passed)
word = total.steps > 1 and "steps" or "step"
......@@ -220,9 +220,7 @@ def print_end(total):
write_out("\033[1;37m%d %s (%s)\033[0m\n" % (
total.steps,
word,
content
)
)
content))
if total.proposed_definitions:
wrt("\n\033[0;33mYou can implement step definitions for undefined steps with these snippets:\n\n")
......@@ -240,6 +238,7 @@ def print_end(total):
wrt("\n")
def print_no_features_found(where):
where = core.fs.relpath(where)
if not where.startswith(os.sep):
......@@ -248,5 +247,4 @@ def print_no_features_found(where):
write_out('\033[1;31mOops!\033[0m\n')
write_out(
'\033[1;37mcould not find features at '
'\033[1;33m%s\033[0m\n' % where
)
'\033[1;33m%s\033[0m\n' % where)
......@@ -23,9 +23,11 @@ from lettuce.terrain import after
failed_scenarios = []
scenarios_and_its_fails = {}
def wrt(string):
sys.stdout.write(string)
@after.each_step
def print_scenario_ran(step):
if not step.failed:
......@@ -40,6 +42,7 @@ def print_scenario_ran(step):
else:
wrt("E")
@after.all
def print_end(total):
if total.scenarios_passed < total.scenarios_ran:
......@@ -54,35 +57,28 @@ def print_end(total):
wrt("%d %s (%d passed)\n" % (
total.features_ran,
word,
total.features_passed
)
)
total.features_passed))
word = total.scenarios_ran > 1 and "scenarios" or "scenario"
wrt("%d %s (%d passed)\n" % (
total.scenarios_ran,
word,
total.scenarios_passed
)
)
total.scenarios_passed))
steps_details = []
for kind in ("failed","skipped", "undefined"):
for kind in "failed", "skipped", "undefined":
attr = 'steps_%s' % kind
stotal = getattr(total, attr)
if stotal:
steps_details.append(
"%d %s" % (stotal, kind)
)
steps_details.append("%d %s" % (stotal, kind))
steps_details.append("%d passed" % total.steps_passed)
word = total.steps > 1 and "steps" or "step"
wrt("%d %s (%s)\n" % (
total.steps,
word,
", ".join(steps_details)
)
)
", ".join(steps_details)))
def print_no_features_found(where):
where = core.fs.relpath(where)
......@@ -90,7 +86,4 @@ def print_no_features_found(where):
where = '.%s%s' % (os.sep, where)
wrt('Oops!\n')
wrt(
'could not find features at '
'%s\n' % where
)
wrt('could not find features at %s\n' % where)
......@@ -20,24 +20,29 @@ from lettuce import core
from lettuce.terrain import after
from lettuce.terrain import before
@before.each_step
def print_step_running(step):
logging.info(step.represent_string(step.sentence))
@after.each_step
def print_step_ran(step):
logging.info("\033[A" + step.represent_string(step.sentence))
@before.each_scenario
def print_scenario_running(scenario):
logging.info(scenario.represented())
@before.each_feature
def print_feature_running(feature):
logging.info("\n")
logging.info(feature.represented())
logging.info("\n")
@after.all
def print_end(total):
logging.info("\n")
......@@ -45,25 +50,20 @@ def print_end(total):
logging.info("%d %s (%d passed)\n" % (
total.features_ran,
word,
total.features_passed
)
)
total.features_passed))
word = total.scenarios_ran > 1 and "scenarios" or "scenario"
logging.info("%d %s (%d passed)\n" % (
total.scenarios_ran,
word,
total.scenarios_passed
)
)
total.scenarios_passed))
word = total.steps > 1 and "steps" or "step"
logging.info("%d %s (%d passed)\n" % (
total.steps,
word,
total.steps_passed
)
)
total.steps_passed))
def print_no_features_found(where):
where = core.fs.relpath(where)
......@@ -73,6 +73,4 @@ def print_no_features_found(where):
logging.info('\033[1;31mOops!\033[0m\n')
logging.info(
'\033[1;37mcould not find features at '
'\033[1;33m%s\033[0m\n' % where
)
'\033[1;33m%s\033[0m\n' % where)
......@@ -24,13 +24,16 @@ from lettuce.terrain import before
failed_scenarios = []
scenarios_and_its_fails = {}
def wrt(string):
sys.stdout.write(string.encode('utf-8'))
@before.each_scenario
def print_scenario_running(scenario):
wrt('%s ... ' % scenario.name)
@after.each_scenario
def print_scenario_ran(scenario):
if scenario.passed:
......@@ -42,16 +45,18 @@ def print_scenario_ran(scenario):
else:
print "ERROR"
@after.each_step
def save_step_failed(step):
if step.failed and step.scenario not in failed_scenarios:
scenarios_and_its_fails[step.scenario] = step.why
failed_scenarios.append(step.scenario)
@after.all
def print_end(total):
if total.scenarios_passed < total.scenarios_ran:
print # just a line to separate things here
print # just a line to separate things here
for scenario in failed_scenarios:
reason = scenarios_and_its_fails[scenario]
wrt(reason.traceback)
......@@ -61,35 +66,25 @@ def print_end(total):
wrt("%d %s (%d passed)\n" % (
total.features_ran,
word,
total.features_passed
)
)
total.features_passed))
word = total.scenarios_ran > 1 and "scenarios" or "scenario"
wrt("%d %s (%d passed)\n" % (
total.scenarios_ran,
word,
total.scenarios_passed
)
)
total.scenarios_passed))
steps_details = []
for kind in ("failed","skipped", "undefined"):
for kind in "failed", "skipped", "undefined":
attr = 'steps_%s' % kind
stotal = getattr(total, attr)
if stotal:
steps_details.append(
"%d %s" % (stotal, kind)
)
steps_details.append("%d %s" % (stotal, kind))
steps_details.append("%d passed" % total.steps_passed)
word = total.steps > 1 and "steps" or "step"
wrt("%d %s (%s)\n" % (
total.steps,
word,
", ".join(steps_details)
)
)
wrt("%d %s (%s)\n" % (total.steps, word, ", ".join(steps_details)))
def print_no_features_found(where):
where = core.fs.relpath(where)
......@@ -97,7 +92,4 @@ def print_no_features_found(where):
where = '.%s%s' % (os.sep, where)
wrt('Oops!\n')
wrt(
'could not find features at '
'%s\n' % where
)
wrt('could not find features at %s\n' % where)
......@@ -22,9 +22,11 @@ from lettuce import strings
from lettuce.terrain import after
from lettuce.terrain import before
def wrt(what):
sys.stdout.write(what.encode('utf-8'))
@after.each_step
def print_step_running(step):
wrt(step.represent_string(step.original_sentence).rstrip())
......@@ -41,11 +43,13 @@ def print_step_running(step):
for line in step.why.traceback.splitlines():
print_spaced(line)
@before.each_scenario
def print_scenario_running(scenario):
wrt('\n')
wrt(scenario.represented())
@after.outline
def print_outline(scenario, order, outline, reasons_to_fail):
table = strings.dicts_to_string(scenario.outlines, scenario.keys)
......@@ -66,11 +70,13 @@ def print_outline(scenario, order, outline, reasons_to_fail):
for line in elines:
print_spaced(line)
@before.each_feature
def print_feature_running(feature):
wrt("\n")
wrt(feature.represented())
@after.all
def print_end(total):
wrt("\n")
......@@ -78,35 +84,27 @@ def print_end(total):
wrt("%d %s (%d passed)\n" % (
total.features_ran,
word,
total.features_passed
)
)
total.features_passed))
word = total.scenarios_ran > 1 and "scenarios" or "scenario"
wrt("%d %s (%d passed)\n" % (
total.scenarios_ran,
word,
total.scenarios_passed
)
)
total.scenarios_passed))
steps_details = []
for kind in ("failed", "skipped", "undefined"):
attr = 'steps_%s' % kind
stotal = getattr(total, attr)
if stotal:
steps_details.append(
"%d %s" % (stotal, kind)
)
steps_details.append("%d %s" % (stotal, kind))
steps_details.append("%d passed" % total.steps_passed)
word = total.steps > 1 and "steps" or "step"
wrt("%d %s (%s)\n" % (
total.steps,
word,
", ".join(steps_details)
)
)
", ".join(steps_details)))
if total.proposed_definitions:
wrt("\nYou can implement step definitions for undefined steps with these snippets:\n\n")
......@@ -118,14 +116,11 @@ def print_end(total):
wrt("def %s:\n" % method_name)
wrt(" assert False, 'This step must be implemented'\n")
def print_no_features_found(where):
where = core.fs.relpath(where)
if not where.startswith(os.sep):
where = '.%s%s' % (os.sep, where)
wrt('Oops!\n')
wrt(
'could not find features at '
'%s\n' % where
)
wrt('could not find features at %s\n' % where)
......@@ -15,7 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
from datetime import datetime
from lettuce.terrain import after
from lettuce.terrain import before
......@@ -27,9 +26,11 @@ def wrt_output(filename, content):
f.write(content.encode('utf-8'))
f.close()
def total_seconds(td):
return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 1e6) / 1e6
def enable(filename=None):
doc = minidom.Document()
......@@ -51,7 +52,7 @@ def enable(filename=None):
if step.failed:
cdata = doc.createCDATASection(step.why.traceback)
failure = doc.createElement("failure")
failure.setAttribute("message",step.why.cause)
failure.setAttribute("message", step.why.cause)
failure.appendChild(cdata)
tc.appendChild(failure)
......@@ -63,4 +64,3 @@ def enable(filename=None):
root.setAttribute("failed", str(total.steps_failed))
doc.appendChild(root)
wrt_output(output_filename, doc.toxml())
......@@ -17,9 +17,9 @@
import re
import time
import string
import unicodedata
def escape_if_necessary(what):
what = unicode(what)
if len(what) is 1:
......@@ -27,6 +27,7 @@ def escape_if_necessary(what):
return what
def get_stripped_lines(string, ignore_lines_starting_with=''):
string = unicode(string)
lines = [unicode(l.strip()) for l in string.splitlines()]
......@@ -39,12 +40,13 @@ def get_stripped_lines(string, ignore_lines_starting_with=''):
return lines
def split_wisely(string, sep, strip=False):
string = unicode(string)
if strip:
string=string.strip()
string = string.strip()
else:
string=string.strip("\n")
string = string.strip("\n")
sep = unicode(sep)
regex = re.compile(escape_if_necessary(sep), re.UNICODE | re.M | re.I)
......@@ -57,15 +59,18 @@ def split_wisely(string, sep, strip=False):
return [unicode(i) for i in items]
def wise_startswith(string, seed):
string = unicode(string).strip()
seed = unicode(seed)
regex = u"^%s" % re.escape(seed)
return bool(re.search(regex, string, re.I))
def remove_it(string, what):
return unicode(re.sub(unicode(what), "", unicode(string)).strip())
def column_width(string):
l = 0
for c in string:
......@@ -75,6 +80,7 @@ def column_width(string):
l += 1
return l
def rfill(string, times, char=u" ", append=u""):
string = unicode(string)
missing = times - column_width(string)
......@@ -83,13 +89,17 @@ def rfill(string, times, char=u" ", append=u""):
return unicode(string) + unicode(append)
def getlen(string):
return column_width(unicode(string)) + 1
def dicts_to_string(dicts, order):
escape = "#{%s}" % str(time.time())
def enline(line):
return unicode(line).replace("|", escape)
def deline(line):
return line.replace(escape, '\\|')
......@@ -120,12 +130,16 @@ def dicts_to_string(dicts, order):
return deline(u"\n".join(table) + u"\n")
def parse_hashes(lines):
escape = "#{%s}" % str(time.time())
def enline(line):
return unicode(line.replace("\\|", escape)).strip()
def deline(line):
return line.replace(escape, '|')
def discard_comments(lines):
return [line for line in lines if not line.startswith('#')]
......@@ -146,6 +160,7 @@ def parse_hashes(lines):
return keys, hashes
def parse_multiline(lines):
multilines = []
in_multiline = False
......@@ -163,11 +178,11 @@ def parse_multiline(lines):
def extract_tags_from_line(given_line):
"""returns tags_array if given_line contains tags, else None"""
line = string.rstrip(given_line)
line = given_line.rstrip()
tags = []
if re.match("\s*?\@", line):
tags = [tag for tag in re.split("\s*\@", line) if len(tag) > 0]
if len(tags) == 0 or [tag for tag in tags if string.find(tag, " ") != -1]:
if len(tags) == 0 or any(' ' in tag for tag in tags):
return None
return tags
......@@ -185,6 +200,7 @@ def consume_tags_lines(lines, tags):
else:
break
def consume_scenario(lines, scenario_prefix):
"""return string of scenario text
and reduce lines array by that much"""
......@@ -205,6 +221,7 @@ def consume_scenario(lines, scenario_prefix):
scenario_lines.extend(get_lines_till_next_scenario(lines, scenario_prefix))
return unicode("\n".join(scenario_lines))
def get_lines_till_next_scenario(lines, scenario_prefix):
"""returns array of lines up till next scenario block"""
sep = unicode(scenario_prefix)
......@@ -222,6 +239,7 @@ def get_lines_till_next_scenario(lines, scenario_prefix):
scenario_lines.append(lines.pop(0))
return scenario_lines
def split_scenarios(lines, scenario_prefix):
"""returns array of strings, one per scenario"""
scenario_strings = []
......
......@@ -18,6 +18,7 @@ import os
import platform
import struct
def get_size():
if platform.system() == "Windows":
size = get_terminal_size_win()
......@@ -29,6 +30,7 @@ def get_size():
return size
def get_terminal_size_win():
#Windows specific imports
from ctypes import windll, create_string_buffer
......@@ -41,20 +43,21 @@ def get_terminal_size_win():
res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
if res:
import struct
(bufx, bufy, curx, cury, wattr,
left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
(bufx, bufy, curx, cury, wattr, left, top, right, bottom,
maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
sizex = right - left + 1
sizey = bottom - top + 1
else:
sizex, sizey = 80, 25 # can't determine actual size - return default values
else: # can't determine actual size - return default values
sizex, sizey = 80, 25
return sizex, sizey
def get_terminal_size_unix():
# Unix/Posix specific imports
import fcntl, termios
import fcntl
import termios
def ioctl_GWINSZ(fd):
try:
cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment