Skip to content

Commit 3cc2d29

Browse files
committed
Remove support for Python 2.7
1 parent 5ac86c1 commit 3cc2d29

File tree

14 files changed

+81
-674
lines changed

14 files changed

+81
-674
lines changed

.github/workflows/ci.yml

Lines changed: 54 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,80 +2,98 @@ name: CI
22

33
on:
44
push:
5-
branches: [ master ]
5+
branches: [ main ]
66
pull_request:
7-
branches: [ master ]
7+
branches: [ main ]
88

99

1010
jobs:
11-
build:
11+
12+
lint:
13+
name: Linting
14+
runs-on: ubuntu-latest
15+
strategy:
16+
fail-fast: false
17+
steps:
18+
- uses: actions/checkout@v4
19+
- name: Set up Python
20+
uses: actions/setup-python@v5
21+
with:
22+
python-version: 3.12
23+
- name: Set up Node
24+
uses: actions/setup-node@v4
25+
with:
26+
node-version: '18'
27+
- name: Install dependencies
28+
run: |
29+
python -m pip install --upgrade pip
30+
pip install ruff
31+
- name: Ruff lint
32+
run: |
33+
ruff check --output-format=github .
34+
- name: Ruff format
35+
run: |
36+
ruff format --check .
37+
38+
docs:
39+
name: Docs
40+
runs-on: ubuntu-latest
41+
strategy:
42+
fail-fast: false
43+
steps:
44+
- uses: actions/checkout@v4
45+
- name: Set up Python
46+
uses: actions/setup-python@v5
47+
with:
48+
python-version: 3.13
49+
- name: Install dev dependencies
50+
run: |
51+
python -m pip install --upgrade pip
52+
#pip install -U -e .[docs]
53+
pip install sphinx
54+
- name: Build docs
55+
run: |
56+
cd docs
57+
make html SPHINXOPTS="-W --keep-going"
58+
59+
tests:
1260
name: ${{ matrix.name }}
1361
runs-on: ${{ matrix.os }}
1462
strategy:
1563
matrix:
1664
include:
17-
- name: Lint
18-
os: ubuntu-latest
19-
pyversion: '3.7'
20-
dolint: 1
2165
- name: Linux py36
2266
os: ubuntu-latest
2367
pyversion: '3.6'
24-
tests: 1
2568
- name: Linux py37
2669
os: ubuntu-latest
2770
pyversion: '3.7'
28-
tests: 1
2971
- name: Linux py38
3072
os: ubuntu-latest
3173
pyversion: '3.8'
32-
tests: 1
3374
- name: Linux py39
3475
os: ubuntu-latest
3576
pyversion: '3.9'
36-
tests: 1
3777
- name: Linux pypy3
3878
os: ubuntu-latest
3979
pyversion: 'pypy3'
40-
tests: 1
4180
- name: Windows py38
4281
os: windows-latest
4382
pyversion: '3.8'
44-
tests: 1
4583
- name: MacOS py38
4684
os: macos-latest
4785
pyversion: '3.8'
48-
tests: 1
4986

5087
steps:
51-
- uses: actions/checkout@v2
88+
- uses: actions/checkout@v4
5289
- name: Set up Python ${{ matrix.pyversion }}
53-
uses: actions/setup-python@v2
90+
uses: actions/setup-python@v5
5491
with:
5592
python-version: ${{ matrix.pyversion }}
56-
- uses: actions/setup-node@v2
57-
if: matrix.dolint == 1
58-
with:
59-
node-version: '14'
60-
- name: Install dependencies (lint and docs)
61-
if: matrix.dolint == 1
62-
run: |
63-
python -m pip install --upgrade pip
64-
pip install invoke pycodestyle flake8 sphinx
65-
- name: Install dependencies (unit tests)
66-
if: matrix.tests == 1
93+
- name: Install dependencies for unit tests
6794
run: |
6895
python -m pip install --upgrade pip
6996
pip install invoke pytest pytest-cov
70-
- name: Lint
71-
if: matrix.dolint == 1
72-
run: |
73-
invoke test --style
74-
- name: Build docs
75-
if: matrix.dolint == 1
76-
run: |
77-
invoke docs --clean --build
7897
- name: Test with pytest
79-
if: matrix.tests == 1
8098
run: |
8199
invoke test --unit

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
See https://github.com/flexxui/flexx/blob/master/CONTRIBUTING.md
1+
See https://github.com/flexxui/flexx/blob/main/CONTRIBUTING.md

pscript/__init__.py

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -246,16 +246,6 @@
246246
import sys
247247
import logging
248248

249-
logger = logging.getLogger(__name__)
250-
251-
# Assert compatibility and redirect to legacy version on Python 2.7
252-
ok = True
253-
if sys.version_info[0] == 2: # pragma: no cover
254-
if sys.version_info < (2, 7):
255-
raise RuntimeError('PScript needs at least Python 2.7')
256-
if type(b'') == type(''): # noqa - will be str and unicode after conversion
257-
sys.modules[__name__] = __import__(__name__ + '_legacy')
258-
ok = False
259249

