Skip to content

Commit

Permalink
Add support for Python 3.12
Browse files Browse the repository at this point in the history
  • Loading branch information
skoolkid committed Oct 31, 2023
1 parent 330d43c commit 60daf9a
Show file tree
Hide file tree
Showing 19 changed files with 55 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ['3.8', '3.9', '3.10', '3.11']
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
steps:
- uses: actions/checkout@v2

Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ usage:
@echo " clean clean the documentation and man pages"
@echo " hh build the Hungry Horace disassembly"
@echo " test run core tests"
@echo " test3X run core tests with Python 3.X (8<=X<=11)"
@echo " test3X run core tests with Python 3.X (8<=X<=12)"
@echo " test-slow run slow tests"
@echo " test-all run core and disassembly tests"
@echo " test3X-all run core and disassembly tests with Python 3.X (8<=X<=11)"
@echo " test3X-all run core and disassembly tests with Python 3.X (8<=X<=12)"
@echo " test-cover run core tests with coverage info"
@echo " release build a SkoolKit release tarball and zip archive"
@echo " tarball build a SkoolKit release tarball"
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ classifiers =
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: 3.12
Topic :: Software Development :: Disassemblers
Topic :: Utilities

Expand Down
4 changes: 2 additions & 2 deletions skoolkit/skoolasm.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2008-2022 Richard Dymond (rjdymond@gmail.com)
# Copyright 2008-2023 Richard Dymond (rjdymond@gmail.com)
#
# This file is part of SkoolKit.
#
Expand Down Expand Up @@ -426,7 +426,7 @@ def find_unconverted_addresses(self, text, ignores):
if ignores == []:
return ()
addresses = set()
for match in re.finditer('(\A|\s|\()((?:0x|\$)[0-9A-Fa-f]{4}|[1-9][0-9]{2,4})(?!([0-9A-Za-z]|[./*+][0-9]))', text):
for match in re.finditer(r'(\A|\s|\()((?:0x|\$)[0-9A-Fa-f]{4}|[1-9][0-9]{2,4})(?!([0-9A-Za-z]|[./*+][0-9]))', text):
addr = match.group(2)
if addr.startswith(('0x', '$')):
address = int(addr[-4:], 16)
Expand Down
4 changes: 2 additions & 2 deletions skoolkit/skoolctl.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2010-2022 Richard Dymond (rjdymond@gmail.com)
# Copyright 2010-2023 Richard Dymond (rjdymond@gmail.com)
#
# This file is part of SkoolKit.
#
Expand Down Expand Up @@ -41,7 +41,7 @@

# An entry ASM directive is one that should be placed before the entry title
# when it is associated with the first instruction in the entry
RE_ENTRY_ASM_DIRECTIVE = re.compile("assemble=|def[bsw]=|end$|equ=|expand=|if\(|org$|org=|remote=|replace=|rom|set-[-a-z]+=|start$|writer=")
RE_ENTRY_ASM_DIRECTIVE = re.compile(r"assemble=|def[bsw]=|end$|equ=|expand=|if\(|org$|org=|remote=|replace=|rom|set-[-a-z]+=|start$|writer=")

