Skip to content

Commit 0edacd7

Browse files
authored
Merge pull request #46 from nexB/45-more-readable-expressions
Make WITH expressions more readable #45
2 parents a6281c4 + 651c48d commit 0edacd7

File tree

90 files changed

+107
-116
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+107
-116
lines changed

azure-pipelines.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ jobs:
6262
python_version: '3.6'
6363
python_architecture: 'x86'
6464
py37:
65-
python_version: '3.7.4'
65+
python_version: '3.7'
6666
python_architecture: 'x86'
6767

6868
- template: etc/ci/azure-win.yml

configure

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
# change these variables to customize this script locally
77
################################
88
# you can define one or more thirdparty dirs, each prefixed with TPP_DIR
9-
export TPP_DIR_BASE="thirdparty/base"
10-
export TPP_DIR_DEV="thirdparty/dev"
11-
export TPP_DIR_PROD="thirdparty/prod"
9+
export TPP_DIR_BASE="thirdparty"
1210

1311
# default configurations for dev
1412
CONF_DEFAULT="etc/conf/dev"

configure.bat

Lines changed: 54 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,54 @@
1-
@echo ON
2-
setlocal
3-
@rem Copyright (c) nexB Inc. http://www.nexb.com/ - All rights reserved.
4-
5-
@rem ################################
6-
@rem # Defaults. change these variables to customize this script locally
7-
@rem ################################
8-
@rem # you can define one or more thirdparty dirs, each prefixed with TPP_DIR
9-
set TPP_DIR_BASE=thirdparty/base
10-
set TPP_DIR_DEV=thirdparty/dev
11-
set TPP_DIR_PROD=thirdparty/prod
12-
13-
set DEFAULT_PYTHON=python
14-
15-
@rem # default configurations
16-
set CONF_DEFAULT="etc/conf/dev"
17-
@rem #################################
18-
19-
@rem this always has a trailing backslash
20-
set CFG_ROOT_DIR=%~dp0
21-
22-
@rem a possible alternative way and simpler way to slurp args
23-
@rem set CFG_CMD_LINE_ARGS=%*
24-
25-
@rem Collect all command line arguments in a variable
26-
set CFG_CMD_LINE_ARGS=
27-
28-
:collectarg
29-
if ""%1""=="""" goto continue
30-
set CFG_CMD_LINE_ARGS=%CFG_CMD_LINE_ARGS% %1
31-
shift
32-
goto collectarg
33-
34-
:continue
35-
36-
37-
@rem Set defaults
38-
if "%CFG_CMD_LINE_ARGS%"=="" set CFG_CMD_LINE_ARGS=%CONF_DEFAULT%
39-
if "%PYTHON_EXE%"=="" set PYTHON_EXE=%DEFAULT_PYTHON%
40-
41-
42-
call "%PYTHON_EXE%" %CFG_ROOT_DIR%\etc\configure.py %CFG_CMD_LINE_ARGS%
43-
44-
45-
@rem Return a proper return code on failure
46-
if %errorlevel% neq 0 (
47-
exit /b %errorlevel%
48-
)
49-
50-
51-
@rem Activate the virtualenv
52-
endlocal
53-
if exist "%CFG_ROOT_DIR%bin\activate" (
54-
"%CFG_ROOT_DIR%bin\activate"
55-
)
56-
goto EOS
57-
58-
:EOS
1+
@echo OFF
2+
setlocal
3+
@rem Copyright (c) nexB Inc. http://www.nexb.com/ - All rights reserved.
4+
5+
@rem ################################
6+
@rem # Defaults. change these variables to customize this script locally
7+
@rem ################################
8+
@rem # you can define one or more thirdparty dirs, each prefixed with TPP_DIR
9+
set TPP_DIR=thirdparty
10+
11+
set DEFAULT_PYTHON=python
12+
13+
@rem # default configurations for dev
14+
set CONF_DEFAULT="etc/conf/dev"
15+
@rem #################################
16+
17+
set CFG_ROOT_DIR=%~dp0
18+
19+
@rem Collect all command line arguments in a variable
20+
set CFG_CMD_LINE_ARGS=
21+
22+
@rem a possible alternative way and simpler way to slurp args
23+
@rem set CFG_CMD_LINE_ARGS=%*
24+
25+
26+
:collectarg
27+
if ""%1""=="""" goto continue
28+
call set CFG_CMD_LINE_ARGS=%CFG_CMD_LINE_ARGS% %1
29+
shift
30+
goto collectarg
31+
32+
:continue
33+
34+
@rem Set defaults when no args are passed
35+
if "%CFG_CMD_LINE_ARGS%"=="" set CFG_CMD_LINE_ARGS="%CONF_DEFAULT%"
36+
if "%PYTHON_EXE%"=="" set PYTHON_EXE=%DEFAULT_PYTHON%
37+
38+
39+
call "%PYTHON_EXE%" "%CFG_ROOT_DIR%etc\configure.py" %CFG_CMD_LINE_ARGS%
40+
@rem Return a proper return code on failure
41+
42+
if %errorlevel% neq 0 (
43+
exit /b %errorlevel%
44+
)
45+
46+
47+
@rem Activate the virtualenv
48+
endlocal
49+
if exist "%CFG_ROOT_DIR%bin\activate" (
50+
"%CFG_ROOT_DIR%bin\activate"
51+
)
52+
goto EOS
53+
54+
:EOS

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
setup(
1919
name='license-expression',
20-
version='1.1',
20+
version='1.2',
2121
license='apache-2.0',
2222
description=desc,
2323
long_description=desc,

src/license_expression/__init__.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ class ExpressionParseError(ParseError, ExpressionError):
128128
# mapping of lowercase operator strings to an operator object
129129
OPERATORS = {'and': KW_AND, 'or': KW_OR, 'with': KW_WITH}
130130

131-
_simple_tokenizer = re.compile('''
131+
_simple_tokenizer = re.compile(r'''
132132
(?P<symop>[^\s\(\)]+)
133133
|
134134
(?P<space>\s+)
@@ -827,6 +827,19 @@ def render(self, template='{symbol.key}', *args, **kwargs):
827827
"""
828828
return NotImplementedError
829829

830+
def render_as_readable(self, template='{symbol.key}', *args, **kwargs):
831+
"""
832+
Return a formatted string rendering for this expression using the
833+
`template` format string to render each symbol. Add extra parenthesis
834+
around WITH sub-expressions for improved readbility. See `render()` for
835+
other arguments.
836+
"""
837+
if isinstance(self, LicenseWithExceptionSymbol):
838+
return self.render(
839+
template=template, wrap_with_in_parens=False, *args, **kwargs)
840+
else:
841+
return self.render(template=template, wrap_with_in_parens=True, *args, **kwargs)
842+
830843

831844
class BaseSymbol(Renderable, boolean.Symbol):
832845
"""
@@ -1075,10 +1088,19 @@ def decompose(self):
10751088
yield self.license_symbol
10761089
yield self.exception_symbol
10771090

1078-
def render(self, template='{symbol.key}', *args, **kwargs):
1091+
def render(self, template='{symbol.key}', wrap_with_in_parens=False, *args, **kwargs):
1092+
"""
1093+
Return a formatted WITH expression. If `wrap_with_in_parens`, wrap in
1094+
parens a WITH expression, unless it is alone and not used with other AND
1095+
or OR sub-expressions.
1096+
"""
10791097
lic = self.license_symbol.render(template, *args, **kwargs)
10801098
exc = self.exception_symbol.render(template, *args, **kwargs)
1081-
return '%(lic)s WITH %(exc)s' % locals()
1099+
if wrap_with_in_parens:
1100+
temp = '(%(lic)s WITH %(exc)s)'
1101+
else:
1102+
temp = '%(lic)s WITH %(exc)s'
1103+
return temp % locals()
10821104

10831105
def __hash__(self, *args, **kwargs):
10841106
return hash((self.license_symbol, self.exception_symbol,))

src/license_expression/_pyahocorasick.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ def overlap(self, other):
608608

609609

610610
# tokenize to separate text from parens
611-
_tokenizer = re.compile('''
611+
_tokenizer = re.compile(r'''
612612
(?P<text>[^\s\(\)]+)
613613
|
614614
(?P<space>\s+)

tests/test_license_expression.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,30 @@ def test_primary_license_symbol_and_primary_license_key(self):
16651665
assert expected == licensing.primary_license_symbol(
16661666
parsed, decompose=False).render('{symbol.key}')
16671667

1668+
def test_render_plain(self):
1669+
l = Licensing()
1670+
result = l.parse('gpl-2.0 WITH exception-gpl-2.0-plus or MIT').render()
1671+
expected = 'gpl-2.0 WITH exception-gpl-2.0-plus OR MIT'
1672+
assert expected == result
1673+
1674+
def test_render_as_readable_does_not_wrap_in_parens_single_with(self):
1675+
l = Licensing()
1676+
result = l.parse('gpl-2.0 WITH exception-gpl-2.0-plus').render_as_readable()
1677+
expected = 'gpl-2.0 WITH exception-gpl-2.0-plus'
1678+
assert expected == result
1679+
1680+
def test_render_as_readable_wraps_in_parens_with_and_other_subexpressions(self):
1681+
l = Licensing()
1682+
result = l.parse('mit AND gpl-2.0 WITH exception-gpl-2.0-plus').render_as_readable()
1683+
expected = 'mit AND (gpl-2.0 WITH exception-gpl-2.0-plus)'
1684+
assert expected == result
1685+
1686+
def test_render_as_readable_does_not_wrap_in_parens_if_no_with(self):
1687+
l = Licensing()
1688+
result1 = l.parse('gpl-2.0 and exception OR that').render_as_readable()
1689+
result2 = l.parse('gpl-2.0 and exception OR that').render()
1690+
assert result1 == result2
1691+
16681692

16691693
class SplitAndTokenizeTest(TestCase):
16701694

File renamed without changes.

0 commit comments

Comments
 (0)