1# bootstrapping setuptools
2import ez_setup
3ez_setup.use_setuptools()
4
5import os
6import sys
7import textwrap
8from distutils.errors import *
9from distutils.command.clean import clean as _clean
10from distutils.cmd import Command
11from setuptools import setup
12from distutils import log
13
14from distutils.core import setup
15
16
17class clean(_clean):
18    """Also cleanup local temp files."""
19
20    def run(self):
21        _clean.run(self)
22
23        import fnmatch
24
25        # kill temporary files
26        patterns = [
27            # generic tempfiles
28            '*~', '*.bak', '*.pyc',
29
30            # tempfiles generated by ANTLR runs
31            't[0-9]*Lexer.py', 't[0-9]*Parser.py',
32            '*.tokens', '*__.g',
33            ]
34
35        for path in ('antlr3', 'unittests', 'tests'):
36            path = os.path.join(os.path.dirname(__file__), path)
37            if os.path.isdir(path):
38                for root, dirs, files in os.walk(path, topdown=True):
39                    graveyard = []
40                    for pat in patterns:
41                        graveyard.extend(fnmatch.filter(files, pat))
42
43                    for name in graveyard:
44                        filePath = os.path.join(root, name)
45
46                        try:
47                            log.info("removing '%s'", filePath)
48                            os.unlink(filePath)
49                        except OSError, exc:
50                            log.warn(
51                                "Failed to delete '%s': %s",
52                                filePath, exc
53                                )
54
55
56class TestError(DistutilsError):
57    pass
58
59
60# grml.. the class name appears in the --help output:
61# ...
62# Options for 'CmdUnitTest' command
63# ...
64# so I have to use a rather ugly name...
65class unittest(Command):
66    """Run unit tests for package"""
67
68    description = "run unit tests for package"
69
70    user_options = [
71        ('xml-output=', None,
72         "Directory for JUnit compatible XML files."),
73        ]
74    boolean_options = []
75
76    def initialize_options(self):
77        self.xml_output = None
78
79    def finalize_options(self):
80        pass
81
82    def run(self):
83        testDir = os.path.join(os.path.dirname(__file__), 'unittests')
84        if not os.path.isdir(testDir):
85            raise DistutilsFileError(
86                "There is not 'unittests' directory. Did you fetch the "
87                "development version?",
88                )
89
90        import glob
91        import imp
92        import unittest
93        import traceback
94        import StringIO
95
96        suite = unittest.TestSuite()
97        loadFailures = []
98
99        # collect tests from all unittests/test*.py files
100        testFiles = []
101        for testPath in glob.glob(os.path.join(testDir, 'test*.py')):
102            testFiles.append(testPath)
103
104        testFiles.sort()
105        for testPath in testFiles:
106            testID = os.path.basename(testPath)[:-3]
107
108            try:
109                modFile, modPathname, modDescription \
110                         = imp.find_module(testID, [testDir])
111
112                testMod = imp.load_module(
113                    testID, modFile, modPathname, modDescription
114                    )
115
116                suite.addTests(
117                    unittest.defaultTestLoader.loadTestsFromModule(testMod)
118                    )
119
120            except Exception:
121                buf = StringIO.StringIO()
122                traceback.print_exc(file=buf)
123
124                loadFailures.append(
125                    (os.path.basename(testPath), buf.getvalue())
126                    )
127
128        if self.xml_output:
129            import xmlrunner
130            runner = xmlrunner.XMLTestRunner(
131                stream=open(os.path.join(self.xml_output, 'unittest.xml'), 'w'))
132        else:
133            runner = unittest.TextTestRunner(verbosity=2)
134        result = runner.run(suite)
135
136        for testName, error in loadFailures:
137            sys.stderr.write('\n' + '='*70 + '\n')
138            sys.stderr.write(
139                "Failed to load test module %s\n" % testName
140                )
141            sys.stderr.write(error)
142            sys.stderr.write('\n')
143
144        if not result.wasSuccessful() or loadFailures:
145            raise TestError(
146                "Unit test suite failed!",
147                )
148
149
150class functest(Command):
151    """Run functional tests for package"""
152
153    description = "run functional tests for package"
154
155    user_options = [
156        ('testcase=', None,
157         "testcase to run [default: run all]"),
158        ('antlr-version=', None,
159         "ANTLR version to use [default: HEAD (in ../../build)]"),
160        ('antlr-jar=', None,
161         "Explicit path to an antlr jar (overrides --antlr-version)"),
162        ('xml-output=', None,
163         "Directory for JUnit compatible XML files."),
164        ]
165
166    boolean_options = []
167
168    def initialize_options(self):
169        self.testcase = None
170        self.antlr_version = 'HEAD'
171        self.antlr_jar = None
172        self.xml_output = None
173
174    def finalize_options(self):
175        pass
176
177    def run(self):
178        import glob
179        import imp
180        import unittest
181        import traceback
182        import StringIO
183
184        testDir = os.path.join(os.path.dirname(__file__), 'tests')
185        if not os.path.isdir(testDir):
186            raise DistutilsFileError(
187                "There is not 'tests' directory. Did you fetch the "
188                "development version?",
189                )
190
191        # make sure, relative imports from testcases work
192        sys.path.insert(0, testDir)
193
194        rootDir = os.path.abspath(
195            os.path.join(os.path.dirname(__file__), '..', '..'))
196
197        if self.antlr_jar is not None:
198            classpath = [self.antlr_jar]
199        elif self.antlr_version == 'HEAD':
200            classpath = [
201                os.path.join(rootDir, 'tool', 'target', 'classes'),
202                os.path.join(rootDir, 'runtime', 'Java', 'target', 'classes')
203                ]
204        else:
205            classpath = [
206                os.path.join(rootDir, 'archive',
207                             'antlr-%s.jar' % self.antlr_version)
208                ]
209
210        classpath.extend([
211            os.path.join(rootDir, 'lib', 'antlr-2.7.7.jar'),
212            os.path.join(rootDir, 'lib', 'stringtemplate-3.2.1.jar'),
213            os.path.join(rootDir, 'lib', 'ST-4.0.2.jar'),
214            os.path.join(rootDir, 'lib', 'junit-4.2.jar')
215            ])
216        os.environ['CLASSPATH'] = ':'.join(classpath)
217
218        os.environ['ANTLRVERSION'] = self.antlr_version
219
220        suite = unittest.TestSuite()
221        loadFailures = []
222
223        # collect tests from all tests/t*.py files
224        testFiles = []
225        test_glob = 't[0-9][0-9][0-9]*.py'
226        for testPath in glob.glob(os.path.join(testDir, test_glob)):
227            if testPath.endswith('Lexer.py') or testPath.endswith('Parser.py'):
228                continue
229
230            # if a single testcase has been selected, filter out all other
231            # tests
232            if (self.testcase is not None
233                and not os.path.basename(testPath)[:-3].startswith(self.testcase)):
234                continue
235
236            testFiles.append(testPath)
237
238        testFiles.sort()
239        for testPath in testFiles:
240            testID = os.path.basename(testPath)[:-3]
241
242            try:
243                modFile, modPathname, modDescription \
244                         = imp.find_module(testID, [testDir])
245
246                testMod = imp.load_module(
247                    testID, modFile, modPathname, modDescription)
248
249                suite.addTests(
250                    unittest.defaultTestLoader.loadTestsFromModule(testMod))
251
252            except Exception:
253                buf = StringIO.StringIO()
254                traceback.print_exc(file=buf)
255
256                loadFailures.append(
257                    (os.path.basename(testPath), buf.getvalue()))
258
259        if self.xml_output:
260            import xmlrunner
261            runner = xmlrunner.XMLTestRunner(
262                stream=open(os.path.join(self.xml_output, 'functest.xml'), 'w'))
263        else:
264            runner = unittest.TextTestRunner(verbosity=2)
265
266        result = runner.run(suite)
267
268        for testName, error in loadFailures:
269            sys.stderr.write('\n' + '='*70 + '\n')
270            sys.stderr.write(
271                "Failed to load test module %s\n" % testName
272                )
273            sys.stderr.write(error)
274            sys.stderr.write('\n')
275
276        if not result.wasSuccessful() or loadFailures:
277            raise TestError(
278                "Functional test suite failed!",
279                )
280
281
282setup(name='antlr_python_runtime',
283      version='3.4',
284      packages=['antlr3'],
285
286      author="Benjamin Niemann",
287      author_email="pink@odahoda.de",
288      url="http://www.antlr.org/",
289      download_url="http://www.antlr.org/download.html",
290      license="BSD",
291      description="Runtime package for ANTLR3",
292      long_description=textwrap.dedent('''\
293      This is the runtime package for ANTLR3, which is required to use parsers
294      generated by ANTLR3.
295      '''),
296      cmdclass={'unittest': unittest,
297                'functest': functest,
298                'clean': clean
299                },
300      )
301