260250
# NOTE: The code for the parser is quite long, especially if you want
261251
# to document it well. Therefore it is split in multiple modules, which
@@ -267,20 +257,19 @@
267257
# demonstrating the features defined in that module. In the docs these
268258
# docstrings are combined into one complete guide.
269259

270-
# flake8: noqa
271260

272-
if ok:
261+
from .parser0 import Parser0, JSError
262+
from .parser1 import Parser1
263+
from .parser2 import Parser2
264+
from .parser3 import Parser3
265+
from .base import *
273266

274-
from .parser0 import Parser0, JSError
275-
from .parser1 import Parser1
276-
from .parser2 import Parser2
277-
from .parser3 import Parser3
278-
from .base import *
267+
from .functions import py2js, evaljs, evalpy, JSString
268+
from .functions import script2js, js_rename, create_js_module
269+
from .stdlib import get_full_std_lib, get_all_std_names
270+
from .stubs import RawJS, JSConstant, window, undefined
279271

280-
from .functions import py2js, evaljs, evalpy, JSString
281-
from .functions import script2js, js_rename, create_js_module
282-
from .stdlib import get_full_std_lib, get_all_std_names
283-
from .stubs import RawJS, JSConstant, window, undefined
284272

273+
logger = logging.getLogger(__name__)
285274

286-
del logging, sys, ok
275+
del logging, sys

pscript/functions.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,6 @@ def evaljs(jscode, whitespace=True, print_result=True, extra_nodejs_args=None):
279279
filename = None
280280
p_or_e = ['-p', '-e'] if print_result else ['-e']
281281
cmd += ['--use_strict'] + p_or_e + [jscode]
282-
if sys.version_info[0] < 3:
283-
cmd = [c.encode('raw_unicode_escape') for c in cmd]
284282

285283
# Call node
286284
try:

