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