Skip to content

Commit 5ca2f7b

Browse files
committed
New distribution [0.1.2]
* updated bash completion * updated README * fixed lambda conversion * fixed line seperator guessing * added universal unique UUID 4 generator * added some more test cases (need reporting issues to `parso`)
1 parent 3a4ff72 commit 5ca2f7b

6 files changed

Lines changed: 122 additions & 65 deletions

File tree

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,21 @@ Raises:
161161

162162
- `ConvertError `-- when `parso.ParserSyntaxError` raised
163163

164-
#### `ConvertError` -- `walrus` internal exception
164+
#### Internal exceptions
165165

166166
```python
167167
class ConvertError(SyntaxError):
168-
pass
168+
"""Parso syntax error."""
169+
```
170+
171+
```python
172+
class ContextError(RuntimeError):
173+
"""Missing conversion context."""
174+
```
175+
176+
```python
177+
class EnvironError(EnvironmentError):
178+
"""Invalid environment."""
169179
```
170180

171181
## Test

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
long_desc = file.read()
1616

1717
# version string
18-
__version__ = '0.1.1'
18+
__version__ = '0.1.2'
1919

2020
# set-up script for pip distribution
2121
setup(
@@ -49,7 +49,7 @@
4949
],
5050
},
5151
classifiers=[
52-
'Development Status :: 1 - Planning',
52+
'Development Status :: 4 - Beta',
5353
# 'Development Status :: 5 - Production/Stable',
5454
'Intended Audience :: Developers',
5555
'License :: OSI Approved :: MIT License',

share/walrus.1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.\" Man page generated from reStructuredText.
22
.
3-
.TH WALRUS 1 "November 26, 2019" "v0.1.1" ""
3+
.TH WALRUS 1 "November 27, 2019" "v0.1.2" ""
44
.SH NAME
55
walrus \- back-port compiler for Python 3.8 assignment expression
66
.

share/walrus.bash-completion

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ _walrus() {
4343
cur="${COMP_WORDS[COMP_CWORD]}"
4444
prev="${COMP_WORDS[COMP_CWORD-1]}"
4545
opts="--help --version --no-archive --dismiss --no-linting"
46-
cmds="--archive-path --encoding --python --linesep"
46+
cmds="--archive-path --encoding --python --linesep --tabsize"
4747

4848
if [[ ${prev} =~ "--help|--version|--no-archive" ]]
4949
then
5050
__walrus_comp_null
5151
return
52-
elif [[ ${prev} =~ "--archive-path|--encoding|--linesep" ]]
52+
elif [[ ${prev} =~ "--archive-path|--encoding|--linesep|--tabsize" ]]
5353
then
5454
__walrus_comp_null
5555
return

share/walrus.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ walrus
66
back-port compiler for Python 3.8 assignment expression
77
-------------------------------------------------------
88

9-
:Version: v0.1.1
9+
:Version: v0.1.2
1010
:Date: November 27, 2019
1111
:Manual section: 1
1212
:Author:

walrus.py

Lines changed: 104 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# -*- coding: utf-8 -*-
2+
"""Back-port compiler for Python 3.8 assignment expressions."""
23

34
import argparse
45
import glob
6+
import io
57
import locale
68
import os
79
import re
@@ -31,7 +33,7 @@
3133
del multiprocessing
3234

3335
# version string
34-
__version__ = '0.1.1'
36+
__version__ = '0.1.2'
3537

3638
# from configparser
3739
BOOLEAN_STATES = {'1': True, '0': False,
@@ -132,7 +134,7 @@ def __walrus_wrapper_%(name)s_%(uuid)s(expr):
132134
'''.splitlines() # `str.splitlines` will remove trailing newline
133135

134136
# special template for lambda
135-
LAMBDA_CALL_TEMPLATE = '__walrus_wrapper_lambda_%(uuid)s(%(param)s)'
137+
LAMBDA_CALL_TEMPLATE = '__walrus_wrapper_lambda_%(uuid)s'
136138
LAMBDA_FUNC_TEMPLATE = '''\
137139
def __walrus_wrapper_lambda_%(uuid)s(%(param)s):
138140
%(tabsize)s"""Wrapper function for lambda definitions."""
@@ -332,12 +334,13 @@ def _process(self, node):
332334
# leaf node
333335
self += node.get_code()
334336

335-
def _process_suite_node(self, node, func=False, cls_ctx=None):
337+
def _process_suite_node(self, node, func=False, raw=False, cls_ctx=None):
336338
"""Process indented suite (`suite` or ...).
337339
338340
Args:
339341
- `node` -- `Union[parso.python.tree.PythonNode, parso.python.tree.PythonLeaf]`, suite node
340342
- `func` -- `bool`, if the suite is of function definition
343+
- `raw` -- `bool`, raw processing flag
341344
- `cls_ctx` -- `Optional[str]`, class name when suite if of class contextion
342345
343346
"""
@@ -357,15 +360,20 @@ def _process_suite_node(self, node, func=False, cls_ctx=None):
357360
if cls_ctx is None:
358361
ctx = Context(node=node, context=self._context,
359362
column=indent, tabsize=self._tabsize,
360-
linesep=self._linesep, keyword=keyword)
363+
linesep=self._linesep, keyword=keyword, raw=raw)
361364
else:
362365
ctx = ClassContext(cls_ctx=cls_ctx,
363366
node=node, context=self._context,
364367
column=indent, tabsize=self._tabsize,
365-
linesep=self._linesep, keyword=keyword)
368+
linesep=self._linesep, keyword=keyword, raw=raw)
369+
self += ctx.string.lstrip()
366370

371+
# keep records
372+
if raw:
373+
self._lamb.extend(ctx.lambdef)
374+
self._vars.extend(ctx.variables)
375+
self._func.extend(ctx.functions)
367376
self._context.extend(ctx.global_stmt)
368-
self += ctx.string.lstrip()
369377

370378
def _process_namedexpr_test(self, node):
371379
"""Process assignment expression (`namedexpr_test`).
@@ -529,11 +537,32 @@ def _process_lambdef(self, node):
529537
self += node.get_code()
530538
return
531539

532-
ctx = LambdaContext(node=node, column=self._column,
533-
tabsize=self._tabsize, linesep=self._linesep,
534-
keyword=self._keyword, context=self._context)
535-
self._lamb.extend(ctx.lambdef)
536-
self += ctx.string.lstrip()
540+
children = iter(node.children)
541+
542+
# <Keyword: lambda>
543+
next(children)
544+
545+
# vararglist
546+
para_list = list()
547+
for child in children:
548+
if child.type == 'operator' and child.value == ':':
549+
break
550+
para_list.append(child)
551+
param = ''.join(map(lambda n: n.get_code(), para_list))
552+
553+
# test_nocond | test
554+
indent = self._column + self._tabsize
555+
ctx = LambdaContext(node=next(children), context=self._context,
556+
column=indent, tabsize=self._tabsize,
557+
linesep=self._linesep, keyword='nonlocal')
558+
suite = ctx.string.strip()
559+
560+
# keep record
561+
nuid = uuid_gen.gen()
562+
self._lamb.append(dict(param=param, suite=suite, uuid=nuid))
563+
564+
# replacing lambda
565+
self += LAMBDA_CALL_TEMPLATE % dict(uuid=nuid)
537566

538567
def _process_if_stmt(self, node):
539568
"""Process if statement (``if_stmt``).
@@ -723,7 +752,7 @@ def _concat(self):
723752

724753
# first, the prefix codes
725754
self._buffer += self._prefix + prefix
726-
if flag and self._linting and self._vars and self._buffer:
755+
if flag and self._linting and self._buffer:
727756
if (self._node_before_walrus is not None \
728757
and self._node_before_walrus.type in ('funcdef', 'classdef') \
729758
and self._column == 0):
@@ -746,26 +775,27 @@ def _concat(self):
746775
'%s%s' % (self._linesep, indent)
747776
).join(NAME_TEMPLATE) % dict(tabsize=tabsize, name_list=name_list) + self._linesep
748777
for func in sorted(self._func, key=lambda func: func['name']):
749-
self._buffer += linesep + indent + (
778+
if self._buffer:
779+
self._buffer += linesep
780+
self._buffer += indent + (
750781
'%s%s' % (self._linesep, indent)
751782
).join(FUNC_TEMPLATE) % dict(tabsize=tabsize, **func) + self._linesep
752783
for lamb in self._lamb:
753-
self._buffer += linesep + indent + (
784+
if self._buffer:
785+
self._buffer += linesep
786+
self._buffer += indent + (
754787
'%s%s' % (self._linesep, indent)
755788
).join(LAMBDA_FUNC_TEMPLATE) % dict(tabsize=tabsize, **lamb) + self._linesep
756789

757790
# finally, the suffix codes
758-
if flag and self._linting and self._vars:
791+
if flag and self._linting:
759792
blank = 2 if self._column == 0 else 1
760793
self._buffer += self._linesep * self.missing_whitespaces(prefix=self._buffer, suffix=suffix,
761794
blank=blank, linesep=self._linesep)
762795
self._buffer += suffix
763796

764797
def _strip(self):
765-
"""Strip comments from string.
766-
767-
Args:
768-
- `string` -- `str`, buffer string
798+
"""Strip comments from suffix buffer.
769799
770800
Returns:
771801
- `str` -- prefix comments
@@ -775,7 +805,7 @@ def _strip(self):
775805
prefix = ''
776806
suffix = ''
777807

778-
lines = iter(self._suffix.splitlines(True))
808+
lines = io.StringIO(self._suffix, newline=self._linesep)
779809
for line in lines:
780810
if line.strip().startswith('#'):
781811
prefix += line
@@ -979,40 +1009,46 @@ def extract_whitespaces(node):
9791009

9801010

9811011
class LambdaContext(Context):
982-
"""Lambda (lambdef) conversion context."""
983-
984-
def _process_lambdef(self, node):
985-
"""Process lambda definition (``lambdef``).
986-
987-
Args:
988-
- `node` -- `parso.python.tree.Lambda`, lambda node
989-
990-
"""
991-
children = iter(node.children)
992-
993-
# <Keyword: lambda>
994-
next(children)
1012+
"""Lambda (suite) conversion context."""
9951013

996-
# vararglist
997-
para_list = list()
998-
for child in children:
999-
if child.type == 'operator' and child.value == ':':
1000-
break
1001-
para_list.append(child)
1002-
param = ''.join(map(lambda n: n.get_code(), para_list))
1014+
def _concat(self):
1015+
"""Concatenate final string."""
1016+
flag = self.has_walrus(self._root)
10031017

1004-
# test_nocond | test
1005-
# test_node = parso.python.tree.ExprStmt([parso.python.tree.Name('lambdef', (0, 0)),
1006-
# parso.python.tree.Operator('=', (0, 0)),
1007-
# next(children)])
1008-
# suite = self._process_suite_node(next(children), func=True, buffer=True)
1018+
# first, the variables and functions
1019+
indent = '\t'.expandtabs(self._column)
1020+
tabsize = '\t'.expandtabs(self._tabsize)
1021+
if self._linting:
1022+
linesep = self._linesep * (1 if self._column > 0 else 2)
1023+
else:
1024+
linesep = ''
1025+
if self._vars:
1026+
name_list = ' = '.join(sorted(set(self._vars)))
1027+
self._buffer += indent + (
1028+
'%s%s' % (self._linesep, indent)
1029+
).join(NAME_TEMPLATE) % dict(tabsize=tabsize, name_list=name_list) + self._linesep
1030+
for func in sorted(self._func, key=lambda func: func['name']):
1031+
if self._buffer:
1032+
self._buffer += linesep
1033+
self._buffer += indent + (
1034+
'%s%s' % (self._linesep, indent)
1035+
).join(FUNC_TEMPLATE) % dict(tabsize=tabsize, **func) + self._linesep
1036+
for lamb in self._lamb:
1037+
if self._buffer:
1038+
self._buffer += linesep
1039+
self._buffer += indent + (
1040+
'%s%s' % (self._linesep, indent)
1041+
).join(LAMBDA_FUNC_TEMPLATE) % dict(tabsize=tabsize, **lamb) + self._linesep
1042+
if flag and self._linting:
1043+
blank = 2 if self._column == 0 else 1
1044+
self._buffer += self._linesep * self.missing_whitespaces(prefix=self._buffer, suffix=self._prefix,
1045+
blank=blank, linesep=self._linesep)
10091046

1010-
# keep record
1011-
nuid = uuid_gen.gen()
1012-
# self._lamb.append(dict(param=param, suite=suite, uuid=nuid))
1047+
# then, the `return` statement
1048+
self._buffer += indent + 'return'
10131049

1014-
# replacing lambda
1015-
self += LAMBDA_CALL_TEMPLATE % dict(param=param, uuid=nuid)
1050+
# finally, the source codes
1051+
self._buffer += self._prefix + self._suffix
10161052

10171053

10181054
class ClassContext(Context):
@@ -1022,22 +1058,23 @@ class ClassContext(Context):
10221058
def cls_var(self):
10231059
return self._cls_var
10241060

1025-
def __init__(self, cls_ctx, node,
1061+
def __init__(self, node,
1062+
cls_ctx, cls_var=None,
10261063
column=0, tabsize=None,
10271064
linesep=None, keyword=None,
1028-
context=None, raw=False, cls_var=None):
1065+
context=None, raw=False):
10291066
"""Conversion context.
10301067
10311068
Args:
1032-
- `cls_ctx` -- `str`, class context name
10331069
- `node` -- `Union[parso.python.tree.PythonNode, parso.python.tree.PythonLeaf]`, parso AST
1070+
- `cls_ctx` -- `str`, class context name
1071+
- `cls_var` -- `Dict[str, str]`, mapping for assignment variable and its UUID
10341072
- `column` -- `int`, current indentation level
10351073
- `tabsize` -- `Optional[int]`, indentation tab size
10361074
- `linesep` -- `Optional[str]`, line seperator
10371075
- `keyword` -- `Optional[str]`, keyword for wrapper function
10381076
- `context` -- `Optional[List[str]]`, global context
10391077
- `raw` -- `bool`, raw context processing flag
1040-
- `cls_var` -- `Dict[str, str]`, mapping for assignment variable and its UUID
10411078
10421079
Envs:
10431080
- `WALRUS_LINESEP` -- line separator to process source files (same as `--linesep` option in CLI)
@@ -1056,12 +1093,13 @@ def __init__(self, cls_ctx, node,
10561093
column=column, tabsize=tabsize,
10571094
linesep=linesep, keyword=keyword, raw=raw)
10581095

1059-
def _process_suite_node(self, node, func=False, cls_ctx=None):
1096+
def _process_suite_node(self, node, func=False, raw=False, cls_ctx=None):
10601097
"""Process indented suite (`suite` or ...).
10611098
10621099
Args:
10631100
- `node` -- `Union[parso.python.tree.PythonNode, parso.python.tree.PythonLeaf]`, suite node
10641101
- `func` -- `bool`, if the suite is of function definition
1102+
- `raw` -- `bool`, raw context processing flag
10651103
- `cls_ctx` -- `Optional[str]`, class name when suite if of class contextion
10661104
10671105
"""
@@ -1091,8 +1129,14 @@ def _process_suite_node(self, node, func=False, cls_ctx=None):
10911129
node=node, context=self._context,
10921130
column=indent, tabsize=self._tabsize,
10931131
linesep=self._linesep, keyword=keyword)
1094-
10951132
self += ctx.string.lstrip()
1133+
1134+
# keep record
1135+
if raw:
1136+
self._lamb.extend(ctx.lambdef)
1137+
self._vars.extend(ctx.variables)
1138+
self._func.extend(ctx.functions)
1139+
self._cls_var.update(ctx.cls_var)
10961140
self._context.extend(ctx.global_stmt)
10971141

10981142
def _process_namedexpr_test(self, node):
@@ -1113,6 +1157,7 @@ def _process_namedexpr_test(self, node):
11131157
column=self._column, tabsize=self._tabsize,
11141158
linesep=self._linesep, keyword=self._keyword, raw=True)
11151159
expr = ctx.string.strip()
1160+
self._lamb.extend(ctx.lambdef)
11161161
self._vars.extend(ctx.variables)
11171162
self._func.extend(ctx.functions)
11181163
self._cls_var.update(ctx.cls_var)
@@ -1214,7 +1259,9 @@ def _concat(self):
12141259
'%s%s' % (self._linesep, indent)
12151260
).join(CLS_NAME_TEMPLATE) % dict(tabsize=tabsize, cls=self._cls_ctx) + linesep
12161261
for func in sorted(self._func, key=lambda func: func['name']):
1217-
self._buffer += linesep + indent + (
1262+
if self._buffer:
1263+
self._buffer += linesep
1264+
self._buffer += indent + (
12181265
'%s%s' % (self._linesep, indent)
12191266
).join(CLS_FUNC_TEMPLATE) % dict(tabsize=tabsize, cls=self._cls_ctx, **func) + linesep
12201267

0 commit comments

Comments
 (0)