# Comment types to which the @ignoreua directive may be applied
TITLE = 't'
Expand Down
6 changes: 3 additions & 3 deletions skoolkit/skoolhtml.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2008-2022 Richard Dymond (rjdymond@gmail.com)
# Copyright 2008-2023 Richard Dymond (rjdymond@gmail.com)
#
# This file is part of SkoolKit.
#
Expand Down Expand Up @@ -127,7 +127,7 @@ def __init__(self, skool_parser, ref_parser, file_info=None, code_id=MAIN_CODE_I
anchor, title, paragraphs = entry
except ValueError:
title, paragraphs = entry
anchor = re.sub('[\s()]', '_', title.lower())
anchor = re.sub(r'[\s()]', '_', title.lower())
if use_paragraphs:
entries.append((anchor, title, paragraphs))
else:
Expand Down Expand Up @@ -1364,7 +1364,7 @@ def _unroll_loops(self, lines, fields):
def _eval_template_expr(self, expr, fields):
if expr:
try:
return eval(re.sub('\[([^0-9][^]]*)\]', r"['\1']", expr.format(**fields)), None, fields)
return eval(re.sub(r'\[([^0-9][^]]*)\]', r"['\1']", expr.format(**fields)), None, fields)
except SyntaxError:
raise ValueError("Syntax error in expression: '{}'".format(expr))
except KeyError as e:
Expand Down
10 changes: 5 additions & 5 deletions skoolkit/skoolmacro.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

ZX_CHARS = {94: 8593, 96: 163, 127: 169}

INTEGER = '(\d+|\$[0-9a-fA-F]+)'
INTEGER = r'(\d+|\$[0-9a-fA-F]+)'

PARAM_NAME = '[a-z]+'

Expand All @@ -57,19 +57,19 @@

RE_CODE_ID = re.compile('@[a-zA-Z0-9$]*')

RE_EXPAND = re.compile('#[^A-Za-z0-9\s]')
RE_EXPAND = re.compile(r'#[^A-Za-z0-9\s]')

RE_FRAME_ID = re.compile('[^\s,;(]+')
RE_FRAME_ID = re.compile(r'[^\s,;(]+')

RE_MACRO = re.compile('#[A-Z]+')

RE_MACRO_METHOD = re.compile('expand_([a-z]+)$')

RE_METHOD_NAME = re.compile('[a-zA-Z_][a-zA-Z0-9_]*')

RE_LINK_PARAMS = re.compile('[^(\s]+')
RE_LINK_PARAMS = re.compile(r'[^(\s]+')

RE_PARAM_NAME = re.compile('\s*{}\s*='.format(PARAM_NAME))
RE_PARAM_NAME = re.compile(r'\s*{}\s*='.format(PARAM_NAME))

RE_REGISTER = re.compile("(af?|f|bc?|c|de?|e|hl?|l)'?|i[xy][lh]?|i|pc|r|sp")

Expand Down
8 changes: 4 additions & 4 deletions skoolkit/skoolparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
Reference = namedtuple('Reference', 'entry address addr_str use_label')

def _replace_nums(operation, hex_fmt=None, skip_bit=False, prefix=None):
elements = re.split('(?<=[\s,(%*/+-])(\$[0-9A-Fa-f]+|\d+)', (prefix or '(') + operation)
elements = re.split(r'(?<=[\s,(%*/+-])(\$[0-9A-Fa-f]+|\d+)', (prefix or '(') + operation)
for i in range(2 * int(skip_bit) + 1, len(elements), 2):
p1, p2 = elements[i - 1][:-1].strip(), elements[i - 1][-1]
if (p2 != '%' or not p1 or p1[-1] in ')"') and p2 != '"':
Expand All @@ -66,7 +66,7 @@ def _is_8_bit_ld_instruction(operation):
return False

def get_address(operation):
search = re.search('(\A|[\s,(+-])(\$[0-9A-Fa-f]+|%[01]+|\d+)', operation)
search = re.search(r'(\A|[\s,(+-])(\$[0-9A-Fa-f]+|%[01]+|\d+)', operation)
if search:
return search.group(2)

Expand Down Expand Up @@ -1008,7 +1008,7 @@ def _convert_base(self, operation, hex2fmt, hex4fmt):
op = elements[0]

# Instructions containing '(I[XY]+d)'
if re.search('\(I[XY] *[+-].*\)', operation.upper()):
if re.search(r'\(I[XY] *[+-].*\)', operation.upper()):
return _replace_nums(operation, hex2fmt, op in ('BIT', 'RES', 'SET'))

if op in ('CALL', 'DJNZ', 'JP', 'JR'):
Expand Down Expand Up @@ -1083,7 +1083,7 @@ def _replace_addresses(self, entry, instruction, operand):
rep = ''
for p in split_quoted(operand):
if not p.startswith('"'):
pieces = re.split('(\A|(?<=[\s,(+-]))(\$[0-9A-Fa-f]+|%[01]+|\d+)', p)
pieces = re.split(r'(\A|(?<=[\s,(+-]))(\$[0-9A-Fa-f]+|%[01]+|\d+)', p)
for i in range(2, len(pieces), 3):
label = self._get_label(entry, instruction, pieces[i])
if label:
Expand Down
4 changes: 2 additions & 2 deletions skoolkit/z80.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2015, 2017-2019, 2021, 2022 Richard Dymond (rjdymond@gmail.com)
# Copyright 2015, 2017-2019, 2021-2023 Richard Dymond (rjdymond@gmail.com)
#
# This file is part of SkoolKit.
#
Expand Down Expand Up @@ -736,7 +736,7 @@ def _convert_chars(text):
return s

def _convert_nums(text):
elements = re.split('(\$[0-9A-Fa-f]+|%[01]+|\d+)', re.sub('\s+', '', text))
elements = re.split(r'(\$[0-9A-Fa-f]+|%[01]+|\d+)', re.sub(r'\s+', '', text))
for i in range(1, len(elements), 2):
q = elements[i]
if q.startswith('$'):
Expand Down
2 changes: 1 addition & 1 deletion tests/skoolkittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ def make_directory(self, path=None):
if path is None:
tempdir = tempfile.mkdtemp(dir='')
self.tempdirs.append(os.path.abspath(tempdir))
return tempdir
return os.path.relpath(tempdir)
if path and not os.path.isdir(path):
parent = path
while 1:
Expand Down
16 changes: 8 additions & 8 deletions tests/test_bin2tap.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,24 +234,24 @@ def test_empty_bin(self):

def test_bin_with_invalid_org_and_begin_and_end_addresses(self):
binfile = self.write_bin_file([0], suffix='.bin')
with self.assertRaisesRegex(SkoolKitError, '^Input is empty \(ORG=32768, BEGIN=65535, END=32769\)$'):
with self.assertRaisesRegex(SkoolKitError, r'^Input is empty \(ORG=32768, BEGIN=65535, END=32769\)$'):
self.run_bin2tap('-o 32768 -b 65535 {}'.format(binfile))
with self.assertRaisesRegex(SkoolKitError, '^Input is empty \(ORG=32768, BEGIN=32768, END=24576\)$'):
with self.assertRaisesRegex(SkoolKitError, r'^Input is empty \(ORG=32768, BEGIN=32768, END=24576\)$'):
self.run_bin2tap('-o 32768 -e 24576 {}'.format(binfile))
with self.assertRaisesRegex(SkoolKitError, '^Input is empty \(ORG=32768, BEGIN=32768, END=32768\)$'):
with self.assertRaisesRegex(SkoolKitError, r'^Input is empty \(ORG=32768, BEGIN=32768, END=32768\)$'):
self.run_bin2tap('-o 32768 -b 32768 -e 32768 {}'.format(binfile))
with self.assertRaisesRegex(SkoolKitError, '^Input is empty \(ORG=32768, BEGIN=23296, END=23297\)$'):
with self.assertRaisesRegex(SkoolKitError, r'^Input is empty \(ORG=32768, BEGIN=23296, END=23297\)$'):
self.run_bin2tap('-o 32768 -b 23296 -e 23297 {}'.format(binfile))
with self.assertRaisesRegex(SkoolKitError, '^Input is empty \(ORG=32768, BEGIN=49152, END=49153\)$'):
with self.assertRaisesRegex(SkoolKitError, r'^Input is empty \(ORG=32768, BEGIN=49152, END=49153\)$'):
self.run_bin2tap('-o 32768 -b 49152 -e 49153 {}'.format(binfile))

def test_snapshot_with_invalid_begin_and_end_addresses(self):
snafile = self.write_bin_file([0] * 49179, suffix='.sna')
with self.assertRaisesRegex(SkoolKitError, '^Input is empty \(ORG=0, BEGIN=65536, END=65536\)$'):
with self.assertRaisesRegex(SkoolKitError, r'^Input is empty \(ORG=0, BEGIN=65536, END=65536\)$'):
self.run_bin2tap('-b 65536 {}'.format(snafile))
with self.assertRaisesRegex(SkoolKitError, '^Input is empty \(ORG=0, BEGIN=16384, END=16384\)$'):
with self.assertRaisesRegex(SkoolKitError, r'^Input is empty \(ORG=0, BEGIN=16384, END=16384\)$'):
self.run_bin2tap('-e 16384 {}'.format(snafile))
with self.assertRaisesRegex(SkoolKitError, '^Input is empty \(ORG=0, BEGIN=32768, END=24576\)$'):
with self.assertRaisesRegex(SkoolKitError, r'^Input is empty \(ORG=0, BEGIN=32768, END=24576\)$'):
self.run_bin2tap('-b 32768 -e 24576 {}'.format(snafile))

def test_no_options(self):
Expand Down
2 changes: 1 addition & 1 deletion tests/test_skool2html.py
Original file line number Diff line number Diff line change
Expand Up @@ -1161,7 +1161,7 @@ def test_option_q(self):
@patch.object(skool2html, 'get_config', mock_config)
def test_option_t(self):
skoolfile = self.write_text_file(suffix='.skool')
pattern = 'Done \([0-9]+\.[0-9][0-9]s\)'
pattern = r'Done \([0-9]+\.[0-9][0-9]s\)'
for option in ('-t', '--time'):
output, error = self.run_skool2html('{} -w i -d {} {}'.format(option, self.odir, skoolfile))
self.assertEqual(error, '')
Expand Down
18 changes: 9 additions & 9 deletions tests/test_skoolhtml.py
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,7 @@ def test_format_template_foreach_no_parameters(self):
{item}
<# endfor #>
"""
with self.assertRaisesRegex(SkoolKitError, "^Invalid foreach directive: Not enough parameters \(expected 2\): ''$"):
with self.assertRaisesRegex(SkoolKitError, r"^Invalid foreach directive: Not enough parameters \(expected 2\): ''$"):
self._get_writer(ref=ref).format_template('loop', {})

def test_format_template_foreach_missing_parameter(self):
Expand All @@ -984,7 +984,7 @@ def test_format_template_foreach_missing_parameter(self):
{item}
<# endfor #>
"""
with self.assertRaisesRegex(SkoolKitError, "^Invalid foreach directive: Not enough parameters \(expected 2\): 'item'$"):
with self.assertRaisesRegex(SkoolKitError, r"^Invalid foreach directive: Not enough parameters \(expected 2\): 'item'$"):
self._get_writer(ref=ref).format_template('loop', {})

def test_format_template_foreach_extra_parameter(self):
Expand All @@ -994,7 +994,7 @@ def test_format_template_foreach_extra_parameter(self):
{item}
<# endfor #>
"""
with self.assertRaisesRegex(SkoolKitError, "^Invalid foreach directive: Too many parameters \(expected 2\): 'item,list,surplus'$"):
with self.assertRaisesRegex(SkoolKitError, r"^Invalid foreach directive: Too many parameters \(expected 2\): 'item,list,surplus'$"):
self._get_writer(ref=ref).format_template('loop', {})

def test_format_template_foreach_no_closing_bracket(self):
Expand All @@ -1004,7 +1004,7 @@ def test_format_template_foreach_no_closing_bracket(self):
{item}
<# endfor #>
"""
with self.assertRaisesRegex(SkoolKitError, "^Invalid foreach directive: No closing bracket: \(item,list$"):
with self.assertRaisesRegex(SkoolKitError, r"^Invalid foreach directive: No closing bracket: \(item,list$"):
self._get_writer(ref=ref).format_template('loop', {})

def test_format_template_foreach_unknown_variable(self):
Expand Down Expand Up @@ -1232,7 +1232,7 @@ def test_format_template_if_no_closing_bracket(self):
Content
<# endif #>
"""
with self.assertRaisesRegex(SkoolKitError, "^Invalid if directive: No closing bracket: \(true$"):
with self.assertRaisesRegex(SkoolKitError, r"^Invalid if directive: No closing bracket: \(true$"):
self._get_writer(ref=ref).format_template('if', {})

def test_format_template_if_unknown_variable(self):
Expand Down Expand Up @@ -1262,7 +1262,7 @@ def test_format_template_if_syntax_error(self):
Content
<# endif #>
"""
with self.assertRaisesRegex(SkoolKitError, "^Invalid if directive: Syntax error in expression: '\(1;\)'$"):
with self.assertRaisesRegex(SkoolKitError, r"^Invalid if directive: Syntax error in expression: '\(1;\)'$"):
self._get_writer(ref=ref).format_template('if', {})

def test_format_template_include(self):
Expand Down Expand Up @@ -1330,7 +1330,7 @@ def test_format_template_include_no_closing_bracket(self):
[Template:include]
<# include(t1 #>
"""
with self.assertRaisesRegex(SkoolKitError, "^Invalid include directive: No closing bracket: \(t1$"):
with self.assertRaisesRegex(SkoolKitError, r"^Invalid include directive: No closing bracket: \(t1$"):
self._get_writer(ref=ref).format_template('include', {})

def test_format_template_include_unknown_template(self):
Expand Down Expand Up @@ -5174,7 +5174,7 @@ def test_expand_directive_with_invalid_macro(self):
@expand=#N(x)
c32768 RET
"""
with self.assertRaisesRegex(SkoolParsingError, "^Failed to expand '#N\(x\)': Error while parsing #N macro: Cannot parse integer 'x' in parameter string: 'x'$"):
with self.assertRaisesRegex(SkoolParsingError, r"^Failed to expand '#N\(x\)': Error while parsing #N macro: Cannot parse integer 'x' in parameter string: 'x'$"):
self._get_writer(skool=skool)

def test_expand_directive_with_unexpandable_macro(self):
Expand Down Expand Up @@ -5901,7 +5901,7 @@ def test_parameter_Expand_with_invalid_macro(self):
[Config]
Expand=#N(x)
"""
with self.assertRaisesRegex(SkoolParsingError, "^Failed to expand '#N\(x\)': Error while parsing #N macro: Cannot parse integer 'x' in parameter string: 'x'$"):
with self.assertRaisesRegex(SkoolParsingError, r"^Failed to expand '#N\(x\)': Error while parsing #N macro: Cannot parse integer 'x' in parameter string: 'x'$"):
self._get_writer(ref=ref, skool=skool)

def test_parameter_Expand_with_unexpandable_macro(self):
Expand Down
14 changes: 7 additions & 7 deletions tests/test_skoolparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3069,7 +3069,7 @@ def test_label_substitution_for_address_operands(self):
index = 2
lines = dedent(skool).strip().split('\n')
for instruction in instructions:
exp_operation = re.sub('(12445|\$309[Dd]|%0011000010011101)', 'START', lines[index][7:])
exp_operation = re.sub(r'(12445|\$309[Dd]|%0011000010011101)', 'START', lines[index][7:])
self.assertEqual(instruction.operation, exp_operation)
self.assertIsNotNone(instruction.reference)
self.assertEqual(instruction.reference.address, 12445)
Expand Down Expand Up @@ -3101,7 +3101,7 @@ def test_label_substitution_for_16_bit_ld_instruction_operands_below_256(self):
index = 2
lines = dedent(skool).strip().split('\n')
for instruction in instructions:
exp_operation = re.sub('(0|\$0000|%0000000000000000)', 'START', lines[index][7:])
exp_operation = re.sub(r'(0|\$0000|%0000000000000000)', 'START', lines[index][7:])
self.assertEqual(instruction.operation, exp_operation)
self.assertIsNotNone(instruction.reference)
self.assertEqual(instruction.reference.address, 0)
Expand Down Expand Up @@ -3585,7 +3585,7 @@ def test_replace_directive_with_invalid_pattern(self):
; Routine
c32768 RET
"""
self.assert_error(skool, "Failed to compile regular expression '\[abc': (unexpected end of regular expression|unterminated character set at position 0)")
self.assert_error(skool, r"Failed to compile regular expression '\[abc': (unexpected end of regular expression|unterminated character set at position 0)")

def test_replace_directive_with_invalid_replacement(self):
skool = r"""
Expand Down Expand Up @@ -5345,7 +5345,7 @@ def test_isub_plus_inside_bfix_plus(self):
@isub+end
@bfix+end
"""
error = "isub\+else inside bfix\+ block"
error = r"isub\+else inside bfix\+ block"
self.assert_error(skool, error, asm_mode=1)

def test_dangling_ofix_else(self):
Expand All @@ -5355,13 +5355,13 @@ def test_dangling_ofix_else(self):
@ofix+else
@ofix+end
"""
error = "ofix\+else not inside block"
error = r"ofix\+else not inside block"
self.assert_error(skool, error, asm_mode=1)

def test_dangling_rfix_end(self):
# Dangling @rfix+end directive
skool = '@start\n@rfix+end'
error = "rfix\+end has no matching start directive"
error = r"rfix\+end has no matching start directive"
self.assert_error(skool, error, asm_mode=1)

def test_wrong_end_infix(self):
Expand All @@ -5372,7 +5372,7 @@ def test_wrong_end_infix(self):
@rsub-else
@rsub+end
"""
error = "rsub\+end cannot end rsub- block"
error = r"rsub\+end cannot end rsub- block"
self.assert_error(skool, error, asm_mode=1)

def test_mismatched_begin_end(self):
Expand Down
3 changes: 2 additions & 1 deletion tests/test_tap2sna.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ def __init__(self, *args, **kwargs):
# The NOP at 49151 is a dummy instruction that triggers LoadTracer's
# read_port() (via in_a_n() below) and starts the tape running.
self.registers[24] = 49151 # PC
self.stop = max(a for a in range(49152, 65536) if mock_memory[a]) + 2
if self.memory:
self.stop = max(a for a in range(49152, 65536) if self.memory[a]) + 2
simulator = self

def set_tracer(self, tracer, *args, **kwargs):
Expand Down
4 changes: 2 additions & 2 deletions tests/test_tapinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ def test_option_d_with_tap_file(self):
tapfile = self.write_bin_file(tap_data, suffix='.tap')
output, error = self.run_tapinfo('-d {}'.format(tapfile))
self.assertEqual(error, '')
exp_output = """
exp_output = r"""
1:
Type: Header block
Bytes: test_tap02
Expand Down Expand Up @@ -687,7 +687,7 @@ def test_option_data_with_tzx_file(self):
tzxfile = self._write_tzx(blocks)
output, error = self.run_tapinfo('-d {}'.format(tzxfile))
self.assertEqual(error, '')
exp_output = """
exp_output = r"""
Version: 1.20
1: Standard speed data (0x10)
Pause: 0ms
Expand Down
2 changes: 1 addition & 1 deletion tools/disassembly.mk
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ usage:
@echo " html build the HTML disassembly"
@echo " asm build the ASM disassembly"
@echo " test run tests"
@echo " test3X run tests with Python 3.X (8<=X<=11)"
@echo " test3X run tests with Python 3.X (8<=X<=12)"
@$(MAKE) -s _targets
@echo ""
@echo "Variables:"
Expand Down
Loading

0 comments on commit 60daf9a

Please sign in to comment.