pscript/parser0.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,6 @@ class Parser0:
152152
'True' : 'true',
153153
'False' : 'false',
154154
'None' : 'null',
155-
'unicode': 'str', # legacy Py compat
156155
'unichr': 'chr',
157156
'xrange': 'range',
158157
'self': 'this',
@@ -208,12 +207,7 @@ def __init__(self, code, pysource=None, indent=0, docstrings=True,
208207
self._pysource = str(pysource[0]), int(pysource[1])
209208
elif pysource is not None:
210209
logger.warning('Parser ignores pysource; it must be str or (str, int).')
211-
if sys.version_info[0] == 2:
212-
fut = 'from __future__ import unicode_literals, print_function\n'
213-
code = fut + code
214210
self._root = ast.parse(code)
215-
if sys.version_info[0] == 2:
216-
self._root.body_nodes.pop(0) # remove that import node we added
217211
self._stack = []
218212
self._indent = indent
219213
self._dummy_counter = 0

pscript/stubs.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,6 @@ def __init__(self, code, _resolve_defining_module=True):
5858
raise Exception()
5959
except Exception as err:
6060
tb = getattr(err, '__traceback__', None)
61-
if tb is None: # Legacy Python 2.x
62-
import sys
63-
_, _, tb = sys.exc_info()
6461
self._globals = tb.tb_frame.f_back.f_globals
6562
del tb
6663
self.__module__ = self._globals['__name__']

pscript/tests/test_commonast.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@
2323

2424
def _export_python_sample_ast():
2525
# Get what to export
26-
if sys.version_info > (3, ):
27-
filenames = filename1, filename3
28-
else:
29-
filenames = filename2,
26+
filenames = filename1, filename3
3027
# Write
3128
for filename in filenames:
3229
filename_bz2 = filename[:-2] + 'bz2'

pscript/tests/test_parser2.py

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -512,16 +512,14 @@ def test_when_funcs_do_parse_kwargs(self):
512512
assert 'kw_values' not in code
513513

514514
# We do for keyword only args
515-
if sys.version_info > (3, ):
516-
code = py2js('def foo(a, *, b=1, c="foo"): pass')
517-
assert 'parse_kwargs' in code
518-
assert 'kw_values' in code
515+
code = py2js('def foo(a, *, b=1, c="foo"): pass')
516+
assert 'parse_kwargs' in code
517+
assert 'kw_values' in code
519518

520519
# We do for keyword only args and **kwargs
521-
if sys.version_info > (3, ):
522-
code = py2js('def foo(a, *, b=1, c="foo", **d): pass')
523-
assert 'parse_kwargs' in code
524-
assert 'kw_values' in code
520+
code = py2js('def foo(a, *, b=1, c="foo", **d): pass')
521+
assert 'parse_kwargs' in code
522+
assert 'kw_values' in code
525523

526524
def test_func1(self):
527525
code = py2js(func1)
@@ -560,7 +558,6 @@ def test_function_call_default_args(self):
560558
assert evalpy(code + 'foo()') == '9'
561559
assert evalpy(code + 'd.foo()') == '9'
562560

563-
@skipif(sys.version_info < (3,), reason='no keyword only args in legacy py')
564561
def test_function_call_keyword_only_args(self):
565562
code = "def foo(*, a=2, b=3, c=4): return a+b+c;\nd = {'foo':foo}\n"
566563
assert evalpy(code + 'foo(a=1, b=2, c=3)') == '6'
@@ -615,7 +612,6 @@ def test_function_call_args_and_kwargs(self):
615612
assert evalpy(code + 'foo(1, 2, 3, **{"b":4})') == '{ b: 4 }'
616613
assert evalpy(code + 'foo(a=3, **{"b":4})') == '{ a: 3, b: 4 }'
617614

618-
@skipif(sys.version_info < (3,), reason='no keyword only args in legacy py')
619615
def test_function_call_keyword_only_args_and_kwargs(self):
620616
code = "def foo(*, a=3, b=4, **x): return repr([a, b]) + repr(x);\nd = {'foo':foo}\n"
621617
assert evalpy(code + 'foo(1)') == '[3,4]{}'
@@ -790,7 +786,6 @@ def inner():
790786
assert evaljs(py2js(func1)+'func1()') == '2'
791787
assert evaljs(py2js(func2)+'func2()') == '3'
792788

793-
@skipif(sys.version_info < (3,), reason='no nonlocal on legacy Python')
794789
def test_nonlocal(self):
795790
assert py2js('nonlocal foo;foo = 3').strip() == 'foo = 3;'
796791

@@ -804,7 +799,6 @@ def inner():
804799
"""
805800
assert evaljs(py2js(func3_code)+'func3()') == '3'
806801

807-
@skipif(sys.version_info < (3,), reason='no nonlocal on legacy Python')
808802
def test_global_vs_nonlocal(self):
809803
js1 = py2js('global foo;foo = 3')
810804
js2 = py2js('nonlocal foo;foo = 3')
@@ -955,7 +949,7 @@ def addTwo(self):
955949
super().addTwo()
956950
self.bar += 1 # haha, we add four!
957951
def addFour(self):
958-
super(MyClass3, self).add(4) # Use legacy Python syntax
952+
super(MyClass3, self).add(4) # Use older syntax
959953

960954
code = py2js(MyClass1) + py2js(MyClass2) + py2js(MyClass3)
961955
code += 'var m1=new MyClass1(), m2=new MyClass2(), m3=new MyClass3();'

pscript/tests/test_parser3.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,6 @@ def test_no_dict(self):
446446
assert evalpy(code + 'foo = Foo(); foo.clear(); foo.bar') == '42'
447447

448448
def test_that_all_dict_methods_are_tested(self):
449-
if sys.version_info[0] == 2:
450-
skip('On legacy py, the dict methods are different')
451449
tested = set([x.split('_')[1] for x in dir(self) if x.startswith('test_')])
452450
needed = set([x for x in dir(dict) if not x.startswith('_')])
453451
ignore = 'fromkeys'
@@ -777,7 +775,7 @@ def test_splitlines(self):
777775
assert evalpy(r'"abc\r\ndef".splitlines(True)') == "[ 'abc\\r\\n', 'def' ]"
778776

779777
res = repr("X\n\nX\r\rX\r\n\rX\n\r\nX".splitlines(True)).replace(' ', '')
780-
res = res.replace('u"', '"').replace("u'", "'") # arg legacy py
778+
# res = res.replace('u"', '"').replace("u'", "'") # arg legacy py
781779
assert nowhitespace(evalpy(r'"X\n\nX\r\rX\r\n\rX\n\r\nX".splitlines(true)')) == res
782780

783781
def test_replace(self):

pscript/tests/test_stdlib.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,15 @@ def test_stdlib_has_all_list_methods():
3434

3535
def test_stdlib_has_all_dict_methods():
3636
method_names = [m for m in dir(dict) if not m.startswith('_')]
37-
if sys.version_info[0] == 2:
38-
ignore = 'fromkeys has_key viewitems viewkeys viewvalues iteritems iterkeys itervalues'
39-
else:
40-
ignore = 'fromkeys'
37+
ignore = 'fromkeys'
4138
for name in ignore.split(' '):
4239
method_names.remove(name)
4340
for method_name in method_names:
4441
assert method_name in stdlib.METHODS
4542

4643
def test_stdlib_has_all_str_methods():
4744
method_names = [m for m in dir(str) if not m.startswith('_')]
48-
if sys.version_info[0] == 2:
49-
ignore = 'encode decode'
50-
else:
51-
ignore = 'encode format_map isprintable maketrans isascii removeprefix removesuffix'
45+
ignore = 'encode format_map isprintable maketrans isascii removeprefix removesuffix'
5246
for name in ignore.split(' '):
5347
if name in method_names:
5448
method_names.remove(name)

0 commit comments

Comments
 (0)