diff --git a/.gitignore b/.gitignore
index 795f9cf9d..5fe57bc66 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,8 @@
./tests/functional/2nd_feature_dir/step_definitions/__init__.py
docs/_build/
docs/_build
-lettuce.egg-info/
+*.egg
+*.egg-info/
build/
dist/
.DS_Store
diff --git a/MANIFEST.in b/MANIFEST.in
index db7fbffad..11bae0fb7 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1 +1,2 @@
include COPYING *.md
+include requirements.txt
\ No newline at end of file
diff --git a/lettuce/__init__.py b/lettuce/__init__.py
index 7f658ff13..d878c2b8e 100644
--- a/lettuce/__init__.py
+++ b/lettuce/__init__.py
@@ -65,7 +65,7 @@
try:
terrain = fs.FileSystem._import("terrain")
reload(terrain)
-except Exception, e:
+except Exception as e:
if not "No module named terrain" in str(e):
string = 'Lettuce has tried to load the conventional environment ' \
'module "terrain"\nbut it has errors, check its contents and ' \
@@ -129,8 +129,8 @@ def run(self):
started_at = datetime.now()
try:
self.loader.find_and_load_step_definitions()
- except StepLoadingError, e:
- print "Error loading step definitions:\n", e
+ except StepLoadingError as e:
+ print("Error loading step definitions:\n", e)
return
call_hook('before', 'all')
@@ -154,12 +154,12 @@ def run(self):
results.append(
feature.run(self.scenarios, tags=self.tags, random=self.random))
- except exceptions.LettuceSyntaxError, e:
+ except exceptions.LettuceSyntaxError as e:
sys.stderr.write(e.msg)
failed = True
except:
e = sys.exc_info()[1]
- print "Died with %s" % str(e)
+ print("Died with %s" % str(e))
traceback.print_exc()
failed = True
@@ -178,10 +178,10 @@ def run(self):
minutes = time_took.seconds / 60
seconds = time_took.seconds
if hours:
- print "(finished within %d hours)" % hours
+ print ("(finished within %d hours)" % hours)
elif minutes:
- print "(finished within %d minutes)" % minutes
+ print("(finished within %d minutes)" % minutes)
elif seconds:
- print "(finished within %d seconds)" % seconds
+ print("(finished within %d seconds)" % seconds)
return total
diff --git a/lettuce/core.py b/lettuce/core.py
index 90fe91f64..fdca2fe8f 100644
--- a/lettuce/core.py
+++ b/lettuce/core.py
@@ -14,7 +14,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-
+from __future__ import unicode_literals
import re
import codecs
@@ -39,16 +39,16 @@
class REP(object):
"RegEx Pattern"
- first_of = re.compile(ur'^first_of_')
- last_of = re.compile(ur'^last_of_')
+ first_of = re.compile(r'^first_of_')
+ last_of = re.compile(r'^last_of_')
language = re.compile(u"language:[ ]*([^\s]+)")
within_double_quotes = re.compile(r'("[^"]+")')
within_single_quotes = re.compile(r"('[^']+')")
only_whitespace = re.compile('^\s*$')
tag_extraction_regex = re.compile(r'(?:(?:^|\s+)[@]([^@\s]+))')
- tag_strip_regex = re.compile(ur'(?:(?:^\s*|\s+)[@]\S+\s*)+$', re.DOTALL)
- comment_strip1 = re.compile(ur'(^[^\'"]*)[#]([^\'"]*)$')
- comment_strip2 = re.compile(ur'(^[^\'"]+)[#](.*)$')
+ tag_strip_regex = re.compile(r'(?:(?:^\s*|\s+)[@]\S+\s*)+$', re.DOTALL)
+ comment_strip1 = re.compile(r'(^[^\'"]*)[#]([^\'"]*)$')
+ comment_strip2 = re.compile(r'(^[^\'"]+)[#](.*)$')
class HashList(list):
@@ -142,7 +142,7 @@ def __call__(self, *args, **kw):
try:
ret = self.function(self.step, *args, **kw)
self.step.passed = True
- except Exception, e:
+ except Exception as e:
self.step.failed = True
self.step.why = ReasonToFail(self.step, e)
raise
@@ -456,10 +456,10 @@ def run_all(steps, outline=None, run_callbacks=False, ignore_case=True):
step.run(ignore_case)
steps_passed.append(step)
- except NoDefinitionFound, e:
+ except NoDefinitionFound as e:
steps_undefined.append(e.step)
- except Exception, e:
+ except Exception as e:
steps_failed.append(step)
reasons_to_fail.append(step.why)
@@ -728,7 +728,7 @@ def _add_myself_to_steps(self):
step.scenario = self
def _find_tags_in(self, original_string):
- broad_regex = re.compile(ur"([@].*)%s: (%s)" % (
+ broad_regex = re.compile(r"([@].*)%s: (%s)" % (
self.language.scenario_separator,
self.name), re.DOTALL)
@@ -737,7 +737,7 @@ def _find_tags_in(self, original_string):
regexes.append(broad_regex)
else:
- regexes.append(re.compile(ur"(?:%s: %s.*)([@]?.*)%s: (%s)\s*\n" % (
+ regexes.append(re.compile(r"(?:%s: %s.*)([@]?.*)%s: (%s)\s*\n" % (
self.language.non_capturable_scenario_separator,
self.previous_scenario.name,
self.language.scenario_separator,
@@ -885,8 +885,8 @@ def run(self, ignore_case):
call_hook('before_each', 'step', step)
try:
results.append(step.run(ignore_case))
- except Exception, e:
- print e
+ except Exception as e:
+ print(e)
pass
call_hook('after_each', 'step', step)
@@ -1089,7 +1089,7 @@ def _parse_remaining_lines(self, lines, original_string, with_file=None):
# replacing occurrences of Scenario Outline, with just "Scenario"
scenario_prefix = u'%s:' % self.language.first_of_scenario
regex = re.compile(
- ur"%s:[\t\r\f\v]*" % self.language.scenario_separator, re.U | re.I | re.DOTALL)
+ r"%s:[\t\r\f\v]*" % self.language.scenario_separator, re.U | re.I | re.DOTALL)
joined = regex.sub(scenario_prefix, joined)
diff --git a/lettuce/decorators.py b/lettuce/decorators.py
index f2f72f836..09a193d9c 100644
--- a/lettuce/decorators.py
+++ b/lettuce/decorators.py
@@ -39,7 +39,7 @@ def step(regex):
def wrap(func):
try:
re.compile(regex)
- except re.error, e:
+ except re.error as e:
raise StepLoadingError("Error when trying to compile:\n"
" regex: %r\n"
" for function: %s\n"
diff --git a/lettuce/django/management/commands/harvest.py b/lettuce/django/management/commands/harvest.py
index d8c8b6561..a2b1308d5 100644
--- a/lettuce/django/management/commands/harvest.py
+++ b/lettuce/django/management/commands/harvest.py
@@ -107,7 +107,7 @@ def handle(self, *args, **options):
if run_server:
try:
server.start()
- except LettuceServerException, e:
+ except LettuceServerException as e:
raise SystemExit(e)
os.environ['SERVER_NAME'] = server.address
@@ -138,10 +138,10 @@ def handle(self, *args, **options):
results.append(result)
if not result or result.steps != result.steps_passed:
failed = True
- except SystemExit, e:
+ except SystemExit as e:
failed = e.code
- except Exception, e:
+ except Exception as e:
failed = True
import traceback
traceback.print_exc(e)
diff --git a/lettuce/django/server.py b/lettuce/django/server.py
index cd694b64c..1e98870c7 100644
--- a/lettuce/django/server.py
+++ b/lettuce/django/server.py
@@ -227,7 +227,7 @@ def start(self):
if getattr(settings, 'LETTUCE_SERVE_ADMIN_MEDIA', False):
msg += ' (as per settings.LETTUCE_SERVE_ADMIN_MEDIA=True)'
- print "%s..." % msg
+ print("%s..." % msg)
self._actual_server.start()
self._actual_server.wait()
@@ -242,7 +242,7 @@ def start(self):
'python manage.py --no-server' % addrport,
)
- print "Django's builtin server is running at %s:%d" % addrport
+ print("Django's builtin server is running at %s:%d" % addrport)
def stop(self, fail=False):
pid = self._actual_server.pid
diff --git a/lettuce/fs.py b/lettuce/fs.py
index 4032d21c6..04f1cbe61 100644
--- a/lettuce/fs.py
+++ b/lettuce/fs.py
@@ -40,7 +40,7 @@ def find_and_load_step_definitions(self):
to_load = FileSystem.filename(filename, with_extension=False)
try:
module = __import__(to_load)
- except ValueError, e:
+ except ValueError as e:
import traceback
err_msg = traceback.format_exc(e)
if 'empty module name' in err_msg.lower():
@@ -136,7 +136,7 @@ def mkdir(cls, path):
"""
try:
os.makedirs(path)
- except OSError, e:
+ except OSError as e:
# ignore if path already exists
if e.errno not in (17, ):
raise e
diff --git a/lettuce/registry.py b/lettuce/registry.py
index 1266a7911..262bf7d6d 100644
--- a/lettuce/registry.py
+++ b/lettuce/registry.py
@@ -86,10 +86,10 @@ def call_hook(situation, kind, *args, **kw):
for callback in CALLBACK_REGISTRY[kind][situation]:
try:
callback(*args, **kw)
- except Exception, e:
- print "=" * 1000
+ except Exception as e:
+ print("=" * 1000)
traceback.print_exc(e)
- print
+ print()
raise
diff --git a/requirements.txt b/requirements.txt
index 09f37f822..ddb916d75 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,13 +4,13 @@ Pygments==1.5
Sphinx==1.1.3
coverage==3.5.2
cssselect==0.7.1
-distribute==0.6.27
+distribute==0.6.31
docutils==0.9.1
fuzzywuzzy==0.1
lxml
mock==1.0b1
mox==0.5.3
nose==1.1.2
-sure==1.0.6
+sure==1.1.7
tornado==2.3
tox==1.4.2
diff --git a/setup.py b/setup.py
index a339511ba..9a650a8e1 100755
--- a/setup.py
+++ b/setup.py
@@ -22,7 +22,7 @@
def get_packages():
# setuptools can't do the job :(
- packages = []
+ packages = ['']
for root, dirnames, filenames in os.walk('lettuce'):
if '__init__.py' in filenames:
packages.append(".".join(os.path.split(root)).strip("."))
@@ -37,6 +37,13 @@ def get_packages():
if os.name.lower() == 'nt':
required_modules.append('colorama')
+import os
+test_reqs = os.path.join(os.getcwd(), 'requirements.txt')
+tests_require = [
+ line.strip() for line in open(test_reqs).readlines()
+ if not line.startswith("#")
+ ]
+
setup(
name='lettuce',
version='0.2.12',
@@ -46,6 +53,7 @@ def get_packages():
url='http://lettuce.it',
packages=get_packages(),
install_requires=required_modules,
+ tests_require=tests_require,
entry_points={
'console_scripts': ['lettuce = lettuce.bin:main'],
},
diff --git a/tests/functional/test_terrain.py b/tests/functional/test_terrain.py
index 664458dd5..d951b0ead 100644
--- a/tests/functional/test_terrain.py
+++ b/tests/functional/test_terrain.py
@@ -16,17 +16,23 @@
# along with this program. If not, see .
import os
import commands
+import sys
from os.path import dirname, abspath, join, curdir
from nose.tools import assert_equals, with_setup
from tests.asserts import prepare_stdout
+PY3 = sys.version_info[0] == 3
+
+
def test_imports_terrain_under_path_that_is_run():
old_path = abspath(curdir)
os.chdir(join(abspath(dirname(__file__)), 'simple_features', '1st_feature_dir'))
- status, output = commands.getstatusoutput('python -c "from lettuce import world;assert hasattr(world, \'works_fine\'); print \'it passed!\'"')
+
+ py_command = 'python3' if PY3 else 'python2'
+ status, output = commands.getstatusoutput('{} -c "from lettuce import world;assert hasattr(world, \'works_fine\'); print \'it passed!\'"'.format(py_command))
assert_equals(status, 0)
assert_equals(output, "it passed!")
diff --git a/tests/unit/test_feature_parser.py b/tests/unit/test_feature_parser.py
index aeb1daf62..7420d32bc 100644
--- a/tests/unit/test_feature_parser.py
+++ b/tests/unit/test_feature_parser.py
@@ -14,7 +14,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-from sure import that, expect
+from sure import expect
from lettuce import step
from lettuce.core import Scenario
from lettuce.core import Feature
@@ -559,7 +559,7 @@ def test_single_scenario_single_scenario():
first_scenario = feature.scenarios[0]
- assert that(first_scenario.tags).deep_equals([
+ expect(first_scenario.tags).should.equal([
'many', 'other', 'basic', 'tags', 'here', ':)'])
@@ -580,21 +580,21 @@ def inspected_within_object(step):
@step(r'fill my email with [\'"]?([^\'"]+)[\'"]?')
def fill_email(step, email):
- assert that(email).equals('gabriel@lettuce.it')
+ assert expect(email).equals('gabriel@lettuce.it')
feature = Feature.from_string(FEATURE13)
first_scenario = feature.scenarios[0]
- assert that(first_scenario.tags).equals(['runme'])
+ assert expect(first_scenario.tags).equals(['runme'])
second_scenario = feature.scenarios[1]
- assert that(second_scenario.tags).equals([])
+ assert expect(second_scenario.tags).equals([])
third_scenario = feature.scenarios[2]
- assert that(third_scenario.tags).equals(['slow'])
+ assert expect(third_scenario.tags).equals(['slow'])
last_scenario = feature.scenarios[3]
- assert that(last_scenario.tags).equals([])
+ assert expect(last_scenario.tags).equals([])
result = feature.run()
print
diff --git a/tox.ini b/tox.ini
index e6be1d84c..20268d6f3 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,9 +4,9 @@
# and then run "tox" from this directory.
[tox]
-envlist = py26, py27
+envlist = py26, py27, py33
[testenv]
commands =
- pip install --use-mirrors -q -r requirements.txt
+ python setup.py test
make unit functional