From 032cfa1a8c4e54dead87bae11f956e1cb6881794 Mon Sep 17 00:00:00 2001 From: Adi Roiban Date: Sun, 16 Feb 2014 15:54:00 +0200 Subject: [PATCH 1/6] Initial code for parsing from stream. --- .gitignore | 1 + lesscpy/lessc/lexer.py | 12 +++++++---- lesscpy/lessc/parser.py | 10 +++++++-- test/test_lexer.py | 47 +++++++++++++++++++++++++++++++++++++++++ test/test_parser.py | 31 +++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 test/test_lexer.py create mode 100644 test/test_parser.py diff --git a/.gitignore b/.gitignore index 46e49c8..6194089 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ dist MANIFEST .tox .venv* +*.egg-info/ diff --git a/lesscpy/lessc/lexer.py b/lesscpy/lessc/lexer.py index a333d94..2defdee 100644 --- a/lesscpy/lessc/lexer.py +++ b/lesscpy/lessc/lexer.py @@ -460,12 +460,16 @@ class LessLexer: self.lexer.input(f.read()) return self - def input(self, filename): + def input(self, file): """ - Wrapper for file + Load lexer with content from `file` which can be a path or a file + like object. """ - with open(filename) as f: - self.lexer.input(f.read()) + if isinstance(file, basestring): + with open(file) as f: + self.lexer.input(f.read()) + else: + self.lexer.input(file.read()) def token(self): """ diff --git a/lesscpy/lessc/parser.py b/lesscpy/lessc/parser.py index 153feff..84e65c2 100644 --- a/lesscpy/lessc/parser.py +++ b/lesscpy/lessc/parser.py @@ -77,7 +77,7 @@ class LessParser(object): self.result = None self.target = None - def parse(self, filename='', debuglevel=0): + def parse(self, filename='', filestream=None, debuglevel=0): """ Parse file. kwargs: filename (str): File to parse @@ -87,8 +87,14 @@ class LessParser(object): print('Compiling target: %s' % filename, file=sys.stderr) self.scope.push() self.target = filename + if filestream: + content = filestream + else: + content = filename + self.result = self.parser.parse( - filename, lexer=self.lex, debug=debuglevel) + content, lexer=self.lex, debug=debuglevel) + self.post_parse() def post_parse(self): diff --git a/test/test_lexer.py b/test/test_lexer.py new file mode 100644 index 0000000..d001202 --- /dev/null +++ b/test/test_lexer.py @@ -0,0 +1,47 @@ +""" +Unit tests for the lexer. +""" +from StringIO import StringIO +from tempfile import NamedTemporaryFile +import unittest + + +from lesscpy.lessc.lexer import LessLexer + + +class TestLessLexer(unittest.TestCase): + """ + Unit tests for LessLexer + """ + + def setUp(self): + self.lexer = LessLexer() + + + def test_input_stream(self): + """ + It can load content from a string. + """ + file = StringIO(""" + @simple-var: 1; + """) + + self.lexer.input(file) + + token = self.lexer.token() + self.assertEqual('@simple-var', token.value) + + def test_input_path(self): + """ + It can load content from a path. + """ + file = NamedTemporaryFile() + file.write(""" + @simple-var: 1; + """) + file.seek(0) + + self.lexer.input(file.name) + + token = self.lexer.token() + self.assertEqual('@simple-var', token.value) diff --git a/test/test_parser.py b/test/test_parser.py new file mode 100644 index 0000000..256ce2a --- /dev/null +++ b/test/test_parser.py @@ -0,0 +1,31 @@ +""" +Unit test for the parser. +""" +from StringIO import StringIO +import unittest + +from lesscpy.lessc.parser import LessParser + +class TestLessParser(unittest.TestCase): + """ + Unit tests for LessParser. + """ + + def setUp(self): + self.parser = LessParser() + + def test_parse_stream(self): + """ + It can parse input from a file stream. + """ + stream = StringIO(""" + @nice-blue: #5B83AD; + """) + + self.parser.parse(filestream=stream) + + # A single object is parser which is the expected variable. + self.assertEqual(1, len(self.parser.result)) + variable = self.parser.result[0] + self.assertEqual('@nice-blue', variable.name) + self.assertEqual(['#5b83ad'], variable.value) From 5a763750d42916609a6a4716558c673da1786ed5 Mon Sep 17 00:00:00 2001 From: Adi Roiban Date: Sun, 16 Feb 2014 17:48:07 +0200 Subject: [PATCH 2/6] Add support for py3. --- lesscpy/lessc/lexer.py | 3 ++- requirements.txt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lesscpy/lessc/lexer.py b/lesscpy/lessc/lexer.py index 2defdee..97b574e 100644 --- a/lesscpy/lessc/lexer.py +++ b/lesscpy/lessc/lexer.py @@ -11,6 +11,7 @@ """ import re import ply.lex as lex +from six import string_types from lesscpy.lib import dom from lesscpy.lib import css @@ -465,7 +466,7 @@ class LessLexer: Load lexer with content from `file` which can be a path or a file like object. """ - if isinstance(file, basestring): + if isinstance(file, string_types): with open(file) as f: self.lexer.input(f.read()) else: diff --git a/requirements.txt b/requirements.txt index 90412f0..4efa1dc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ ply +six From a329d2befd9588efeeca0d49d5ef5e7bc0d28cfd Mon Sep 17 00:00:00 2001 From: Adi Roiban Date: Sun, 16 Feb 2014 17:57:29 +0200 Subject: [PATCH 3/6] Update py3. --- test/test_lexer.py | 2 +- test/test_parser.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/test_lexer.py b/test/test_lexer.py index d001202..ff2f803 100644 --- a/test/test_lexer.py +++ b/test/test_lexer.py @@ -1,10 +1,10 @@ """ Unit tests for the lexer. """ -from StringIO import StringIO from tempfile import NamedTemporaryFile import unittest +from six import StringIO from lesscpy.lessc.lexer import LessLexer diff --git a/test/test_parser.py b/test/test_parser.py index 256ce2a..6653c3c 100644 --- a/test/test_parser.py +++ b/test/test_parser.py @@ -1,11 +1,13 @@ """ Unit test for the parser. """ -from StringIO import StringIO import unittest +from six import StringIO + from lesscpy.lessc.parser import LessParser + class TestLessParser(unittest.TestCase): """ Unit tests for LessParser. From 31b6dffd9369bfb547a7c7bf76b40738a74b9fcf Mon Sep 17 00:00:00 2001 From: Adi Roiban Date: Sun, 16 Feb 2014 18:03:31 +0200 Subject: [PATCH 4/6] Fix py3 string. --- test/test_lexer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_lexer.py b/test/test_lexer.py index ff2f803..a784806 100644 --- a/test/test_lexer.py +++ b/test/test_lexer.py @@ -22,7 +22,7 @@ class TestLessLexer(unittest.TestCase): """ It can load content from a string. """ - file = StringIO(""" + file = StringIO(b""" @simple-var: 1; """) @@ -36,7 +36,7 @@ class TestLessLexer(unittest.TestCase): It can load content from a path. """ file = NamedTemporaryFile() - file.write(""" + file.write(b""" @simple-var: 1; """) file.seek(0) From f11e9e6ece6331fc8dce9448e094edd640a19ded Mon Sep 17 00:00:00 2001 From: Adi Roiban Date: Sun, 16 Feb 2014 18:06:04 +0200 Subject: [PATCH 5/6] Fix py3. --- test/test_lexer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_lexer.py b/test/test_lexer.py index a784806..60b573b 100644 --- a/test/test_lexer.py +++ b/test/test_lexer.py @@ -22,7 +22,7 @@ class TestLessLexer(unittest.TestCase): """ It can load content from a string. """ - file = StringIO(b""" + file = StringIO(""" @simple-var: 1; """) From e82ca278c4d2c532ca85bf7c3a1760986254ca4c Mon Sep 17 00:00:00 2001 From: Adi Roiban Date: Tue, 18 Feb 2014 11:24:00 +0200 Subject: [PATCH 6/6] Update after review. --- .gitignore | 1 - lesscpy/lessc/parser.py | 27 ++++++++++++++++++--------- test/test_parser.py | 4 +++- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 6194089..46e49c8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,3 @@ dist MANIFEST .tox .venv* -*.egg-info/ diff --git a/lesscpy/lessc/parser.py b/lesscpy/lessc/parser.py index 84e65c2..32014c3 100644 --- a/lesscpy/lessc/parser.py +++ b/lesscpy/lessc/parser.py @@ -77,23 +77,32 @@ class LessParser(object): self.result = None self.target = None - def parse(self, filename='', filestream=None, debuglevel=0): + def parse(self, filename=None, file=None, debuglevel=0): """ Parse file. kwargs: filename (str): File to parse debuglevel (int): Parser debuglevel """ + self.scope.push() + + if not file: + # We use a path. + file = filename + else: + # We use a stream and try to extract the name from the stream. + if hasattr(file, 'name'): + if filename is not None: + raise AssertionError( + 'names of file and filename are in conflict') + filename = file.name() + else: + filename = '(stream)' + + self.target = filename if self.verbose: print('Compiling target: %s' % filename, file=sys.stderr) - self.scope.push() - self.target = filename - if filestream: - content = filestream - else: - content = filename - self.result = self.parser.parse( - content, lexer=self.lex, debug=debuglevel) + file, lexer=self.lex, debug=debuglevel) self.post_parse() diff --git a/test/test_parser.py b/test/test_parser.py index 6653c3c..7a23605 100644 --- a/test/test_parser.py +++ b/test/test_parser.py @@ -24,10 +24,12 @@ class TestLessParser(unittest.TestCase): @nice-blue: #5B83AD; """) - self.parser.parse(filestream=stream) + self.parser.parse(file=stream) # A single object is parser which is the expected variable. self.assertEqual(1, len(self.parser.result)) + # This is a stream without a name so it sets default name. + self.assertEqual('(stream)', self.parser.target) variable = self.parser.result[0] self.assertEqual('@nice-blue', variable.name) self.assertEqual(['#5b83ad'], variable.value)