From c837a38ef133470e4eb92f7f348877ca62358cc7 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Oct 2025 12:04:58 -0400 Subject: [PATCH 01/17] Misc fixes --- .pre-commit-config.yaml | 12 ++++++------ xasm/assemble.py | 20 ++++++++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ae003f3..4cbf372 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,9 +14,9 @@ repos: hooks: - id: isort stages: [pre-commit] -# - repo: https://github.com/psf/black -# rev: 23.12.0 -# hooks: -# - id: black -# language_version: python3 -# stages: [commit] +- repo: https://github.com/psf/black + rev: 23.12.1 + hooks: + - id: black + language_version: python3 + stages: [pre-commit] diff --git a/xasm/assemble.py b/xasm/assemble.py index 9539054..6a0aad7 100644 --- a/xasm/assemble.py +++ b/xasm/assemble.py @@ -216,7 +216,9 @@ def asm_file(path): python_bytecode_version, length=2 ) asm.code_init(python_version_pair) - asm.code.co_name = line[len("# Method Name: ") :].strip() + asm.code.co_qual_name = asm.code.co_name = line[ + len("# Method Name: ") : + ].strip() method_name = asm.code.co_name elif line.startswith("# SipHash: "): siphash = line[len("# ShipHash: ") :].strip().split()[0] @@ -341,7 +343,9 @@ def asm_file(path): if match: line_no = int(match.group(1)) - linetable_field = "co_lnotab" if python_version_pair < (3, 10) else "co_linetable" + linetable_field = ( + "co_lnotab" if python_version_pair < (3, 10) else "co_linetable" + ) assert asm is not None linetable = getattr(asm.code, linetable_field) linetable[offset] = line_no @@ -437,7 +441,9 @@ def update_code_tuple_field(field_name, code, lines, i): match = re.match(r"^#\s+(\d+): (.+)$", line) if match: index = int(match.group(1)) - assert index == count, f'In field" "{field_name}", line {i}, number {index} is expected to have value {count}.' + assert ( + index == count + ), f'In field" "{field_name}", line {i}, number {index} is expected to have value {count}.' field_values = getattr(code, field_name) field_values.append(match.group(2)) count += 1 @@ -593,7 +599,6 @@ def create_code(asm: Assembler, label, backpatch) -> tuple: is_valid = True for i, inst in enumerate(asm.code.instructions): - # Strip out extended arg instructions. # Operands in the input can be arbitary numbers. # In this loop we will figure out whether @@ -609,10 +614,13 @@ def create_code(asm: Assembler, label, backpatch) -> tuple: if offset in offset2label: if is_int(offset2label[offset]): inst.line_no = int(offset2label[offset]) - if inst.line_no in asm.code.co_lnotab.values() and asm.python_version < (3, 10): + if ( + inst.line_no in asm.code.co_lnotab.values() + and asm.python_version < (3, 10) + ): print( f"Line {i}: this is not the first we encounter source-code line {inst.line_no}." - ) + ) asm.code.co_lnotab[offset] = inst.line_no inst.offset = offset From 18961bd6dbd84625b1df41716fd534a388017cda Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Oct 2025 12:04:58 -0400 Subject: [PATCH 02/17] Misc fixes --- .pre-commit-config.yaml | 12 ++++++------ requirements.txt | 2 +- xasm/assemble.py | 20 ++++++++++++++------ 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ae003f3..4cbf372 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,9 +14,9 @@ repos: hooks: - id: isort stages: [pre-commit] -# - repo: https://github.com/psf/black -# rev: 23.12.0 -# hooks: -# - id: black -# language_version: python3 -# stages: [commit] +- repo: https://github.com/psf/black + rev: 23.12.1 + hooks: + - id: black + language_version: python3 + stages: [pre-commit] diff --git a/requirements.txt b/requirements.txt index 9bfdd49..4969fbe 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ click~=8.0.3 -pip~>23.3 +pip wheel~=0.38.1 cryptography~>44.0.1 lxml~>4.9.1 diff --git a/xasm/assemble.py b/xasm/assemble.py index 9539054..6a0aad7 100644 --- a/xasm/assemble.py +++ b/xasm/assemble.py @@ -216,7 +216,9 @@ def asm_file(path): python_bytecode_version, length=2 ) asm.code_init(python_version_pair) - asm.code.co_name = line[len("# Method Name: ") :].strip() + asm.code.co_qual_name = asm.code.co_name = line[ + len("# Method Name: ") : + ].strip() method_name = asm.code.co_name elif line.startswith("# SipHash: "): siphash = line[len("# ShipHash: ") :].strip().split()[0] @@ -341,7 +343,9 @@ def asm_file(path): if match: line_no = int(match.group(1)) - linetable_field = "co_lnotab" if python_version_pair < (3, 10) else "co_linetable" + linetable_field = ( + "co_lnotab" if python_version_pair < (3, 10) else "co_linetable" + ) assert asm is not None linetable = getattr(asm.code, linetable_field) linetable[offset] = line_no @@ -437,7 +441,9 @@ def update_code_tuple_field(field_name, code, lines, i): match = re.match(r"^#\s+(\d+): (.+)$", line) if match: index = int(match.group(1)) - assert index == count, f'In field" "{field_name}", line {i}, number {index} is expected to have value {count}.' + assert ( + index == count + ), f'In field" "{field_name}", line {i}, number {index} is expected to have value {count}.' field_values = getattr(code, field_name) field_values.append(match.group(2)) count += 1 @@ -593,7 +599,6 @@ def create_code(asm: Assembler, label, backpatch) -> tuple: is_valid = True for i, inst in enumerate(asm.code.instructions): - # Strip out extended arg instructions. # Operands in the input can be arbitary numbers. # In this loop we will figure out whether @@ -609,10 +614,13 @@ def create_code(asm: Assembler, label, backpatch) -> tuple: if offset in offset2label: if is_int(offset2label[offset]): inst.line_no = int(offset2label[offset]) - if inst.line_no in asm.code.co_lnotab.values() and asm.python_version < (3, 10): + if ( + inst.line_no in asm.code.co_lnotab.values() + and asm.python_version < (3, 10) + ): print( f"Line {i}: this is not the first we encounter source-code line {inst.line_no}." - ) + ) asm.code.co_lnotab[offset] = inst.line_no inst.offset = offset From cccb5a76396e2b12a6e247647b79d21286a6c353 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Oct 2025 12:30:39 -0400 Subject: [PATCH 03/17] Try custom CI for this branch --- .github/workflows/osx.yml | 30 ------------------------------ .github/workflows/ubuntu.yml | 21 +++++++++++++-------- .github/workflows/windows.yml | 31 ------------------------------- 3 files changed, 13 insertions(+), 69 deletions(-) delete mode 100644 .github/workflows/osx.yml delete mode 100644 .github/workflows/windows.yml diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml deleted file mode 100644 index bacf2b0..0000000 --- a/.github/workflows/osx.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: xasm (osx) - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - runs-on: macos-latest - strategy: - matrix: - os: [macOS] - python-version: ['3.10'] - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - # We can comment out after next xdis release - python -m pip install -e git+https://github.com/rocky/python-xdis#egg=xdis - pip install -e . - pip install -r requirements-dev.txt - - name: Test xasm - run: | - make check diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index ea2946c..6af0daa 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -1,27 +1,32 @@ -name: xdis (ubuntu) +name: xdis (Ubuntu) on: push: - branches: [ master ] + branches: [ python-3.6-to-3.10 ] pull_request: - branches: [ master ] + branches: [ python-3.6-to-3.10 ] jobs: build: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.8', '3.9', '3.10'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - # We can comment out after next xdis release - python -m pip install -e git+https://github.com/rocky/python-xdis#egg=xdis + # Install the latest xdis release tarball from GitHub Releases (asset named xdis_36-*.tar.gz) + XDIS_URL=$(curl -s https://api.github.com/repos/rocky/python-xdis/releases/latest \ + | python -c "import sys,json; j=json.load(sys.stdin); assets=j.get('assets',[]); print(next((a.get('browser_download_url') for a in assets if a.get('name','').startswith('xdis_36-') and a.get('name','').endswith('.tar.gz')), ''))") + if [ -z "$XDIS_URL" ]; then + echo "ERROR: no xdis_36-*.tar.gz asset found on the latest release"; exit 1 + fi + python -m pip install "$XDIS_URL" pip install -e . pip install -r requirements-dev.txt - name: Test xasm diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml deleted file mode 100644 index ff755a1..0000000 --- a/.github/workflows/windows.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: xasm (windows) - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - runs-on: windows-latest - strategy: - matrix: - os: [windows] - python-version: ['3.8', '3.9', '3.10', '3.11'] - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - # We can comment out after next xdis release - python -m pip install -e git+https://github.com/rocky/python-xdis#egg=xdis - pip install -e . - pip install -r requirements-dev.txt - - name: Test xasm - run: | - # Until workflows CI problems are fixed - make check From 8eb1015d15c070ec45ba28b02b6d4c64dd9d60b6 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Oct 2025 16:22:39 -0400 Subject: [PATCH 04/17] Go over packaging. --- __pkginfo__.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 134348b..8dd4586 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -7,9 +7,11 @@ # less elegant than having it here with reduced code, albeit there # still is some room for improvement. +import os.path as osp + # Things that change more often go here. copyright = """ -Copyright (C) 2017, 2019-2021, 2024 Rocky Bernstein . +Copyright (C) 2017, 2019-2021, 2024-2025 Rocky Bernstein . """ classifiers = [ @@ -31,13 +33,11 @@ "Topic :: Software Development :: Libraries :: Python Modules", ] -_six = "six >= 1.10.0" - # The rest in alphabetic order author = "Rocky Bernstein" author_email = "rb@dustyfeet.com" ftp_url = None -install_requires = [_six, "xdis >= 6.1.0"] +install_requires = ["xdis >= 6.1.0"] license = "GPL-2.0" mailing_list = "python-debugger@googlegroups.com" modname = "xasm" @@ -45,14 +45,12 @@ setup_requires = ["pytest-runner", "xdis >= 6.1.0"] # scripts = ['bin/pydisasm'] short_desc = "Python cross-version byte-code assembler" -tests_require = ["pytest", _six] +tests_require = ["pytest"] web = "https://github.com/rocky/python-xasm/" # tracebacks in zip files are funky and not debuggable zip_safe = True -import os.path as osp - def get_srcdir(): filename = osp.normcase(osp.dirname(osp.abspath(__file__))) From 2c8c5ce03649460a8d5a6639381bd742751b2983 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Oct 2025 16:30:43 -0400 Subject: [PATCH 05/17] Ignore compare of bytecode on 3.6 for now. We are seeing REF_FLAG differences (0x63 vs 0xe3) on a code object. This needs sorting out in xdis, not here. --- pytest/test_write_pyc.py | 2 +- xasm/assemble.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pytest/test_write_pyc.py b/pytest/test_write_pyc.py index 776bf08..fcdc732 100644 --- a/pytest/test_write_pyc.py +++ b/pytest/test_write_pyc.py @@ -36,7 +36,7 @@ def test_roundtrip3(): print("Wrote Python %s bytecode file %s; %d bytes" % (version, fp.name, size)) old_fp = open(orig_path, "rb") new_fp = open(new_path, "rb") - if PYTHON_VERSION_TRIPLE < (3, 7): + if PYTHON_VERSION_TRIPLE < (3, 6): compare_size = 590 assert old_fp.read(compare_size) == new_fp.read(compare_size) else: diff --git a/xasm/assemble.py b/xasm/assemble.py index 6a0aad7..df57022 100644 --- a/xasm/assemble.py +++ b/xasm/assemble.py @@ -37,7 +37,7 @@ def is_int(s) -> bool: return False -def match_lineno(s: str) -> Optional[re.Match]: +def match_lineno(s: str): return re.match(r"^\d+:", s) From fe831955f439c9b6cc315dba5ebf24c5349f1739 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Oct 2025 16:40:31 -0400 Subject: [PATCH 06/17] 3.6..3.10 uses older packaging --- .pre-commit-config.yaml | 10 ++-- __pkginfo__.py | 5 +- admin-tools/check-3.6-3.10-versions.sh | 2 +- admin-tools/pyenv-3.6-3.10-versions | 2 +- pyproject.toml | 63 -------------------------- setup.py | 41 ++++++++++++++++- 6 files changed, 50 insertions(+), 73 deletions(-) delete mode 100644 pyproject.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4cbf372..d5d5ca2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,11 +9,11 @@ repos: stages: [pre-commit] - id: end-of-file-fixer stages: [pre-commit] -- repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - stages: [pre-commit] +# - repo: https://github.com/pycqa/isort +# rev: 5.13.2 +# hooks: +# - id: isort +# stages: [pre-commit] - repo: https://github.com/psf/black rev: 23.12.1 hooks: diff --git a/__pkginfo__.py b/__pkginfo__.py index 8dd4586..9148e02 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -41,7 +41,7 @@ license = "GPL-2.0" mailing_list = "python-debugger@googlegroups.com" modname = "xasm" -py_modules = None +py_modules = [] setup_requires = ["pytest-runner", "xdis >= 6.1.0"] # scripts = ['bin/pydisasm'] short_desc = "Python cross-version byte-code assembler" @@ -66,4 +66,7 @@ def read(*rnames): # Get info from files; set: long_description and VERSION long_description = read("README.rst") + "\n" + +# The below exec() overwrites __version +__version__ = "??" exec(read("xasm/version.py")) diff --git a/admin-tools/check-3.6-3.10-versions.sh b/admin-tools/check-3.6-3.10-versions.sh index 5be48b6..e111a09 100755 --- a/admin-tools/check-3.6-3.10-versions.sh +++ b/admin-tools/check-3.6-3.10-versions.sh @@ -10,7 +10,7 @@ xasm_owd=$(pwd) # trap finish EXIT cd $(dirname ${BASH_SOURCE[0]}) -if ! source ./pyenv-3.8-3.10-versions ; then +if ! source ./pyenv-3.6-3.10-versions ; then exit $? fi diff --git a/admin-tools/pyenv-3.6-3.10-versions b/admin-tools/pyenv-3.6-3.10-versions index 83c4f4a..590ee80 100644 --- a/admin-tools/pyenv-3.6-3.10-versions +++ b/admin-tools/pyenv-3.6-3.10-versions @@ -7,4 +7,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then exit 1 fi -export PYVERSIONS='3.6 pypy3.6, 3.7 pypy3.7 3.8 pyston-2.3.5 pypy3.8 3.9 pypy3.9 3.10 pypy3.10' +export PYVERSIONS='3.6 pypy3.6 3.7 pypy3.7 3.8 pyston-2.3.5 pypy3.8 3.9 pypy3.9 3.10 pypy3.10' diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 647ad2d..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,63 +0,0 @@ -[build-system] -requires = [ - "setuptools", -] - -build-backend = "setuptools.build_meta" - -[project] -authors = [ - {name = "Rocky Bernstein", email = "rb@dustyfeet.com"}, -] - -name = "xasm" -description = "Cross-version Python bytecode assembler" -dependencies = [ - "click", - "xdis >= 6.1.1, < 6.3.0", -] -readme = "README.rst" -license = "GPL-2.0" -keywords = ["Python bytecode", "bytecode", "disassembler"] -classifiers = [ - "Development Status :: 4 - Beta", - "Intended Audience :: Developers", - "Programming Language :: Python", - "Topic :: Software Development :: Libraries :: Python Modules", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Topic :: Software Development :: Code Generators", -] -dynamic = ["version"] - -[project.urls] -Homepage = "https://github.com/rocky/python-xasm" -Downloads = "https://github.com/rocky/python-xasm/releases" - -[project.optional-dependencies] -dev = [ - "pre-commit", - "black", - "isort", - "pytest", -] - -[project.scripts] -python-cfg = "xasm.__main__:main" - -[tool.setuptools] -packages = [ - "xasm", -] - -[tool.setuptools.dynamic] -version = {attr = "xasm.version.__version__"} - -[tool.pyright] -include = ["xasm"] -# exclude = [] -ignore = ["dist", "docs", "tmp", ".cache"] diff --git a/setup.py b/setup.py index d74d4cc..97b6964 100755 --- a/setup.py +++ b/setup.py @@ -2,6 +2,43 @@ """Setup script for the 'xasm' distribution.""" -from setuptools import setup +from setuptools import find_packages, setup -setup() +from __pkginfo__ import ( + __version__, + author, + author_email, + classifiers, + install_requires, + license, + long_description, + modname, + py_modules, + short_desc, + tests_require, + web, + zip_safe, +) + +setup( + author=author, + author_email=author_email, + classifiers=classifiers, + description=short_desc, + license=license, + long_description=long_description, + long_description_content_type="text/x-rst", + name=modname, + packages=find_packages(), + py_modules=py_modules, + install_requires=install_requires, + entry_points=""" + [console_scripts] + pyc-xasm = xasm.xasm_cli:main + pyc-convert = xasm.pyc_convert:main + """, + tests_require=tests_require, + url=web, + version=__version__, + zip_safe=zip_safe, +) From 4dbd4d442e392bb23dbc5ebc557598215a420ce2 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Oct 2025 17:27:12 -0400 Subject: [PATCH 07/17] Better package testing --- admin-tools/install-all-3.6-3.10.sh | 33 ++++++++++++ admin-tools/install-all-newest.sh | 2 +- admin-tools/make-dist-3.6-3.10.sh | 80 +++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100755 admin-tools/install-all-3.6-3.10.sh create mode 100755 admin-tools/make-dist-3.6-3.10.sh diff --git a/admin-tools/install-all-3.6-3.10.sh b/admin-tools/install-all-3.6-3.10.sh new file mode 100755 index 0000000..2a655b3 --- /dev/null +++ b/admin-tools/install-all-3.6-3.10.sh @@ -0,0 +1,33 @@ +#!/usr/bin/bash +PACKAGE_MODULE=xasm +xasm_owd=$(pwd) +bs=${BASH_SOURCE[0]} +mydir=$(dirname $bs) +xasm_fulldir=$(readlink -f $mydir) +cd $xasm_fulldir +. ./checkout_common.sh + +pyenv_file="pyenv-3.6-3.10-versions" +if ! source $pyenv_file ; then + echo "Having trouble reading ${pyenv_file} version $(pwd)" + exit 1 +fi + +source ../${PACKAGE_MODULE}/version.py +if [[ ! $__version__ ]] ; then + echo "Something is wrong: __version__ should have been set." + exit 1 +fi + +cd ../dist/ + +install_file="xasm_36-${__version__}.tar.gz" +install_check_command="pyc-xasm --version" +for version in $PYVERSIONS; do + echo "*** Installing ${install_file} for Python ${version} ***" + echo $version + pyenv local $version + pip install $install_file + $install_check_command + echo "----" +done diff --git a/admin-tools/install-all-newest.sh b/admin-tools/install-all-newest.sh index fa27748..3921f62 100755 --- a/admin-tools/install-all-newest.sh +++ b/admin-tools/install-all-newest.sh @@ -22,7 +22,7 @@ fi cd ../dist/ install_check_command="xasm --version" -install_file="xasm-${__version__}.tar.gz" +install_file="pyc-xasm-${__version__}.tar.gz" for pyversion in $PYVERSIONS; do echo "*** Installing ${install_file} for Python ${pyversion} ***" pyenv local $pyversion diff --git a/admin-tools/make-dist-3.6-3.10.sh b/admin-tools/make-dist-3.6-3.10.sh new file mode 100755 index 0000000..8aed961 --- /dev/null +++ b/admin-tools/make-dist-3.6-3.10.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# The name Python's import uses. +# It is reflected in the directory structure. +PACKAGE_MODULE="xasm" + +# The name that PyPi sees this as. +# It is set in setup.py's name. +PACKAGE_NAME="xasm" + +# FIXME put some of the below in a common routine +function finish { + if [[ -n "$make_dist_xasm_36_owd" ]] then + cd $make_dist_xasm_36_owd + fi +} + +make_dist_xasm_36_owd=$(pwd) +cd $(dirname ${BASH_SOURCE[0]}) +trap finish EXIT + +if ! source ./pyenv-3.6-3.10-versions ; then + exit $? +fi + +if ! source ./setup-python-3.6.sh ; then + exit $? +fi + +cd .. + +source ${PACKAGE_MODULE}/version.py +if [[ ! -n $__version__ ]]; then + echo "Something is wrong: __version__ should have been set." + exit 1 +fi + +for pyversion in $PYVERSIONS; do + case ${pyversion:0:4} in + "graal" ) + echo "$pyversion - Graal does not get special packaging" + continue + ;; + "jyth" ) + echo "$pyversion - Jython does not get special packaging" + continue + ;; + "pypy" ) + echo "$pyversion - PyPy does not get special packaging" + continue + ;; + "pyst" ) + echo "$pyversion - Pyston does not get special packaging" + continue + ;; + esac + echo "*** Packaging ${PACKAGE_NAME} for version ${__version__} on Python ${pyversion} ***" + if ! pyenv local $pyversion ; then + exit $? + fi + # pip bdist_egg create too-general wheels. So + # we narrow that by moving the generated wheel. + + # Pick out first two number of version, e.g. 3.5.1 -> 35 + first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') + rm -fr build + python setup.py bdist_wheel + mv -v dist/${PACKAGE_MODULE}-${__version__}-{py3,py$first_two}-none-any.whl +done + +python ./setup.py sdist +tarball=dist/${PACKAGE_NAME}-${__version__}.tar.gz + +if [[ -f $tarball ]]; then + version_specific_tarball=dist/${PACKAGE_NAME}_36-${__version__}.tar.gz + mv -v $tarball $version_specific_tarball + twine check $version_specific_tarball + +fi +twine check dist/${PACKAGE_MODULE}-${__version__}-py3*.whl +finish From 0c3cb727b9df923aaf3e8342fe3b934e1739b73d Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Oct 2025 17:27:12 -0400 Subject: [PATCH 08/17] Better package testing --- admin-tools/install-all-3.6-3.10.sh | 33 ++++++++++++ admin-tools/install-all-newest.sh | 4 +- admin-tools/make-dist-3.6-3.10.sh | 80 +++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100755 admin-tools/install-all-3.6-3.10.sh create mode 100755 admin-tools/make-dist-3.6-3.10.sh diff --git a/admin-tools/install-all-3.6-3.10.sh b/admin-tools/install-all-3.6-3.10.sh new file mode 100755 index 0000000..e3dce2b --- /dev/null +++ b/admin-tools/install-all-3.6-3.10.sh @@ -0,0 +1,33 @@ +#!/usr/bin/bash +PACKAGE_MODULE=xasm +xasm_owd=$(pwd) +bs=${BASH_SOURCE[0]} +mydir=$(dirname $bs) +xasm_fulldir=$(readlink -f $mydir) +cd $xasm_fulldir +. ./checkout_common.sh + +pyenv_file="pyenv-3.6-3.10-versions" +if ! source $pyenv_file ; then + echo "Having trouble reading ${pyenv_file} version $(pwd)" + exit 1 +fi + +source ../${PACKAGE_MODULE}/version.py +if [[ ! $__version__ ]] ; then + echo "Something is wrong: __version__ should have been set." + exit 1 +fi + +cd ../dist/ + +install_file="xasm_36-${__version__}.tar.gz" +install_check_command="pyc-xasm --help" +for version in $PYVERSIONS; do + echo "*** Installing ${install_file} for Python ${version} ***" + echo $version + pyenv local $version + pip install $install_file + $install_check_command + echo "----" +done diff --git a/admin-tools/install-all-newest.sh b/admin-tools/install-all-newest.sh index fa27748..86f24d3 100755 --- a/admin-tools/install-all-newest.sh +++ b/admin-tools/install-all-newest.sh @@ -21,8 +21,8 @@ fi cd ../dist/ -install_check_command="xasm --version" -install_file="xasm-${__version__}.tar.gz" +install_check_command="xasm --help" +install_file="pyc-xasm-${__version__}.tar.gz" for pyversion in $PYVERSIONS; do echo "*** Installing ${install_file} for Python ${pyversion} ***" pyenv local $pyversion diff --git a/admin-tools/make-dist-3.6-3.10.sh b/admin-tools/make-dist-3.6-3.10.sh new file mode 100755 index 0000000..8aed961 --- /dev/null +++ b/admin-tools/make-dist-3.6-3.10.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# The name Python's import uses. +# It is reflected in the directory structure. +PACKAGE_MODULE="xasm" + +# The name that PyPi sees this as. +# It is set in setup.py's name. +PACKAGE_NAME="xasm" + +# FIXME put some of the below in a common routine +function finish { + if [[ -n "$make_dist_xasm_36_owd" ]] then + cd $make_dist_xasm_36_owd + fi +} + +make_dist_xasm_36_owd=$(pwd) +cd $(dirname ${BASH_SOURCE[0]}) +trap finish EXIT + +if ! source ./pyenv-3.6-3.10-versions ; then + exit $? +fi + +if ! source ./setup-python-3.6.sh ; then + exit $? +fi + +cd .. + +source ${PACKAGE_MODULE}/version.py +if [[ ! -n $__version__ ]]; then + echo "Something is wrong: __version__ should have been set." + exit 1 +fi + +for pyversion in $PYVERSIONS; do + case ${pyversion:0:4} in + "graal" ) + echo "$pyversion - Graal does not get special packaging" + continue + ;; + "jyth" ) + echo "$pyversion - Jython does not get special packaging" + continue + ;; + "pypy" ) + echo "$pyversion - PyPy does not get special packaging" + continue + ;; + "pyst" ) + echo "$pyversion - Pyston does not get special packaging" + continue + ;; + esac + echo "*** Packaging ${PACKAGE_NAME} for version ${__version__} on Python ${pyversion} ***" + if ! pyenv local $pyversion ; then + exit $? + fi + # pip bdist_egg create too-general wheels. So + # we narrow that by moving the generated wheel. + + # Pick out first two number of version, e.g. 3.5.1 -> 35 + first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') + rm -fr build + python setup.py bdist_wheel + mv -v dist/${PACKAGE_MODULE}-${__version__}-{py3,py$first_two}-none-any.whl +done + +python ./setup.py sdist +tarball=dist/${PACKAGE_NAME}-${__version__}.tar.gz + +if [[ -f $tarball ]]; then + version_specific_tarball=dist/${PACKAGE_NAME}_36-${__version__}.tar.gz + mv -v $tarball $version_specific_tarball + twine check $version_specific_tarball + +fi +twine check dist/${PACKAGE_MODULE}-${__version__}-py3*.whl +finish From b97328f03d596dd622ab5bee2b9483d1cc8bba64 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Oct 2025 20:31:05 -0400 Subject: [PATCH 09/17] Get ready for release 1.2.1 --- .gitignore | 1 + .pre-commit-config.yaml | 10 +- ChangeLog | 267 ++++++++++++++++++++++++++++++- ChangeLog-spell-corrected.diff | 52 ++++++ Makefile | 1 + NEWS.md | 18 +++ __pkginfo__.py | 4 +- pytest/test_assemble.py | 15 +- pytest/test_write_pyc.py | 4 +- test/columnize.py | 280 ++++++++++++++++++++------------- test/fn.py | 4 +- test/gcd.py | 15 +- test/run-test.py | 37 +++-- test/test_all.py | 8 +- xasm/assemble.py | 34 ++-- xasm/pyc_convert.py | 25 ++- xasm/version.py | 2 +- xasm/xasm_cli.py | 3 +- 18 files changed, 598 insertions(+), 182 deletions(-) create mode 100644 ChangeLog-spell-corrected.diff diff --git a/.gitignore b/.gitignore index 2c828d6..293539e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ /.mypy_cache /.pytest_cache /.python-version +/ChangeLog-spell-corrected /README.html /build /dist diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4cbf372..d5d5ca2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,11 +9,11 @@ repos: stages: [pre-commit] - id: end-of-file-fixer stages: [pre-commit] -- repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - stages: [pre-commit] +# - repo: https://github.com/pycqa/isort +# rev: 5.13.2 +# hooks: +# - id: isort +# stages: [pre-commit] - repo: https://github.com/psf/black rev: 23.12.1 hooks: diff --git a/ChangeLog b/ChangeLog index 895cbf6..4cd58fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,262 @@ +2025-10-13 rocky + + * xasm/version.py: Get ready for release 1.2.1 + +2025-10-13 rocky + + * README.rst, admin-tools/install-all-3.6-3.10.sh, + admin-tools/install-all-newest.sh, + admin-tools/make-dist-3.6-3.10.sh: Better package testing + +2025-10-13 rocky + + * admin-tools/install-all-3.8-3.10.sh, + admin-tools/install-all-newest.sh, + admin-tools/make-dist-3.8-3.10.sh, + admin-tools/pyenv-3.6-3.10-versions: Packaging, yet again + +2025-10-13 rocky + + * Makefile, admin-tools/merge-for-3.6.sh: Ever changing "standards" + +2025-10-13 rocky + + * admin-tools/check-newest-versions.sh: Correct admin scripts + +2025-10-13 rocky + + * README.rst, admin-tools/make-dist-newest.sh, pyproject.toml, + setup.py: Packaging + +2025-10-13 rocky + + * admin-tools/check-3.6-3.10-versions.sh, + admin-tools/check-newest-versions.sh, + admin-tools/checkout_common.sh, + admin-tools/install-all-3.8-3.10.sh, + admin-tools/install-all-newest.sh, + admin-tools/make-dist-3.8-3.10.sh, admin-tools/make-dist-newest.sh, + admin-tools/merge-for-3.6.sh, admin-tools/pyenv-3.6-3.10-versions, + admin-tools/pyenv-newest-versions, admin-tools/setup-master.sh, + admin-tools/setup-python-3.6.sh, admin-tools/test-versions.sh: Admin + crap + +2025-10-13 rocky + + * .github/workflows/{osx.yml => macos.yml}, + .github/workflows/ubuntu.yml, .pre-commit-config.yaml, + requirements.txt, xasm/assemble.py: Misc fixes + +2025-06-21 rocky + + * xasm/assemble.py: Correct bug respecing create_code API Fixes #24 + +2025-02-18 rocky + + * requirements.txt: Make dependabot happy + +2024-12-24 rocky + + * .pre-commit-config.yaml, requirements.txt: Make dependabot happy + +2024-09-10 rocky + + * requirements.txt: Silenced dependabot + +2024-07-03 rocky + + * .github/ISSUE_TEMPLATE/bug-report.md, + .github/ISSUE_TEMPLATE/config.yml, + .github/ISSUE_TEMPLATE/feature-request.md, HOW-TO-USE.rst, + README.rst: Correct spelling typos + +2024-07-02 rocky + + * HOW-TO-USE.rst, README.rst: Update README.rst + +2024-07-02 rocky + + * HOW-TO-USE.rst, xasm/assemble.py, xasm/pyc_convert.py: More + explicit comments and ... add ## comments, and document better module and method information + +2024-06-23 rocky + + * xasm/assemble.py, xasm/pyc_convert.py: bug fixes... * decode_linotab() -> decode_lineno_tab_old to make it clear that + this routine works for version before 3.10 * last instruction can be RERAISE or RASE_VARARGS in addition to RETURN_VALUE * Avoid using asm.code.to_native() for now, since there are bugs + +2024-06-23 R. Bernstein + + * HOW-TO-USE.rst: Update HOW-TO-USE.rst Spell check and update information + +2024-06-23 R. Bernstein + + * HOW-TO-USE.rst: Update HOW-TO-USE.rst + +2024-06-23 R. Bernstein + + * HOW-TO-USE.rst: Update HOW-TO-USE.rst + +2024-06-23 R. Bernstein + + * HOW-TO-USE.rst: Update HOW-TO-USE.rst + +2024-06-15 rocky + + * xasm/assemble.py: Misc tweaks and bug fixes... * Handle numeric labels better * Adjust field name co_linetable for 3.10+ * Warn if duplicate line number seen and < 3.10 + +2024-06-04 rocky + + * .github/workflows/osx.yml, .github/workflows/ubuntu.yml, + .github/workflows/windows.yml: CI - need latest xdis for testing + +2024-06-04 rocky + + * pytest/test_assemble.py, xasm/assemble.py: Go over EXTENDED_ARG + creation in bytecode + +2024-06-03 rocky + + * xasm/assemble.py: remove unused import + +2024-06-03 rocky + + * xasm/assemble.py, xasm/xasm_cli.py: Compute EXTENDED_ARG better; + fix a typo + +2024-06-03 rocky + + * xasm/assemble.py: Improve offset label handling and .. ignore EXTENDED_ARG + +2024-06-03 rocky + + * xasm/assemble.py: Fix two misfeatures... 1. If Python bytecode is not set, complain and exit 2. Detect and handle line numbers on instructions + +2024-05-26 rocky + + * xasm/assemble.py: Check that operand values are in range + +2024-05-26 rocky + + * xasm/write_pyc.py, xasm/xasm_cli.py: Track and report errors in + return code better + +2024-05-26 rocky + + * .editorconfig: Typo + +2024-05-26 rocky + + * xasm/assemble.py: Tweak missing return value error + +2024-05-26 rocky + + * pytest/test_write_pyc.py: Skip a pytest on windows CI + +2024-05-26 rocky + + * .github/workflows/windows.yml, __pkginfo__.py, requirements.txt, + setup.py: Another attempt to get CI actions working + +2024-05-26 rocky + + * .github/workflows/osx.yml, .github/workflows/ubuntu.yml, + .github/workflows/windows.yml: Try Workflows actions + +2024-05-26 rocky + + * test/TODO.md: Add a TODO + +2024-05-26 rocky + + * test/tasm-3.10-bad.pyasm, test/tasm-3.10.pyasm, xasm/assemble.py: + Add a check for last instruction being a "return" + +2024-05-22 rocky + + * xasm/assemble.py: Offset in 3.10+ need to be divided by two + +2024-05-20 rocky + + * xasm/xasm_cli.py: Tweak asm file path + +2024-02-20 rocky + + * requirements.txt: Keep dependabot happy + +2024-01-10 rocky + + * requirements.txt: Bump cryptography to silence Depedabot + +2024-01-10 rocky + + * .pre-commit-config.yaml, xasm/assemble.py, xasm/pyc_convert.py, + xasm/xasm_cli.py: convert % to f-strings + +2024-01-09 rocky + + * pytest/test_write_pyc.py, requirements.txt: Update requirements as + recommended by dependabot Also comment out a test where xdis marshal is broken. + +2023-12-17 R. Bernstein + + * : Merge pull request #21 from rocky/lint Some lint found + +2023-10-23 rocky + + * .gitignore, __pkginfo__.py, requirements.txt, xasm/.gitignore, + xasm/assemble.py, xasm/pyc_convert.py, xasm/xasm_cli.py: Misc lint + +2023-09-18 rocky + + * xasm/assemble.py: version -> version_tuple fixes + +2023-09-18 rocky + + * .gitignore, admin-tools/pyenv-newest-versions, + admin-tools/setup-master.sh, test/.gitignore: Bump testing versions + +2022-12-02 rocky + + * xasm/assemble.py: Pycharm lint + +2022-12-02 rocky + + * xasm/assemble.py: Add a more detailed assert message... about the header. + +2022-12-02 rocky + + * xasm/version.py: Bump version to development version + +2022-10-17 rocky + + * xasm/assemble.py, xasm/write_pyc.py: Remove debug statement. Fixes #17 Also, add msg when we can't dump a code object + +2022-08-22 rocky + + * xasm/assemble.py, xasm/write_pyc.py: Fix a couple of small bugs + +2022-06-16 rocky + + * xasm/assemble.py: Detect native code objects in constants + +2022-04-02 R. Bernstein + + * : Merge pull request #15 from + Svenskithesource/Svenskithesource-patch-2 Fix empty append call + +2022-03-05 R. Bernstein + + * : Merge pull request #13 from Svenskithesource/patch-1 Typo + +2021-12-04 rocky + + * xasm/assemble.py: wrong variable python_version -> version Fixes #11 + 2021-11-07 rocky * ChangeLog, NEWS.md, admin-tools/check-versions.sh, - admin-tools/pyenv-versions, xasm/version.py: Get ready for release - 1.2.0 + admin-tools/make-dist.sh, admin-tools/pyenv-versions, setup.cfg, + xasm/version.py: Get ready for release 1.2.0 2021-11-07 rocky @@ -10,7 +264,7 @@ 2021-11-07 rocky - * admin-tools/pyenv-versions, admin-tools/setup-master.sh: + * admin-tools/pyenv-versions, admin-tools/setup-master.sh: Administrivia 2021-11-05 rocky @@ -62,7 +316,7 @@ * ChangeLog, NEWS.md, __pkginfo__.py, admin-tools/how-to-make-a-release.md, admin-tools/pyenv-versions, - setup.py, xasm/__init__.py, xasm/pyc_convert.py, xasm/version.py: + setup.py, xasm/__init__.py, xasm/pyc_convert.py, xasm/version.py: Get ready for release 1.1.1 2020-07-02 rocky @@ -129,7 +383,7 @@ * Makefile, __pkginfo__.py, admin-tools/how-to-make-a-release.md, admin-tools/pyenv-versions, pytest/.gitignore, pytest/test_write_pyc.py, test/test_all.py, xasm/.gitignore, - xasm/assemble.py, xasm/misc.py, xasm/write_pyc.py, xasm/xasm_cli.py: + xasm/assemble.py, xasm/misc.py, xasm/write_pyc.py, xasm/xasm_cli.py: Revise for new xdis. Add Better write_pyc() fn 2019-11-06 rocky @@ -463,7 +717,7 @@ 2017-07-04 rocky * test/gcd-2.7.pyasm, xasm/assemble.py: More proper label handling All non-int labels are absolute Labels as an operand don't and shouldn't have the trailing ':'. - pydisasm doen't add that Start moving toward xdis enhanced ability to work with Python code + pydisasm doesn't add that. Start moving toward xdis's enhanced ability to work with Python code more interchangeably between Python 2 and 3. 2017-07-03 rocky @@ -547,4 +801,3 @@ 2017-06-26 rocky * Assembler first step - diff --git a/ChangeLog-spell-corrected.diff b/ChangeLog-spell-corrected.diff new file mode 100644 index 0000000..2c98e8a --- /dev/null +++ b/ChangeLog-spell-corrected.diff @@ -0,0 +1,52 @@ +--- ChangeLog 2025-10-13 20:32:16.800140934 -0400 ++++ ChangeLog-spell-corrected 2025-10-13 20:31:50.631953303 -0400 +@@ -168,7 +168,7 @@ + + 2024-05-26 rocky + +- * test/tasm-3.10-bad.pyasm, test/tasm-3.10.pyasm, xasm/assemble.py: ++ * test/tasm-3.10-bad.pyasm, test/tasm-3.10.pyasm, xasm/assemble.py: + Add a check for last instruction being a "return" + + 2024-05-22 rocky +@@ -264,7 +264,7 @@ + + 2021-11-07 rocky + +- * admin-tools/pyenv-versions, admin-tools/setup-master.sh: ++ * admin-tools/pyenv-versions, admin-tools/setup-master.sh: + Administrivia + + 2021-11-05 rocky +@@ -316,7 +316,7 @@ + + * ChangeLog, NEWS.md, __pkginfo__.py, + admin-tools/how-to-make-a-release.md, admin-tools/pyenv-versions, +- setup.py, xasm/__init__.py, xasm/pyc_convert.py, xasm/version.py: ++ setup.py, xasm/__init__.py, xasm/pyc_convert.py, xasm/version.py: + Get ready for release 1.1.1 + + 2020-07-02 rocky +@@ -383,7 +383,7 @@ + * Makefile, __pkginfo__.py, admin-tools/how-to-make-a-release.md, + admin-tools/pyenv-versions, pytest/.gitignore, + pytest/test_write_pyc.py, test/test_all.py, xasm/.gitignore, +- xasm/assemble.py, xasm/misc.py, xasm/write_pyc.py, xasm/xasm_cli.py: ++ xasm/assemble.py, xasm/misc.py, xasm/write_pyc.py, xasm/xasm_cli.py: + Revise for new xdis. Add Better write_pyc() fn + + 2019-11-06 rocky +@@ -717,7 +717,7 @@ + 2017-07-04 rocky + + * test/gcd-2.7.pyasm, xasm/assemble.py: More proper label handling All non-int labels are absolute Labels as an operand don't and shouldn't have the trailing ':'. +- pydisasm doen't add that Start moving toward xdis enhanced ability to work with Python code ++ pydisasm doesn't add that. Start moving toward xdis's enhanced ability to work with Python code + more interchangeably between Python 2 and 3. + + 2017-07-03 rocky +@@ -801,4 +801,3 @@ + 2017-06-26 rocky + + * Assembler first step +- diff --git a/Makefile b/Makefile index 532301c..44968ee 100644 --- a/Makefile +++ b/Makefile @@ -27,3 +27,4 @@ rmChangeLog: #: Create a ChangeLog from git via git log and git2cl ChangeLog: rmChangeLog git log --pretty --numstat --summary | $(GIT2CL) >$@ + patch ChangeLog < ChangeLog-spell-corrected.diff diff --git a/NEWS.md b/NEWS.md index 8c07eca..ea9e2b8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,21 @@ +1.2.1 2025-10-13 +---------------- + +* Repackage for Python 3.11 and poetry. I can't describe what thrill it gives me to have to do this every few years. +* Correct bug respecting `create_code` API Fixes #24 +* More explicit comments. Add some `##` comments. Document module and method information better. +* `decode_linotab()` is now `decode_lineno_tab_old` to make it clear that this routine works for version before 3.10. +* Avoid using `asm.code.to_native()` for now, since there are bugs. +* Handle numeric labels better. +* Adjust field name `co_linetable` for bytecode after 3.10. +* Warn if duplicate line numbers seen and the assembler is before bytecode for 3.10 +* Improve `EXTENDED_ARG` handling and creation. +* If Python bytecode is not set, complain and exit. +* Detect and handle line numbers on instructions +* Add a check for last instruction being either a `RETURN_VALUE`, or `RERAISE`, or `RAISE_VARARGS` +* Offsets in bytecode for 3.10 need to be divided by two +* Lint code a little + 1.2.0 2021-11-07 ---------------- diff --git a/__pkginfo__.py b/__pkginfo__.py index 134348b..478c9f9 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -54,7 +54,7 @@ import os.path as osp -def get_srcdir(): +def get_srcdir() -> str: filename = osp.normcase(osp.dirname(osp.abspath(__file__))) return osp.realpath(filename) @@ -62,7 +62,7 @@ def get_srcdir(): srcdir = get_srcdir() -def read(*rnames): +def read(*rnames) -> str: return open(osp.join(srcdir, *rnames)).read() diff --git a/pytest/test_assemble.py b/pytest/test_assemble.py index b762263..d67646e 100644 --- a/pytest/test_assemble.py +++ b/pytest/test_assemble.py @@ -2,15 +2,20 @@ Test xasm.assemble code """ -from xdis.opcodes import (opcode_15, opcode_27, opcode_35, opcode_36, - opcode_36pypy, opcode_312) +from xdis.opcodes import ( + opcode_15, + opcode_27, + opcode_35, + opcode_36, + opcode_36pypy, + opcode_312, +) from xasm.assemble import append_operand -def test_append_operand(): - - def check_one(expected_bytecode_len: int, operand_value): +def test_append_operand() -> None: + def check_one(expected_bytecode_len: int, operand_value: int) -> None: bytecode = [] append_operand( bytecode, diff --git a/pytest/test_write_pyc.py b/pytest/test_write_pyc.py index 776bf08..3a9e96e 100644 --- a/pytest/test_write_pyc.py +++ b/pytest/test_write_pyc.py @@ -9,7 +9,7 @@ from xasm.write_pyc import write_pycfile -def get_srcdir(): +def get_srcdir() -> str: filename = osp.normcase(os.path.dirname(__file__)) return osp.realpath(filename) @@ -23,7 +23,7 @@ def get_srcdir(): reason="test skipped because Python 2.x has problems creating Python 3.x files", ) @pytest.mark.skipif(sys.platform in ("win32",), reason="Test does not work on Windows?") -def test_roundtrip3(): +def test_roundtrip3() -> None: fp = NamedTemporaryFile(mode="wb+", suffix=".pyc", prefix="test_pyc-", delete=False) orig_path = "testdata/test_pyc.pyc" version, timestamp, magic_int, co, is_pypy, source_size, sip_hash = load_module( diff --git a/test/columnize.py b/test/columnize.py index 6f1e038..aa3f806 100644 --- a/test/columnize.py +++ b/test/columnize.py @@ -7,12 +7,12 @@ import os -def computed_displaywidth(): - '''Figure out a reasonable default with. Use os.environ['COLUMNS'] if possible, +def computed_displaywidth() -> int: + """Figure out a reasonable default with. Use os.environ['COLUMNS'] if possible, and failing that use 80. - ''' + """ try: - width = int(os.environ['COLUMNS']) + width = int(os.environ["COLUMNS"]) except (KeyError, ValueError): width = 80 @@ -20,27 +20,33 @@ def computed_displaywidth(): default_opts = { - 'arrange_array' : False, # Check if file has changed since last time - 'arrange_vertical' : True, - 'array_prefix' : '', - 'array_suffix' : '', - 'colfmt' : None, - 'colsep' : ' ', - 'displaywidth' : computed_displaywidth(), - 'lineprefix' : '', - 'linesuffix' : "\n", - 'ljust' : None, - 'term_adjust' : False - } + "arrange_array": False, # Check if file has changed since last time + "arrange_vertical": True, + "array_prefix": "", + "array_suffix": "", + "colfmt": None, + "colsep": " ", + "displaywidth": computed_displaywidth(), + "lineprefix": "", + "linesuffix": "\n", + "ljust": None, + "term_adjust": False, +} -def get_option(key, options): +def get_option(key: str, options): return options.get(key, default_opts.get(key)) -def columnize(array, displaywidth=80, colsep = ' ', - arrange_vertical=True, ljust=True, lineprefix='', - opts={}): +def columnize( + array, + displaywidth: int = 80, + colsep: str = " ", + arrange_vertical=True, + ljust=True, + lineprefix="", + opts={}, +): """Return a list of strings as a compact set of columns arranged horizontally or vertically. @@ -60,38 +66,37 @@ def columnize(array, displaywidth=80, colsep = ' ', set false, consecutive items will go across, left to right, top to bottom.""" if not isinstance(array, (list, tuple)): - raise TypeError(( - 'array needs to be an instance of a list or a tuple')) + raise TypeError(("array needs to be an instance of a list or a tuple")) o = {} if len(opts.keys()) > 0: for key in default_opts.keys(): o[key] = get_option(key, opts) pass - if o['arrange_array']: - o['array_prefix'] = '[' - o['lineprefix'] = ' ' - o['linesuffix'] = ",\n" - o['array_suffix'] = "]\n" - o['colsep'] = ', ' - o['arrange_vertical'] = False + if o["arrange_array"]: + o["array_prefix"] = "[" + o["lineprefix"] = " " + o["linesuffix"] = ",\n" + o["array_suffix"] = "]\n" + o["colsep"] = ", " + o["arrange_vertical"] = False pass else: o = default_opts.copy() - o['displaywidth'] = displaywidth - o['colsep'] = colsep - o['arrange_vertical'] = arrange_vertical - o['ljust'] = ljust - o['lineprefix'] = lineprefix + o["displaywidth"] = displaywidth + o["colsep"] = colsep + o["arrange_vertical"] = arrange_vertical + o["ljust"] = ljust + o["lineprefix"] = lineprefix pass # if o['ljust'] is None: # o['ljust'] = !(list.all?{|datum| datum.kind_of?(Numeric)}) # pass - if o['colfmt']: - array = [(o['colfmt'] % i) for i in array] + if o["colfmt"]: + array = [(o["colfmt"] % i) for i in array] else: array = [str(i) for i in array] pass @@ -101,43 +106,43 @@ def columnize(array, displaywidth=80, colsep = ' ', if 0 == size: return "\n" elif size == 1: - return '%s%s%s\n' % (o['array_prefix'], str(array[0]), - o['array_suffix']) + return "%s%s%s\n" % (o["array_prefix"], str(array[0]), o["array_suffix"]) - o['displaywidth'] = max(4, o['displaywidth'] - len(o['lineprefix'])) - if o['arrange_vertical']: - array_index = lambda nrows, row, col: nrows*col + row + o["displaywidth"] = max(4, o["displaywidth"] - len(o["lineprefix"])) + if o["arrange_vertical"]: + array_index = lambda nrows, row, col: nrows * col + row # Try every row count from 1 upwards - for nrows in range(1, size+1): - ncols = (size+nrows-1) // nrows + for nrows in range(1, size + 1): + ncols = (size + nrows - 1) // nrows colwidths = [] - totwidth = -len(o['colsep']) + totwidth = -len(o["colsep"]) for col in range(ncols): # get max column width for this column colwidth = 0 for row in range(nrows): i = array_index(nrows, row, col) - if i >= size: break + if i >= size: + break x = array[i] colwidth = max(colwidth, len(x)) pass colwidths.append(colwidth) - totwidth += colwidth + len(o['colsep']) - if totwidth > o['displaywidth']: + totwidth += colwidth + len(o["colsep"]) + if totwidth > o["displaywidth"]: break pass - if totwidth <= o['displaywidth']: + if totwidth <= o["displaywidth"]: break pass # The smallest number of rows computed and the # max widths for each column has been obtained. # Now we just have to format each of the # rows. - s = '' + s = "" for row in range(nrows): texts = [] for col in range(ncols): - i = row + nrows*col + i = row + nrows * col if i >= size: x = "" else: @@ -146,149 +151,204 @@ def columnize(array, displaywidth=80, colsep = ' ', while texts and not texts[-1]: del texts[-1] for col in range(len(texts)): - if o['ljust']: + if o["ljust"]: texts[col] = texts[col].ljust(colwidths[col]) else: texts[col] = texts[col].rjust(colwidths[col]) pass pass - s += "%s%s%s" % (o['lineprefix'], str(o['colsep'].join(texts)), - o['linesuffix']) + s += "%s%s%s" % ( + o["lineprefix"], + str(o["colsep"].join(texts)), + o["linesuffix"], + ) pass return s else: - array_index = lambda ncols, row, col: ncols*(row-1) + col + array_index = lambda ncols, row, col: ncols * (row - 1) + col # Try every column count from size downwards colwidths = [] for ncols in range(size, 0, -1): # Try every row count from 1 upwards - min_rows = (size+ncols-1) // ncols - nrows = min_rows -1 + min_rows = (size + ncols - 1) // ncols + nrows = min_rows - 1 while nrows < size: nrows += 1 rounded_size = nrows * ncols colwidths = [] - totwidth = -len(o['colsep']) + totwidth = -len(o["colsep"]) for col in range(ncols): # get max column width for this column - colwidth = 0 - for row in range(1, nrows+1): + colwidth = 0 + for row in range(1, nrows + 1): i = array_index(ncols, row, col) - if i >= rounded_size: break + if i >= rounded_size: + break elif i < size: x = array[i] colwidth = max(colwidth, len(x)) pass pass colwidths.append(colwidth) - totwidth += colwidth + len(o['colsep']) - if totwidth >= o['displaywidth']: + totwidth += colwidth + len(o["colsep"]) + if totwidth >= o["displaywidth"]: break pass - if totwidth <= o['displaywidth'] and i >= rounded_size-1: + if totwidth <= o["displaywidth"] and i >= rounded_size - 1: # Found the right nrows and ncols # print "right nrows and ncols" - nrows = row + nrows = row break - elif totwidth >= o['displaywidth']: + elif totwidth >= o["displaywidth"]: # print "reduce ncols", ncols # Need to reduce ncols break pass - if totwidth <= o['displaywidth'] and i >= rounded_size-1: + if totwidth <= o["displaywidth"] and i >= rounded_size - 1: break pass # The smallest number of rows computed and the # max widths for each column has been obtained. # Now we just have to format each of the # rows. - s = '' - if len(o['array_prefix']) != 0: - prefix = o['array_prefix'] + s = "" + if len(o["array_prefix"]) != 0: + prefix = o["array_prefix"] else: - prefix = o['lineprefix'] + prefix = o["lineprefix"] pass - for row in range(1, nrows+1): + for row in range(1, nrows + 1): texts = [] for col in range(ncols): i = array_index(ncols, row, col) if i >= size: break - else: x = array[i] + else: + x = array[i] texts.append(x) pass for col in range(len(texts)): - if o['ljust']: + if o["ljust"]: texts[col] = texts[col].ljust(colwidths[col]) else: texts[col] = texts[col].rjust(colwidths[col]) pass pass - s += "%s%s%s" % (prefix, str(o['colsep'].join(texts)), - o['linesuffix']) - prefix = o['lineprefix'] + s += "%s%s%s" % (prefix, str(o["colsep"].join(texts)), o["linesuffix"]) + prefix = o["lineprefix"] pass - if o['arrange_array']: - colsep = o['colsep'].rstrip() - colsep_pos = -(len(colsep)+1) + if o["arrange_array"]: + colsep = o["colsep"].rstrip() + colsep_pos = -(len(colsep) + 1) if s[colsep_pos:] == colsep + "\n": - s = s[:colsep_pos] + o['array_suffix'] + "\n" + s = s[:colsep_pos] + o["array_suffix"] + "\n" pass pass else: - s += o['array_suffix'] + s += o["array_suffix"] pass return s pass + # Demo it -if __name__=='__main__': +if __name__ == "__main__": # from trepan.api import debug # debug() - print(columnize(list(range(12)), - opts={'displaywidth':6, 'arrange_array':True})) - print(columnize(list(range(12)), - opts={'displaywidth':10, 'arrange_array':True})) - for t in ((4, 4,), (4, 7), (100, 80)): + print(columnize(list(range(12)), opts={"displaywidth": 6, "arrange_array": True})) + print(columnize(list(range(12)), opts={"displaywidth": 10, "arrange_array": True})) + for t in ( + ( + 4, + 4, + ), + (4, 7), + (100, 80), + ): width = t[1] data = [str(i) for i in range(t[0])] options = {} - for t2 in ((False, 'horizontal',), (True, 'vertical',)): + for t2 in ( + ( + False, + "horizontal", + ), + ( + True, + "vertical", + ), + ): print("Width: %d, direction: %s" % (width, t2[1])) - options['displaywidth'] = width - options['arrange_vertical'] = t2[0] + options["displaywidth"] = width + options["arrange_vertical"] = t2[0] print(columnize(data, opts=options)) pass pass print(columnize([])) - print(columnize(["a", '2', "c"], 10, ', ')) + print(columnize(["a", "2", "c"], 10, ", ")) print(columnize(["oneitem"])) - print(columnize(("one", "two", "three",))) + print( + columnize( + ( + "one", + "two", + "three", + ) + ) + ) data = ( - "one", "two", "three", - "for", "five", "six", - "seven", "eight", "nine", - "ten", "eleven", "twelve", - "thirteen", "fourteen", "fifteen", - "sixteen", "seventeen", "eightteen", - "nineteen", "twenty", "twentyone", - "twentytwo", "twentythree", "twentyfour", - "twentyfive","twentysix", "twentyseven",) + "one", + "two", + "three", + "for", + "five", + "six", + "seven", + "eight", + "nine", + "ten", + "eleven", + "twelve", + "thirteen", + "fourteen", + "fifteen", + "sixteen", + "seventeen", + "eightteen", + "nineteen", + "twenty", + "twentyone", + "twentytwo", + "twentythree", + "twentyfour", + "twentyfive", + "twentysix", + "twentyseven", + ) print(columnize(data)) print(columnize(data, arrange_vertical=False)) data = [str(i) for i in range(55)] - print(columnize(data, opts={'displaywidth':39, 'arrange_array':True})) - print(columnize(data, displaywidth=39, ljust=False, - colsep=', ', lineprefix=' ')) - print(columnize(data, displaywidth=39, ljust=False, - arrange_vertical=False, - colsep = ', ')) + print(columnize(data, opts={"displaywidth": 39, "arrange_array": True})) + print(columnize(data, displaywidth=39, ljust=False, colsep=", ", lineprefix=" ")) + print( + columnize( + data, displaywidth=39, ljust=False, arrange_vertical=False, colsep=", " + ) + ) - print(columnize(data, displaywidth=39, ljust=False, - arrange_vertical=False, - colsep = ', ', lineprefix=' ')) + print( + columnize( + data, + displaywidth=39, + ljust=False, + arrange_vertical=False, + colsep=", ", + lineprefix=" ", + ) + ) import sys + try: print(columnize(5)) except TypeError: diff --git a/test/fn.py b/test/fn.py index 35da334..2565e7b 100644 --- a/test/fn.py +++ b/test/fn.py @@ -1,3 +1,5 @@ -def five(): +def five() -> int: return 5 + + print(five()) diff --git a/test/gcd.py b/test/gcd.py index 263710c..e7bb257 100644 --- a/test/gcd.py +++ b/test/gcd.py @@ -8,21 +8,24 @@ of parameters. """ -def gcd(a,b): - """ GCD. We assume positive numbers""" + + +def gcd(a: int, b: int): + """GCD. We assume positive numbers""" # Make: a <= b if a > b: - (a, b) = (b, a) - pass + (a, b) = (b, a) + pass if a <= 0: return None if a == 1 or a == b: return a - return gcd(b-a, a) + return gcd(b - a, a) + -if __name__=='__main__': +if __name__ == "__main__": a, b = 3, 5 print("The GCD of %d and %d is %d" % (a, b, gcd(a, b))) pass diff --git a/test/run-test.py b/test/run-test.py index b62edcd..b1cf727 100755 --- a/test/run-test.py +++ b/test/run-test.py @@ -1,12 +1,19 @@ #!/usr/bin/env python -import click, os, py_compile, sys +import os +import py_compile +import sys + +import click + @click.command() -@click.option('--compile/--no-compile', default=None) -@click.option('--disasm/--no-disasm', default=True) -@click.option('--asm/--no-asm', default=None) -@click.argument('files', nargs=-1, type=click.Path(exists=True, readable=True), required=True) -def main(compile, disasm, asm, files): +@click.option("--compile/--no-compile", default=None) +@click.option("--disasm/--no-disasm", default=True) +@click.option("--asm/--no-asm", default=None) +@click.argument( + "files", nargs=-1, type=click.Path(exists=True, readable=True), required=True +) +def main(compile: list[str], disasm, asm, files) -> None: """ Byte-compile, get assembly listing, assemble, and run a Python program """ @@ -18,17 +25,16 @@ def main(compile, disasm, asm, files): PY_VERSION = sys.version_info[0] + (sys.version_info[1] / 10.0) for path in files: - if compile is None: - do_compile = path.endswith('.py') + do_compile = path.endswith(".py") else: do_compile = compile and disasm if do_compile: if asm is None: asm = True - if path.endswith('.py'): - basename = path[:-len('.py')] + if path.endswith(".py"): + basename = path[: -len(".py")] else: basename = path @@ -40,8 +46,8 @@ def main(compile, disasm, asm, files): else: bytecode = path - have_disasm_path = path.endswith('.pyc') or path.endswith('.pyo') - have_asm_path = path.endswith('.pyasm') + have_disasm_path = path.endswith(".pyc") or path.endswith(".pyo") + have_asm_path = path.endswith(".pyasm") if disasm is None: do_disasm = have_disasm_path else: @@ -53,7 +59,7 @@ def main(compile, disasm, asm, files): if have_disasm_path: produced_bytecode = path bytecode = path - basename = path[:-len('.pyo')] + basename = path[: -len(".pyo")] asm_file = "%s.pyasm" % basename else: asm_file = "%s.pyasm" % ver_prefix @@ -63,7 +69,7 @@ def main(compile, disasm, asm, files): os.system(cmd) if have_asm_path: - basename = path[:-len('.pyasm')] + basename = path[: -len(".pyasm")] ver_prefix = basename asm_file = path produced_bytecode = "%s.pyc" % ver_prefix @@ -81,5 +87,6 @@ def main(compile, disasm, asm, files): print(cmd) os.system(cmd) -if __name__ == '__main__': + +if __name__ == "__main__": main(sys.argv[1:]) diff --git a/test/test_all.py b/test/test_all.py index 0f36553..9c3bf90 100644 --- a/test/test_all.py +++ b/test/test_all.py @@ -1,15 +1,19 @@ #!/usr/bin/env python -import os, subprocess, sys +import os import os.path as osp +import subprocess +import sys os.chdir(osp.dirname(__file__)) -def test_xasm(): + +def test_xasm() -> None: python_interp = sys.executable for asm in "tasm fn gcd columnize".split(): print("Testing %s" % asm) assert subprocess.call((python_interp, "./%s.py" % asm)) == 0 + if __name__ == "__main__": test_xasm() diff --git a/xasm/assemble.py b/xasm/assemble.py index 6a0aad7..3dce73c 100644 --- a/xasm/assemble.py +++ b/xasm/assemble.py @@ -1,7 +1,7 @@ #!/usr/bin/env python import ast import re -from typing import Optional +from typing import List, Optional import xdis from xdis import get_opcode, load_module @@ -21,7 +21,7 @@ def __repr__(self) -> str: s = "%4d: " % self.line_no else: s = " " * 6 - s += "%-15s" % self.opname + s += f"{self.opname:15}" if self.arg is not None: s += f"\t{self.arg}" return s @@ -29,7 +29,7 @@ def __repr__(self) -> str: pass -def is_int(s) -> bool: +def is_int(s: int | str | None) -> bool: try: int(s) return True @@ -41,7 +41,7 @@ def match_lineno(s: str) -> Optional[re.Match]: return re.match(r"^\d+:", s) -def get_opname_operand(opc, fields): +def get_opname_operand(opc, fields: List[str]): assert len(fields) > 0 opname = fields[0] if opc.opmap[opname] < opc.HAVE_ARGUMENT: @@ -63,7 +63,7 @@ def get_opname_operand(opc, fields): class Assembler: - def __init__(self, python_version, is_pypy): + def __init__(self, python_version, is_pypy) -> None: self.opc = get_opcode(python_version, is_pypy) self.code_list = [] self.codes = [] # FIXME use a better name @@ -76,7 +76,7 @@ def __init__(self, python_version, is_pypy): self.code = None self.siphash = None - def code_init(self, python_version=None): + def code_init(self, python_version=None) -> None: if self.python_version is None and python_version: self.python_version = python_version @@ -102,19 +102,19 @@ def code_init(self, python_version=None): self.code.instructions = [] - def update_lists(self, co, label, backpatch): + def update_lists(self, co, label, backpatch) -> None: self.code_list.append(co) self.codes.append(self.code) self.label.append(label) self.backpatch.append(backpatch) - def print_instructions(self): + def print_instructions(self) -> None: for inst in self.code.instructions: if inst.line_no: print() print(inst) - def warn(self, mess: str): + def warn(self, mess: str) -> None: """ Print an error message and record that we warned, unless we have already errored. """ @@ -122,7 +122,7 @@ def warn(self, mess: str): if self.status != "errored": self.status = "warning" - def err(self, mess: str): + def err(self, mess: str) -> None: """ Print an error message and record that we errored. """ @@ -130,7 +130,7 @@ def err(self, mess: str): self.status = "errored" -def asm_file(path): +def asm_file(path) -> Assembler | None: offset = 0 methods = {} method_name = None @@ -413,7 +413,7 @@ def asm_file(path): return asm -def member(fields, match_value): +def member(fields, match_value) -> int: for i, v in enumerate(fields): if v == match_value and type(v) == type(match_value): return i @@ -421,7 +421,7 @@ def member(fields, match_value): return -1 -def update_code_field(field_name, value, inst, opc): +def update_code_field(field_name: str, value, inst, opc) -> None: field_values = getattr(opc, field_name) # Can't use "in" because True == 1 and False == 0 # if value in l: @@ -433,7 +433,7 @@ def update_code_field(field_name, value, inst, opc): field_values.append(value) -def update_code_tuple_field(field_name, code, lines, i): +def update_code_tuple_field(field_name: str, code, lines: List[str], i: int): count = 0 while i < len(lines): line = lines[i] @@ -454,12 +454,12 @@ def update_code_tuple_field(field_name, code, lines, i): return i -def err(msg, inst, i): +def err(msg: str, inst, i: int): msg += ". Instruction %d:\n%s" % (i, inst) raise RuntimeError(msg) -def warn(mess: str): +def warn(mess: str) -> None: """ Print an error message and record that we warned. """ @@ -562,7 +562,7 @@ def is_code_ok(asm: Assembler) -> bool: def append_operand( bytecode: list, arg_value, extended_arg_shift, arg_max_value, extended_arg_op -): +) -> None: """ Write instruction operand adding EXTENDED_ARG instructions when necessary. diff --git a/xasm/pyc_convert.py b/xasm/pyc_convert.py index 958b766..db46ccd 100755 --- a/xasm/pyc_convert.py +++ b/xasm/pyc_convert.py @@ -13,13 +13,18 @@ from xdis.magics import magics from xdis.opcodes import opcode_27, opcode_33 -from xasm.assemble import (Assembler, Instruction, asm_file, create_code, - decode_lineno_tab_old) +from xasm.assemble import ( + Assembler, + Instruction, + asm_file, + create_code, + decode_lineno_tab_old, +) from xasm.version import __version__ from xasm.write_pyc import write_pycfile -def add_credit(asm, src_version, dest_version): +def add_credit(asm, src_version, dest_version) -> None: stamp = "Converted from Python %s to %s by %s version %s" % ( src_version, dest_version, @@ -30,7 +35,7 @@ def add_credit(asm, src_version, dest_version): return -def copy_magic_into_pyc(input_pyc, output_pyc, src_version, dest_version): +def copy_magic_into_pyc(input_pyc, output_pyc, src_version, dest_version) -> None: """Bytecodes are the same except the magic number, so just change that""" (version, timestamp, magic_int, co, is_pypy, source_size) = load_module(input_pyc) @@ -43,7 +48,7 @@ def copy_magic_into_pyc(input_pyc, output_pyc, src_version, dest_version): return -def xlate26_27(inst): +def xlate26_27(inst) -> None: """Between 2.6 and 2.7 opcode values changed Adjust for the differences by using the opcode name """ @@ -141,7 +146,9 @@ def transform_33_32(inst, new_inst, i, n, offset, instructions, new_asm): return 0 -def transform_asm(asm, conversion_type, src_version, dest_version): +def transform_asm( + asm: Assembler | None, conversion_type, src_version, dest_version +) -> Assembler: new_asm = Assembler(dest_version, is_pypy=False) for field in "code size".split(): setattr(new_asm, field, copy(getattr(asm, field))) @@ -159,7 +166,9 @@ def transform_asm(asm, conversion_type, src_version, dest_version): new_asm.backpatch.append(copy(asm.backpatch[j])) new_asm.label.append(copy(asm.label[j])) new_asm.codes.append(copy(code)) - new_asm.code.co_lnotab = decode_lineno_tab_old(code.co_lnotab, code.co_firstlineno) + new_asm.code.co_lnotab = decode_lineno_tab_old( + code.co_lnotab, code.co_firstlineno + ) instructions = asm.codes[j].instructions new_asm.code.instructions = [] i, offset, n = 0, 0, len(instructions) @@ -211,7 +220,7 @@ def transform_asm(asm, conversion_type, src_version, dest_version): @click.argument( "output_pyc", type=click.Path(writable=True), required=False, nargs=1, default=None ) -def main(conversion_type, input_pyc, output_pyc): +def main(conversion_type, input_pyc, output_pyc) -> None: """Convert Python bytecode from one version to another. INPUT_PYC contains the input bytecode path name diff --git a/xasm/version.py b/xasm/version.py index ba6b9bf..f3b1162 100644 --- a/xasm/version.py +++ b/xasm/version.py @@ -5,4 +5,4 @@ # space around "=" below. # fmt: off -__version__="1.2.1.dev0" # noqa +__version__="1.2.1" # noqa diff --git a/xasm/xasm_cli.py b/xasm/xasm_cli.py index 6c96dfe..9178645 100755 --- a/xasm/xasm_cli.py +++ b/xasm/xasm_cli.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import os import sys +from typing import List import click import xdis @@ -13,7 +14,7 @@ @click.command() @click.option("--pyc-file", default=None) @click.argument("asm-path", type=click.Path(exists=True, readable=True), required=True) -def main(pyc_file, asm_path): +def main(pyc_file: List[str], asm_path): """ Create Python bytecode from a Python assembly file. From 2a93ef0cb3f96bf5d0b75b80c39b4ad9469fd2c5 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Oct 2025 20:55:05 -0400 Subject: [PATCH 10/17] Type annotation compatibility for 3.6 --- xasm/assemble.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xasm/assemble.py b/xasm/assemble.py index 80a5e0a..9b269be 100644 --- a/xasm/assemble.py +++ b/xasm/assemble.py @@ -1,7 +1,7 @@ #!/usr/bin/env python import ast import re -from typing import List, Optional +from typing import List, Optional, Union import xdis from xdis import get_opcode, load_module @@ -29,7 +29,7 @@ def __repr__(self) -> str: pass -def is_int(s: int | str | None) -> bool: +def is_int(s: Union[int, str, None]) -> bool: try: int(s) return True @@ -130,7 +130,7 @@ def err(self, mess: str) -> None: self.status = "errored" -def asm_file(path) -> Assembler | None: +def asm_file(path) -> Optional[Assembler]: offset = 0 methods = {} method_name = None From 31ac7c08249766830d722248d9a6f6d1096f8179 Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 13 Oct 2025 20:31:05 -0400 Subject: [PATCH 11/17] Get ready for release 1.2.1 --- .gitignore | 1 + .pre-commit-config.yaml | 10 +- ChangeLog | 267 ++++++++++++++++++++++++++++++- ChangeLog-spell-corrected.diff | 52 ++++++ Makefile | 1 + NEWS.md | 18 +++ __pkginfo__.py | 4 +- pytest/test_assemble.py | 15 +- pytest/test_write_pyc.py | 4 +- test/columnize.py | 280 ++++++++++++++++++++------------- test/fn.py | 4 +- test/gcd.py | 15 +- test/run-test.py | 37 +++-- test/test_all.py | 8 +- xasm/assemble.py | 34 ++-- xasm/pyc_convert.py | 25 ++- xasm/version.py | 2 +- xasm/xasm_cli.py | 3 +- 18 files changed, 598 insertions(+), 182 deletions(-) create mode 100644 ChangeLog-spell-corrected.diff diff --git a/.gitignore b/.gitignore index 2c828d6..293539e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ /.mypy_cache /.pytest_cache /.python-version +/ChangeLog-spell-corrected /README.html /build /dist diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4cbf372..d5d5ca2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,11 +9,11 @@ repos: stages: [pre-commit] - id: end-of-file-fixer stages: [pre-commit] -- repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - stages: [pre-commit] +# - repo: https://github.com/pycqa/isort +# rev: 5.13.2 +# hooks: +# - id: isort +# stages: [pre-commit] - repo: https://github.com/psf/black rev: 23.12.1 hooks: diff --git a/ChangeLog b/ChangeLog index 895cbf6..4cd58fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,262 @@ +2025-10-13 rocky + + * xasm/version.py: Get ready for release 1.2.1 + +2025-10-13 rocky + + * README.rst, admin-tools/install-all-3.6-3.10.sh, + admin-tools/install-all-newest.sh, + admin-tools/make-dist-3.6-3.10.sh: Better package testing + +2025-10-13 rocky + + * admin-tools/install-all-3.8-3.10.sh, + admin-tools/install-all-newest.sh, + admin-tools/make-dist-3.8-3.10.sh, + admin-tools/pyenv-3.6-3.10-versions: Packaging, yet again + +2025-10-13 rocky + + * Makefile, admin-tools/merge-for-3.6.sh: Ever changing "standards" + +2025-10-13 rocky + + * admin-tools/check-newest-versions.sh: Correct admin scripts + +2025-10-13 rocky + + * README.rst, admin-tools/make-dist-newest.sh, pyproject.toml, + setup.py: Packaging + +2025-10-13 rocky + + * admin-tools/check-3.6-3.10-versions.sh, + admin-tools/check-newest-versions.sh, + admin-tools/checkout_common.sh, + admin-tools/install-all-3.8-3.10.sh, + admin-tools/install-all-newest.sh, + admin-tools/make-dist-3.8-3.10.sh, admin-tools/make-dist-newest.sh, + admin-tools/merge-for-3.6.sh, admin-tools/pyenv-3.6-3.10-versions, + admin-tools/pyenv-newest-versions, admin-tools/setup-master.sh, + admin-tools/setup-python-3.6.sh, admin-tools/test-versions.sh: Admin + crap + +2025-10-13 rocky + + * .github/workflows/{osx.yml => macos.yml}, + .github/workflows/ubuntu.yml, .pre-commit-config.yaml, + requirements.txt, xasm/assemble.py: Misc fixes + +2025-06-21 rocky + + * xasm/assemble.py: Correct bug respecing create_code API Fixes #24 + +2025-02-18 rocky + + * requirements.txt: Make dependabot happy + +2024-12-24 rocky + + * .pre-commit-config.yaml, requirements.txt: Make dependabot happy + +2024-09-10 rocky + + * requirements.txt: Silenced dependabot + +2024-07-03 rocky + + * .github/ISSUE_TEMPLATE/bug-report.md, + .github/ISSUE_TEMPLATE/config.yml, + .github/ISSUE_TEMPLATE/feature-request.md, HOW-TO-USE.rst, + README.rst: Correct spelling typos + +2024-07-02 rocky + + * HOW-TO-USE.rst, README.rst: Update README.rst + +2024-07-02 rocky + + * HOW-TO-USE.rst, xasm/assemble.py, xasm/pyc_convert.py: More + explicit comments and ... add ## comments, and document better module and method information + +2024-06-23 rocky + + * xasm/assemble.py, xasm/pyc_convert.py: bug fixes... * decode_linotab() -> decode_lineno_tab_old to make it clear that + this routine works for version before 3.10 * last instruction can be RERAISE or RASE_VARARGS in addition to RETURN_VALUE * Avoid using asm.code.to_native() for now, since there are bugs + +2024-06-23 R. Bernstein + + * HOW-TO-USE.rst: Update HOW-TO-USE.rst Spell check and update information + +2024-06-23 R. Bernstein + + * HOW-TO-USE.rst: Update HOW-TO-USE.rst + +2024-06-23 R. Bernstein + + * HOW-TO-USE.rst: Update HOW-TO-USE.rst + +2024-06-23 R. Bernstein + + * HOW-TO-USE.rst: Update HOW-TO-USE.rst + +2024-06-15 rocky + + * xasm/assemble.py: Misc tweaks and bug fixes... * Handle numeric labels better * Adjust field name co_linetable for 3.10+ * Warn if duplicate line number seen and < 3.10 + +2024-06-04 rocky + + * .github/workflows/osx.yml, .github/workflows/ubuntu.yml, + .github/workflows/windows.yml: CI - need latest xdis for testing + +2024-06-04 rocky + + * pytest/test_assemble.py, xasm/assemble.py: Go over EXTENDED_ARG + creation in bytecode + +2024-06-03 rocky + + * xasm/assemble.py: remove unused import + +2024-06-03 rocky + + * xasm/assemble.py, xasm/xasm_cli.py: Compute EXTENDED_ARG better; + fix a typo + +2024-06-03 rocky + + * xasm/assemble.py: Improve offset label handling and .. ignore EXTENDED_ARG + +2024-06-03 rocky + + * xasm/assemble.py: Fix two misfeatures... 1. If Python bytecode is not set, complain and exit 2. Detect and handle line numbers on instructions + +2024-05-26 rocky + + * xasm/assemble.py: Check that operand values are in range + +2024-05-26 rocky + + * xasm/write_pyc.py, xasm/xasm_cli.py: Track and report errors in + return code better + +2024-05-26 rocky + + * .editorconfig: Typo + +2024-05-26 rocky + + * xasm/assemble.py: Tweak missing return value error + +2024-05-26 rocky + + * pytest/test_write_pyc.py: Skip a pytest on windows CI + +2024-05-26 rocky + + * .github/workflows/windows.yml, __pkginfo__.py, requirements.txt, + setup.py: Another attempt to get CI actions working + +2024-05-26 rocky + + * .github/workflows/osx.yml, .github/workflows/ubuntu.yml, + .github/workflows/windows.yml: Try Workflows actions + +2024-05-26 rocky + + * test/TODO.md: Add a TODO + +2024-05-26 rocky + + * test/tasm-3.10-bad.pyasm, test/tasm-3.10.pyasm, xasm/assemble.py: + Add a check for last instruction being a "return" + +2024-05-22 rocky + + * xasm/assemble.py: Offset in 3.10+ need to be divided by two + +2024-05-20 rocky + + * xasm/xasm_cli.py: Tweak asm file path + +2024-02-20 rocky + + * requirements.txt: Keep dependabot happy + +2024-01-10 rocky + + * requirements.txt: Bump cryptography to silence Depedabot + +2024-01-10 rocky + + * .pre-commit-config.yaml, xasm/assemble.py, xasm/pyc_convert.py, + xasm/xasm_cli.py: convert % to f-strings + +2024-01-09 rocky + + * pytest/test_write_pyc.py, requirements.txt: Update requirements as + recommended by dependabot Also comment out a test where xdis marshal is broken. + +2023-12-17 R. Bernstein + + * : Merge pull request #21 from rocky/lint Some lint found + +2023-10-23 rocky + + * .gitignore, __pkginfo__.py, requirements.txt, xasm/.gitignore, + xasm/assemble.py, xasm/pyc_convert.py, xasm/xasm_cli.py: Misc lint + +2023-09-18 rocky + + * xasm/assemble.py: version -> version_tuple fixes + +2023-09-18 rocky + + * .gitignore, admin-tools/pyenv-newest-versions, + admin-tools/setup-master.sh, test/.gitignore: Bump testing versions + +2022-12-02 rocky + + * xasm/assemble.py: Pycharm lint + +2022-12-02 rocky + + * xasm/assemble.py: Add a more detailed assert message... about the header. + +2022-12-02 rocky + + * xasm/version.py: Bump version to development version + +2022-10-17 rocky + + * xasm/assemble.py, xasm/write_pyc.py: Remove debug statement. Fixes #17 Also, add msg when we can't dump a code object + +2022-08-22 rocky + + * xasm/assemble.py, xasm/write_pyc.py: Fix a couple of small bugs + +2022-06-16 rocky + + * xasm/assemble.py: Detect native code objects in constants + +2022-04-02 R. Bernstein + + * : Merge pull request #15 from + Svenskithesource/Svenskithesource-patch-2 Fix empty append call + +2022-03-05 R. Bernstein + + * : Merge pull request #13 from Svenskithesource/patch-1 Typo + +2021-12-04 rocky + + * xasm/assemble.py: wrong variable python_version -> version Fixes #11 + 2021-11-07 rocky * ChangeLog, NEWS.md, admin-tools/check-versions.sh, - admin-tools/pyenv-versions, xasm/version.py: Get ready for release - 1.2.0 + admin-tools/make-dist.sh, admin-tools/pyenv-versions, setup.cfg, + xasm/version.py: Get ready for release 1.2.0 2021-11-07 rocky @@ -10,7 +264,7 @@ 2021-11-07 rocky - * admin-tools/pyenv-versions, admin-tools/setup-master.sh: + * admin-tools/pyenv-versions, admin-tools/setup-master.sh: Administrivia 2021-11-05 rocky @@ -62,7 +316,7 @@ * ChangeLog, NEWS.md, __pkginfo__.py, admin-tools/how-to-make-a-release.md, admin-tools/pyenv-versions, - setup.py, xasm/__init__.py, xasm/pyc_convert.py, xasm/version.py: + setup.py, xasm/__init__.py, xasm/pyc_convert.py, xasm/version.py: Get ready for release 1.1.1 2020-07-02 rocky @@ -129,7 +383,7 @@ * Makefile, __pkginfo__.py, admin-tools/how-to-make-a-release.md, admin-tools/pyenv-versions, pytest/.gitignore, pytest/test_write_pyc.py, test/test_all.py, xasm/.gitignore, - xasm/assemble.py, xasm/misc.py, xasm/write_pyc.py, xasm/xasm_cli.py: + xasm/assemble.py, xasm/misc.py, xasm/write_pyc.py, xasm/xasm_cli.py: Revise for new xdis. Add Better write_pyc() fn 2019-11-06 rocky @@ -463,7 +717,7 @@ 2017-07-04 rocky * test/gcd-2.7.pyasm, xasm/assemble.py: More proper label handling All non-int labels are absolute Labels as an operand don't and shouldn't have the trailing ':'. - pydisasm doen't add that Start moving toward xdis enhanced ability to work with Python code + pydisasm doesn't add that. Start moving toward xdis's enhanced ability to work with Python code more interchangeably between Python 2 and 3. 2017-07-03 rocky @@ -547,4 +801,3 @@ 2017-06-26 rocky * Assembler first step - diff --git a/ChangeLog-spell-corrected.diff b/ChangeLog-spell-corrected.diff new file mode 100644 index 0000000..2c98e8a --- /dev/null +++ b/ChangeLog-spell-corrected.diff @@ -0,0 +1,52 @@ +--- ChangeLog 2025-10-13 20:32:16.800140934 -0400 ++++ ChangeLog-spell-corrected 2025-10-13 20:31:50.631953303 -0400 +@@ -168,7 +168,7 @@ + + 2024-05-26 rocky + +- * test/tasm-3.10-bad.pyasm, test/tasm-3.10.pyasm, xasm/assemble.py: ++ * test/tasm-3.10-bad.pyasm, test/tasm-3.10.pyasm, xasm/assemble.py: + Add a check for last instruction being a "return" + + 2024-05-22 rocky +@@ -264,7 +264,7 @@ + + 2021-11-07 rocky + +- * admin-tools/pyenv-versions, admin-tools/setup-master.sh: ++ * admin-tools/pyenv-versions, admin-tools/setup-master.sh: + Administrivia + + 2021-11-05 rocky +@@ -316,7 +316,7 @@ + + * ChangeLog, NEWS.md, __pkginfo__.py, + admin-tools/how-to-make-a-release.md, admin-tools/pyenv-versions, +- setup.py, xasm/__init__.py, xasm/pyc_convert.py, xasm/version.py: ++ setup.py, xasm/__init__.py, xasm/pyc_convert.py, xasm/version.py: + Get ready for release 1.1.1 + + 2020-07-02 rocky +@@ -383,7 +383,7 @@ + * Makefile, __pkginfo__.py, admin-tools/how-to-make-a-release.md, + admin-tools/pyenv-versions, pytest/.gitignore, + pytest/test_write_pyc.py, test/test_all.py, xasm/.gitignore, +- xasm/assemble.py, xasm/misc.py, xasm/write_pyc.py, xasm/xasm_cli.py: ++ xasm/assemble.py, xasm/misc.py, xasm/write_pyc.py, xasm/xasm_cli.py: + Revise for new xdis. Add Better write_pyc() fn + + 2019-11-06 rocky +@@ -717,7 +717,7 @@ + 2017-07-04 rocky + + * test/gcd-2.7.pyasm, xasm/assemble.py: More proper label handling All non-int labels are absolute Labels as an operand don't and shouldn't have the trailing ':'. +- pydisasm doen't add that Start moving toward xdis enhanced ability to work with Python code ++ pydisasm doesn't add that. Start moving toward xdis's enhanced ability to work with Python code + more interchangeably between Python 2 and 3. + + 2017-07-03 rocky +@@ -801,4 +801,3 @@ + 2017-06-26 rocky + + * Assembler first step +- diff --git a/Makefile b/Makefile index 532301c..44968ee 100644 --- a/Makefile +++ b/Makefile @@ -27,3 +27,4 @@ rmChangeLog: #: Create a ChangeLog from git via git log and git2cl ChangeLog: rmChangeLog git log --pretty --numstat --summary | $(GIT2CL) >$@ + patch ChangeLog < ChangeLog-spell-corrected.diff diff --git a/NEWS.md b/NEWS.md index 8c07eca..ea9e2b8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,21 @@ +1.2.1 2025-10-13 +---------------- + +* Repackage for Python 3.11 and poetry. I can't describe what thrill it gives me to have to do this every few years. +* Correct bug respecting `create_code` API Fixes #24 +* More explicit comments. Add some `##` comments. Document module and method information better. +* `decode_linotab()` is now `decode_lineno_tab_old` to make it clear that this routine works for version before 3.10. +* Avoid using `asm.code.to_native()` for now, since there are bugs. +* Handle numeric labels better. +* Adjust field name `co_linetable` for bytecode after 3.10. +* Warn if duplicate line numbers seen and the assembler is before bytecode for 3.10 +* Improve `EXTENDED_ARG` handling and creation. +* If Python bytecode is not set, complain and exit. +* Detect and handle line numbers on instructions +* Add a check for last instruction being either a `RETURN_VALUE`, or `RERAISE`, or `RAISE_VARARGS` +* Offsets in bytecode for 3.10 need to be divided by two +* Lint code a little + 1.2.0 2021-11-07 ---------------- diff --git a/__pkginfo__.py b/__pkginfo__.py index 134348b..478c9f9 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -54,7 +54,7 @@ import os.path as osp -def get_srcdir(): +def get_srcdir() -> str: filename = osp.normcase(osp.dirname(osp.abspath(__file__))) return osp.realpath(filename) @@ -62,7 +62,7 @@ def get_srcdir(): srcdir = get_srcdir() -def read(*rnames): +def read(*rnames) -> str: return open(osp.join(srcdir, *rnames)).read() diff --git a/pytest/test_assemble.py b/pytest/test_assemble.py index b762263..d67646e 100644 --- a/pytest/test_assemble.py +++ b/pytest/test_assemble.py @@ -2,15 +2,20 @@ Test xasm.assemble code """ -from xdis.opcodes import (opcode_15, opcode_27, opcode_35, opcode_36, - opcode_36pypy, opcode_312) +from xdis.opcodes import ( + opcode_15, + opcode_27, + opcode_35, + opcode_36, + opcode_36pypy, + opcode_312, +) from xasm.assemble import append_operand -def test_append_operand(): - - def check_one(expected_bytecode_len: int, operand_value): +def test_append_operand() -> None: + def check_one(expected_bytecode_len: int, operand_value: int) -> None: bytecode = [] append_operand( bytecode, diff --git a/pytest/test_write_pyc.py b/pytest/test_write_pyc.py index 776bf08..3a9e96e 100644 --- a/pytest/test_write_pyc.py +++ b/pytest/test_write_pyc.py @@ -9,7 +9,7 @@ from xasm.write_pyc import write_pycfile -def get_srcdir(): +def get_srcdir() -> str: filename = osp.normcase(os.path.dirname(__file__)) return osp.realpath(filename) @@ -23,7 +23,7 @@ def get_srcdir(): reason="test skipped because Python 2.x has problems creating Python 3.x files", ) @pytest.mark.skipif(sys.platform in ("win32",), reason="Test does not work on Windows?") -def test_roundtrip3(): +def test_roundtrip3() -> None: fp = NamedTemporaryFile(mode="wb+", suffix=".pyc", prefix="test_pyc-", delete=False) orig_path = "testdata/test_pyc.pyc" version, timestamp, magic_int, co, is_pypy, source_size, sip_hash = load_module( diff --git a/test/columnize.py b/test/columnize.py index 6f1e038..aa3f806 100644 --- a/test/columnize.py +++ b/test/columnize.py @@ -7,12 +7,12 @@ import os -def computed_displaywidth(): - '''Figure out a reasonable default with. Use os.environ['COLUMNS'] if possible, +def computed_displaywidth() -> int: + """Figure out a reasonable default with. Use os.environ['COLUMNS'] if possible, and failing that use 80. - ''' + """ try: - width = int(os.environ['COLUMNS']) + width = int(os.environ["COLUMNS"]) except (KeyError, ValueError): width = 80 @@ -20,27 +20,33 @@ def computed_displaywidth(): default_opts = { - 'arrange_array' : False, # Check if file has changed since last time - 'arrange_vertical' : True, - 'array_prefix' : '', - 'array_suffix' : '', - 'colfmt' : None, - 'colsep' : ' ', - 'displaywidth' : computed_displaywidth(), - 'lineprefix' : '', - 'linesuffix' : "\n", - 'ljust' : None, - 'term_adjust' : False - } + "arrange_array": False, # Check if file has changed since last time + "arrange_vertical": True, + "array_prefix": "", + "array_suffix": "", + "colfmt": None, + "colsep": " ", + "displaywidth": computed_displaywidth(), + "lineprefix": "", + "linesuffix": "\n", + "ljust": None, + "term_adjust": False, +} -def get_option(key, options): +def get_option(key: str, options): return options.get(key, default_opts.get(key)) -def columnize(array, displaywidth=80, colsep = ' ', - arrange_vertical=True, ljust=True, lineprefix='', - opts={}): +def columnize( + array, + displaywidth: int = 80, + colsep: str = " ", + arrange_vertical=True, + ljust=True, + lineprefix="", + opts={}, +): """Return a list of strings as a compact set of columns arranged horizontally or vertically. @@ -60,38 +66,37 @@ def columnize(array, displaywidth=80, colsep = ' ', set false, consecutive items will go across, left to right, top to bottom.""" if not isinstance(array, (list, tuple)): - raise TypeError(( - 'array needs to be an instance of a list or a tuple')) + raise TypeError(("array needs to be an instance of a list or a tuple")) o = {} if len(opts.keys()) > 0: for key in default_opts.keys(): o[key] = get_option(key, opts) pass - if o['arrange_array']: - o['array_prefix'] = '[' - o['lineprefix'] = ' ' - o['linesuffix'] = ",\n" - o['array_suffix'] = "]\n" - o['colsep'] = ', ' - o['arrange_vertical'] = False + if o["arrange_array"]: + o["array_prefix"] = "[" + o["lineprefix"] = " " + o["linesuffix"] = ",\n" + o["array_suffix"] = "]\n" + o["colsep"] = ", " + o["arrange_vertical"] = False pass else: o = default_opts.copy() - o['displaywidth'] = displaywidth - o['colsep'] = colsep - o['arrange_vertical'] = arrange_vertical - o['ljust'] = ljust - o['lineprefix'] = lineprefix + o["displaywidth"] = displaywidth + o["colsep"] = colsep + o["arrange_vertical"] = arrange_vertical + o["ljust"] = ljust + o["lineprefix"] = lineprefix pass # if o['ljust'] is None: # o['ljust'] = !(list.all?{|datum| datum.kind_of?(Numeric)}) # pass - if o['colfmt']: - array = [(o['colfmt'] % i) for i in array] + if o["colfmt"]: + array = [(o["colfmt"] % i) for i in array] else: array = [str(i) for i in array] pass @@ -101,43 +106,43 @@ def columnize(array, displaywidth=80, colsep = ' ', if 0 == size: return "\n" elif size == 1: - return '%s%s%s\n' % (o['array_prefix'], str(array[0]), - o['array_suffix']) + return "%s%s%s\n" % (o["array_prefix"], str(array[0]), o["array_suffix"]) - o['displaywidth'] = max(4, o['displaywidth'] - len(o['lineprefix'])) - if o['arrange_vertical']: - array_index = lambda nrows, row, col: nrows*col + row + o["displaywidth"] = max(4, o["displaywidth"] - len(o["lineprefix"])) + if o["arrange_vertical"]: + array_index = lambda nrows, row, col: nrows * col + row # Try every row count from 1 upwards - for nrows in range(1, size+1): - ncols = (size+nrows-1) // nrows + for nrows in range(1, size + 1): + ncols = (size + nrows - 1) // nrows colwidths = [] - totwidth = -len(o['colsep']) + totwidth = -len(o["colsep"]) for col in range(ncols): # get max column width for this column colwidth = 0 for row in range(nrows): i = array_index(nrows, row, col) - if i >= size: break + if i >= size: + break x = array[i] colwidth = max(colwidth, len(x)) pass colwidths.append(colwidth) - totwidth += colwidth + len(o['colsep']) - if totwidth > o['displaywidth']: + totwidth += colwidth + len(o["colsep"]) + if totwidth > o["displaywidth"]: break pass - if totwidth <= o['displaywidth']: + if totwidth <= o["displaywidth"]: break pass # The smallest number of rows computed and the # max widths for each column has been obtained. # Now we just have to format each of the # rows. - s = '' + s = "" for row in range(nrows): texts = [] for col in range(ncols): - i = row + nrows*col + i = row + nrows * col if i >= size: x = "" else: @@ -146,149 +151,204 @@ def columnize(array, displaywidth=80, colsep = ' ', while texts and not texts[-1]: del texts[-1] for col in range(len(texts)): - if o['ljust']: + if o["ljust"]: texts[col] = texts[col].ljust(colwidths[col]) else: texts[col] = texts[col].rjust(colwidths[col]) pass pass - s += "%s%s%s" % (o['lineprefix'], str(o['colsep'].join(texts)), - o['linesuffix']) + s += "%s%s%s" % ( + o["lineprefix"], + str(o["colsep"].join(texts)), + o["linesuffix"], + ) pass return s else: - array_index = lambda ncols, row, col: ncols*(row-1) + col + array_index = lambda ncols, row, col: ncols * (row - 1) + col # Try every column count from size downwards colwidths = [] for ncols in range(size, 0, -1): # Try every row count from 1 upwards - min_rows = (size+ncols-1) // ncols - nrows = min_rows -1 + min_rows = (size + ncols - 1) // ncols + nrows = min_rows - 1 while nrows < size: nrows += 1 rounded_size = nrows * ncols colwidths = [] - totwidth = -len(o['colsep']) + totwidth = -len(o["colsep"]) for col in range(ncols): # get max column width for this column - colwidth = 0 - for row in range(1, nrows+1): + colwidth = 0 + for row in range(1, nrows + 1): i = array_index(ncols, row, col) - if i >= rounded_size: break + if i >= rounded_size: + break elif i < size: x = array[i] colwidth = max(colwidth, len(x)) pass pass colwidths.append(colwidth) - totwidth += colwidth + len(o['colsep']) - if totwidth >= o['displaywidth']: + totwidth += colwidth + len(o["colsep"]) + if totwidth >= o["displaywidth"]: break pass - if totwidth <= o['displaywidth'] and i >= rounded_size-1: + if totwidth <= o["displaywidth"] and i >= rounded_size - 1: # Found the right nrows and ncols # print "right nrows and ncols" - nrows = row + nrows = row break - elif totwidth >= o['displaywidth']: + elif totwidth >= o["displaywidth"]: # print "reduce ncols", ncols # Need to reduce ncols break pass - if totwidth <= o['displaywidth'] and i >= rounded_size-1: + if totwidth <= o["displaywidth"] and i >= rounded_size - 1: break pass # The smallest number of rows computed and the # max widths for each column has been obtained. # Now we just have to format each of the # rows. - s = '' - if len(o['array_prefix']) != 0: - prefix = o['array_prefix'] + s = "" + if len(o["array_prefix"]) != 0: + prefix = o["array_prefix"] else: - prefix = o['lineprefix'] + prefix = o["lineprefix"] pass - for row in range(1, nrows+1): + for row in range(1, nrows + 1): texts = [] for col in range(ncols): i = array_index(ncols, row, col) if i >= size: break - else: x = array[i] + else: + x = array[i] texts.append(x) pass for col in range(len(texts)): - if o['ljust']: + if o["ljust"]: texts[col] = texts[col].ljust(colwidths[col]) else: texts[col] = texts[col].rjust(colwidths[col]) pass pass - s += "%s%s%s" % (prefix, str(o['colsep'].join(texts)), - o['linesuffix']) - prefix = o['lineprefix'] + s += "%s%s%s" % (prefix, str(o["colsep"].join(texts)), o["linesuffix"]) + prefix = o["lineprefix"] pass - if o['arrange_array']: - colsep = o['colsep'].rstrip() - colsep_pos = -(len(colsep)+1) + if o["arrange_array"]: + colsep = o["colsep"].rstrip() + colsep_pos = -(len(colsep) + 1) if s[colsep_pos:] == colsep + "\n": - s = s[:colsep_pos] + o['array_suffix'] + "\n" + s = s[:colsep_pos] + o["array_suffix"] + "\n" pass pass else: - s += o['array_suffix'] + s += o["array_suffix"] pass return s pass + # Demo it -if __name__=='__main__': +if __name__ == "__main__": # from trepan.api import debug # debug() - print(columnize(list(range(12)), - opts={'displaywidth':6, 'arrange_array':True})) - print(columnize(list(range(12)), - opts={'displaywidth':10, 'arrange_array':True})) - for t in ((4, 4,), (4, 7), (100, 80)): + print(columnize(list(range(12)), opts={"displaywidth": 6, "arrange_array": True})) + print(columnize(list(range(12)), opts={"displaywidth": 10, "arrange_array": True})) + for t in ( + ( + 4, + 4, + ), + (4, 7), + (100, 80), + ): width = t[1] data = [str(i) for i in range(t[0])] options = {} - for t2 in ((False, 'horizontal',), (True, 'vertical',)): + for t2 in ( + ( + False, + "horizontal", + ), + ( + True, + "vertical", + ), + ): print("Width: %d, direction: %s" % (width, t2[1])) - options['displaywidth'] = width - options['arrange_vertical'] = t2[0] + options["displaywidth"] = width + options["arrange_vertical"] = t2[0] print(columnize(data, opts=options)) pass pass print(columnize([])) - print(columnize(["a", '2', "c"], 10, ', ')) + print(columnize(["a", "2", "c"], 10, ", ")) print(columnize(["oneitem"])) - print(columnize(("one", "two", "three",))) + print( + columnize( + ( + "one", + "two", + "three", + ) + ) + ) data = ( - "one", "two", "three", - "for", "five", "six", - "seven", "eight", "nine", - "ten", "eleven", "twelve", - "thirteen", "fourteen", "fifteen", - "sixteen", "seventeen", "eightteen", - "nineteen", "twenty", "twentyone", - "twentytwo", "twentythree", "twentyfour", - "twentyfive","twentysix", "twentyseven",) + "one", + "two", + "three", + "for", + "five", + "six", + "seven", + "eight", + "nine", + "ten", + "eleven", + "twelve", + "thirteen", + "fourteen", + "fifteen", + "sixteen", + "seventeen", + "eightteen", + "nineteen", + "twenty", + "twentyone", + "twentytwo", + "twentythree", + "twentyfour", + "twentyfive", + "twentysix", + "twentyseven", + ) print(columnize(data)) print(columnize(data, arrange_vertical=False)) data = [str(i) for i in range(55)] - print(columnize(data, opts={'displaywidth':39, 'arrange_array':True})) - print(columnize(data, displaywidth=39, ljust=False, - colsep=', ', lineprefix=' ')) - print(columnize(data, displaywidth=39, ljust=False, - arrange_vertical=False, - colsep = ', ')) + print(columnize(data, opts={"displaywidth": 39, "arrange_array": True})) + print(columnize(data, displaywidth=39, ljust=False, colsep=", ", lineprefix=" ")) + print( + columnize( + data, displaywidth=39, ljust=False, arrange_vertical=False, colsep=", " + ) + ) - print(columnize(data, displaywidth=39, ljust=False, - arrange_vertical=False, - colsep = ', ', lineprefix=' ')) + print( + columnize( + data, + displaywidth=39, + ljust=False, + arrange_vertical=False, + colsep=", ", + lineprefix=" ", + ) + ) import sys + try: print(columnize(5)) except TypeError: diff --git a/test/fn.py b/test/fn.py index 35da334..2565e7b 100644 --- a/test/fn.py +++ b/test/fn.py @@ -1,3 +1,5 @@ -def five(): +def five() -> int: return 5 + + print(five()) diff --git a/test/gcd.py b/test/gcd.py index 263710c..e7bb257 100644 --- a/test/gcd.py +++ b/test/gcd.py @@ -8,21 +8,24 @@ of parameters. """ -def gcd(a,b): - """ GCD. We assume positive numbers""" + + +def gcd(a: int, b: int): + """GCD. We assume positive numbers""" # Make: a <= b if a > b: - (a, b) = (b, a) - pass + (a, b) = (b, a) + pass if a <= 0: return None if a == 1 or a == b: return a - return gcd(b-a, a) + return gcd(b - a, a) + -if __name__=='__main__': +if __name__ == "__main__": a, b = 3, 5 print("The GCD of %d and %d is %d" % (a, b, gcd(a, b))) pass diff --git a/test/run-test.py b/test/run-test.py index b62edcd..b1cf727 100755 --- a/test/run-test.py +++ b/test/run-test.py @@ -1,12 +1,19 @@ #!/usr/bin/env python -import click, os, py_compile, sys +import os +import py_compile +import sys + +import click + @click.command() -@click.option('--compile/--no-compile', default=None) -@click.option('--disasm/--no-disasm', default=True) -@click.option('--asm/--no-asm', default=None) -@click.argument('files', nargs=-1, type=click.Path(exists=True, readable=True), required=True) -def main(compile, disasm, asm, files): +@click.option("--compile/--no-compile", default=None) +@click.option("--disasm/--no-disasm", default=True) +@click.option("--asm/--no-asm", default=None) +@click.argument( + "files", nargs=-1, type=click.Path(exists=True, readable=True), required=True +) +def main(compile: list[str], disasm, asm, files) -> None: """ Byte-compile, get assembly listing, assemble, and run a Python program """ @@ -18,17 +25,16 @@ def main(compile, disasm, asm, files): PY_VERSION = sys.version_info[0] + (sys.version_info[1] / 10.0) for path in files: - if compile is None: - do_compile = path.endswith('.py') + do_compile = path.endswith(".py") else: do_compile = compile and disasm if do_compile: if asm is None: asm = True - if path.endswith('.py'): - basename = path[:-len('.py')] + if path.endswith(".py"): + basename = path[: -len(".py")] else: basename = path @@ -40,8 +46,8 @@ def main(compile, disasm, asm, files): else: bytecode = path - have_disasm_path = path.endswith('.pyc') or path.endswith('.pyo') - have_asm_path = path.endswith('.pyasm') + have_disasm_path = path.endswith(".pyc") or path.endswith(".pyo") + have_asm_path = path.endswith(".pyasm") if disasm is None: do_disasm = have_disasm_path else: @@ -53,7 +59,7 @@ def main(compile, disasm, asm, files): if have_disasm_path: produced_bytecode = path bytecode = path - basename = path[:-len('.pyo')] + basename = path[: -len(".pyo")] asm_file = "%s.pyasm" % basename else: asm_file = "%s.pyasm" % ver_prefix @@ -63,7 +69,7 @@ def main(compile, disasm, asm, files): os.system(cmd) if have_asm_path: - basename = path[:-len('.pyasm')] + basename = path[: -len(".pyasm")] ver_prefix = basename asm_file = path produced_bytecode = "%s.pyc" % ver_prefix @@ -81,5 +87,6 @@ def main(compile, disasm, asm, files): print(cmd) os.system(cmd) -if __name__ == '__main__': + +if __name__ == "__main__": main(sys.argv[1:]) diff --git a/test/test_all.py b/test/test_all.py index 0f36553..9c3bf90 100644 --- a/test/test_all.py +++ b/test/test_all.py @@ -1,15 +1,19 @@ #!/usr/bin/env python -import os, subprocess, sys +import os import os.path as osp +import subprocess +import sys os.chdir(osp.dirname(__file__)) -def test_xasm(): + +def test_xasm() -> None: python_interp = sys.executable for asm in "tasm fn gcd columnize".split(): print("Testing %s" % asm) assert subprocess.call((python_interp, "./%s.py" % asm)) == 0 + if __name__ == "__main__": test_xasm() diff --git a/xasm/assemble.py b/xasm/assemble.py index 6a0aad7..6e905ec 100644 --- a/xasm/assemble.py +++ b/xasm/assemble.py @@ -1,7 +1,7 @@ #!/usr/bin/env python import ast import re -from typing import Optional +from typing import Any, List, Optional import xdis from xdis import get_opcode, load_module @@ -21,7 +21,7 @@ def __repr__(self) -> str: s = "%4d: " % self.line_no else: s = " " * 6 - s += "%-15s" % self.opname + s += f"{self.opname:15}" if self.arg is not None: s += f"\t{self.arg}" return s @@ -29,7 +29,7 @@ def __repr__(self) -> str: pass -def is_int(s) -> bool: +def is_int(s: Any) -> bool: try: int(s) return True @@ -41,7 +41,7 @@ def match_lineno(s: str) -> Optional[re.Match]: return re.match(r"^\d+:", s) -def get_opname_operand(opc, fields): +def get_opname_operand(opc, fields: List[str]): assert len(fields) > 0 opname = fields[0] if opc.opmap[opname] < opc.HAVE_ARGUMENT: @@ -63,7 +63,7 @@ def get_opname_operand(opc, fields): class Assembler: - def __init__(self, python_version, is_pypy): + def __init__(self, python_version, is_pypy) -> None: self.opc = get_opcode(python_version, is_pypy) self.code_list = [] self.codes = [] # FIXME use a better name @@ -76,7 +76,7 @@ def __init__(self, python_version, is_pypy): self.code = None self.siphash = None - def code_init(self, python_version=None): + def code_init(self, python_version=None) -> None: if self.python_version is None and python_version: self.python_version = python_version @@ -102,19 +102,19 @@ def code_init(self, python_version=None): self.code.instructions = [] - def update_lists(self, co, label, backpatch): + def update_lists(self, co, label, backpatch) -> None: self.code_list.append(co) self.codes.append(self.code) self.label.append(label) self.backpatch.append(backpatch) - def print_instructions(self): + def print_instructions(self) -> None: for inst in self.code.instructions: if inst.line_no: print() print(inst) - def warn(self, mess: str): + def warn(self, mess: str) -> None: """ Print an error message and record that we warned, unless we have already errored. """ @@ -122,7 +122,7 @@ def warn(self, mess: str): if self.status != "errored": self.status = "warning" - def err(self, mess: str): + def err(self, mess: str) -> None: """ Print an error message and record that we errored. """ @@ -130,7 +130,7 @@ def err(self, mess: str): self.status = "errored" -def asm_file(path): +def asm_file(path) -> Optional[Assembler]: offset = 0 methods = {} method_name = None @@ -413,7 +413,7 @@ def asm_file(path): return asm -def member(fields, match_value): +def member(fields, match_value) -> int: for i, v in enumerate(fields): if v == match_value and type(v) == type(match_value): return i @@ -421,7 +421,7 @@ def member(fields, match_value): return -1 -def update_code_field(field_name, value, inst, opc): +def update_code_field(field_name: str, value, inst, opc) -> None: field_values = getattr(opc, field_name) # Can't use "in" because True == 1 and False == 0 # if value in l: @@ -433,7 +433,7 @@ def update_code_field(field_name, value, inst, opc): field_values.append(value) -def update_code_tuple_field(field_name, code, lines, i): +def update_code_tuple_field(field_name: str, code, lines: List[str], i: int): count = 0 while i < len(lines): line = lines[i] @@ -454,12 +454,12 @@ def update_code_tuple_field(field_name, code, lines, i): return i -def err(msg, inst, i): +def err(msg: str, inst, i: int): msg += ". Instruction %d:\n%s" % (i, inst) raise RuntimeError(msg) -def warn(mess: str): +def warn(mess: str) -> None: """ Print an error message and record that we warned. """ @@ -562,7 +562,7 @@ def is_code_ok(asm: Assembler) -> bool: def append_operand( bytecode: list, arg_value, extended_arg_shift, arg_max_value, extended_arg_op -): +) -> None: """ Write instruction operand adding EXTENDED_ARG instructions when necessary. diff --git a/xasm/pyc_convert.py b/xasm/pyc_convert.py index 958b766..db46ccd 100755 --- a/xasm/pyc_convert.py +++ b/xasm/pyc_convert.py @@ -13,13 +13,18 @@ from xdis.magics import magics from xdis.opcodes import opcode_27, opcode_33 -from xasm.assemble import (Assembler, Instruction, asm_file, create_code, - decode_lineno_tab_old) +from xasm.assemble import ( + Assembler, + Instruction, + asm_file, + create_code, + decode_lineno_tab_old, +) from xasm.version import __version__ from xasm.write_pyc import write_pycfile -def add_credit(asm, src_version, dest_version): +def add_credit(asm, src_version, dest_version) -> None: stamp = "Converted from Python %s to %s by %s version %s" % ( src_version, dest_version, @@ -30,7 +35,7 @@ def add_credit(asm, src_version, dest_version): return -def copy_magic_into_pyc(input_pyc, output_pyc, src_version, dest_version): +def copy_magic_into_pyc(input_pyc, output_pyc, src_version, dest_version) -> None: """Bytecodes are the same except the magic number, so just change that""" (version, timestamp, magic_int, co, is_pypy, source_size) = load_module(input_pyc) @@ -43,7 +48,7 @@ def copy_magic_into_pyc(input_pyc, output_pyc, src_version, dest_version): return -def xlate26_27(inst): +def xlate26_27(inst) -> None: """Between 2.6 and 2.7 opcode values changed Adjust for the differences by using the opcode name """ @@ -141,7 +146,9 @@ def transform_33_32(inst, new_inst, i, n, offset, instructions, new_asm): return 0 -def transform_asm(asm, conversion_type, src_version, dest_version): +def transform_asm( + asm: Assembler | None, conversion_type, src_version, dest_version +) -> Assembler: new_asm = Assembler(dest_version, is_pypy=False) for field in "code size".split(): setattr(new_asm, field, copy(getattr(asm, field))) @@ -159,7 +166,9 @@ def transform_asm(asm, conversion_type, src_version, dest_version): new_asm.backpatch.append(copy(asm.backpatch[j])) new_asm.label.append(copy(asm.label[j])) new_asm.codes.append(copy(code)) - new_asm.code.co_lnotab = decode_lineno_tab_old(code.co_lnotab, code.co_firstlineno) + new_asm.code.co_lnotab = decode_lineno_tab_old( + code.co_lnotab, code.co_firstlineno + ) instructions = asm.codes[j].instructions new_asm.code.instructions = [] i, offset, n = 0, 0, len(instructions) @@ -211,7 +220,7 @@ def transform_asm(asm, conversion_type, src_version, dest_version): @click.argument( "output_pyc", type=click.Path(writable=True), required=False, nargs=1, default=None ) -def main(conversion_type, input_pyc, output_pyc): +def main(conversion_type, input_pyc, output_pyc) -> None: """Convert Python bytecode from one version to another. INPUT_PYC contains the input bytecode path name diff --git a/xasm/version.py b/xasm/version.py index ba6b9bf..f3b1162 100644 --- a/xasm/version.py +++ b/xasm/version.py @@ -5,4 +5,4 @@ # space around "=" below. # fmt: off -__version__="1.2.1.dev0" # noqa +__version__="1.2.1" # noqa diff --git a/xasm/xasm_cli.py b/xasm/xasm_cli.py index 6c96dfe..9178645 100755 --- a/xasm/xasm_cli.py +++ b/xasm/xasm_cli.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import os import sys +from typing import List import click import xdis @@ -13,7 +14,7 @@ @click.command() @click.option("--pyc-file", default=None) @click.argument("asm-path", type=click.Path(exists=True, readable=True), required=True) -def main(pyc_file, asm_path): +def main(pyc_file: List[str], asm_path): """ Create Python bytecode from a Python assembly file. From 50ac99257e395032a9734182c983e5df1435f18b Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 14 Oct 2025 05:37:12 -0400 Subject: [PATCH 12/17] Administriva - cd'd to wrong directory --- admin-tools/checkout_common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin-tools/checkout_common.sh b/admin-tools/checkout_common.sh index 6bd4151..30365c4 100644 --- a/admin-tools/checkout_common.sh +++ b/admin-tools/checkout_common.sh @@ -8,7 +8,7 @@ function setup_version { local repo=$1 version=$2 echo Running setup $version on $repo ... - (cd ./$repo && . ./admin-tools/setup-${version}.sh) + (cd ../$repo && . ./admin-tools/setup-${version}.sh) return $? } From 1a84dc83b42c32d7c3dcf740ce8ba45e3e80ec20 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 14 Oct 2025 05:53:20 -0400 Subject: [PATCH 13/17] Administrivia --- admin-tools/check-newest-versions.sh | 4 +++- admin-tools/check-versions.sh | 25 ------------------- admin-tools/make-dist.sh | 36 ---------------------------- 3 files changed, 3 insertions(+), 62 deletions(-) delete mode 100755 admin-tools/check-versions.sh delete mode 100755 admin-tools/make-dist.sh diff --git a/admin-tools/check-newest-versions.sh b/admin-tools/check-newest-versions.sh index 3cea33d..6552f9c 100755 --- a/admin-tools/check-newest-versions.sh +++ b/admin-tools/check-newest-versions.sh @@ -14,7 +14,9 @@ if ! source ./pyenv-newest-versions ; then exit $? fi -. ./setup-master.sh +if ! source ./setup-master.sh ; then + exit $? +fi cd .. for version in $PYVERSIONS; do diff --git a/admin-tools/check-versions.sh b/admin-tools/check-versions.sh deleted file mode 100755 index 6a18bc7..0000000 --- a/admin-tools/check-versions.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -function finish { - cd $owd -} - -# FIXME put some of the below in a common routine -owd=$(pwd) -trap finish EXIT - -cd $(dirname ${BASH_SOURCE[0]}) -if ! source ./pyenv-newest-versions ; then - exit $? -fi -cd .. -for version in $PYVERSIONS; do - echo --- $version --- - if ! pyenv local $version ; then - exit $? - fi - make clean && pip install -e . - if ! make check; then - exit $? - fi - echo === $version === -done diff --git a/admin-tools/make-dist.sh b/admin-tools/make-dist.sh deleted file mode 100755 index 6fe963d..0000000 --- a/admin-tools/make-dist.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -PACKAGE=xasm - -# FIXME put some of the below in a common routine -function finish { - cd $owd -} - -cd $(dirname ${BASH_SOURCE[0]}) -owd=$(pwd) -trap finish EXIT - -if ! source ./pyenv-newest-versions ; then - exit $? -fi -cd .. -source $PACKAGE/version.py -echo $__version__ - -for pyversion in $PYVERSIONS; do - echo --- $pyversion --- - if ! pyenv local $pyversion ; then - exit $? - fi - # pip bdist_egg create too-general wheels. So - # we narrow that by moving the generated wheel. - - # Pick out first two number of version, e.g. 3.5.1 -> 35 - first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//') - rm -fr build - python setup.py bdist_egg bdist_wheel - mv -v dist/${PACKAGE}-$__version__-{py3,py$first_two}-none-any.whl - echo === $pyversion === -done - -python ./setup.py sdist From c2a35adcff9dfdc3d8b1d0235e77c1e1f3ae9671 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 17 Oct 2025 09:09:47 -0400 Subject: [PATCH 14/17] More 3.6-3.10 versions --- admin-tools/pyenv-3.6-3.10-versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin-tools/pyenv-3.6-3.10-versions b/admin-tools/pyenv-3.6-3.10-versions index 590ee80..f920ded 100644 --- a/admin-tools/pyenv-3.6-3.10-versions +++ b/admin-tools/pyenv-3.6-3.10-versions @@ -7,4 +7,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then exit 1 fi -export PYVERSIONS='3.6 pypy3.6 3.7 pypy3.7 3.8 pyston-2.3.5 pypy3.8 3.9 pypy3.9 3.10 pypy3.10' +export PYVERSIONS='3.6 pypy3.6 3.7 pypy3.7 pyston-2.3.5 pypy3.8 graalpython-20.3.0 3.8 3.9 pypy3.9 3.9 pypy3.10 graalpy-24.0 3.10' From 6afe0f3a9f1949673d16f64b85328f9196d353a4 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 17 Oct 2025 13:30:15 -0400 Subject: [PATCH 15/17] Get ready for release 1.2.2 --- ChangeLog | 41 ++++++++++++++++++++++++++++++++++++++++- NEWS.md | 6 ++++++ pyproject.toml | 2 +- xasm/version.py | 2 +- 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4cd58fc..d0b8b12 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,45 @@ +2025-10-17 rocky + + * pyproject.toml, xasm/version.py: Get ready for release 1.2.2 + +2025-10-17 rocky + + * admin-tools/make-dist-3.6-3.10.sh, + admin-tools/make-dist-newest.sh, + admin-tools/pyenv-3.6-3.10-versions: More 3.6-3.10 versions + +2025-10-17 rocky + + * README.rst, admin-tools/install-all-3.6-3.10.sh, + admin-tools/install-all-newest.sh, admin-tools/make-dist-newest.sh, + admin-tools/pyenv-newest-versions, pyproject.toml, + xasm/assemble.py, xasm/write_pyc.py, xasm/xasm_cli.py: Pass PyPy + status to write pyc. Correct pyc-xasm entry. And more. + +2025-10-14 rocky + + * admin-tools/check-newest-versions.sh, + admin-tools/check-versions.sh, admin-tools/checkout_common.sh, + admin-tools/make-dist.sh: Administrivia + +2025-10-14 rocky + + * admin-tools/checkout_common.sh: Administriva - cd'd to wrong + directory + +2025-10-13 rocky + + * .github/workflows/ubuntu.yml, .github/workflows/windows.yml, + xasm/version.py: Bump version and adjust CI + 2025-10-13 rocky - * xasm/version.py: Get ready for release 1.2.1 + * .gitignore, .pre-commit-config.yaml, ChangeLog, + ChangeLog-spell-corrected.diff, Makefile, NEWS.md, __pkginfo__.py, + pytest/test_assemble.py, pytest/test_write_pyc.py, + test/columnize.py, test/fn.py, test/gcd.py, test/run-test.py, + test/test_all.py, xasm/assemble.py, xasm/pyc_convert.py, + xasm/version.py, xasm/xasm_cli.py: Get ready for release 1.2.1 2025-10-13 rocky diff --git a/NEWS.md b/NEWS.md index ea9e2b8..a543bf6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +1.2.2 2025-10-13 +---------------- + +* Pass PyPy status to write_pyc. +* Correct packaging pyc-xasm command-line entry. + 1.2.1 2025-10-13 ---------------- diff --git a/pyproject.toml b/pyproject.toml index e2e5c09..000a50f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ name = "xasm" description = "Cross-version Python bytecode assembler" dependencies = [ "click", - "xdis >= 6.1.1, < 6.3.0", + "xdis >= 6.1.8, < 6.3.0", ] readme = "README.rst" license = "GPL-2.0" diff --git a/xasm/version.py b/xasm/version.py index d23924c..2561538 100644 --- a/xasm/version.py +++ b/xasm/version.py @@ -5,4 +5,4 @@ # space around "=" below. # fmt: off -__version__="1.2.2.dev0" # noqa +__version__="1.2.2" # noqa From 96ebdd7f9933dacc6ad437ccfe127659090cf0bd Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 17 Oct 2025 13:41:47 -0400 Subject: [PATCH 16/17] We now need the newest xdis to pass "is_pypy" to. --- __pkginfo__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/__pkginfo__.py b/__pkginfo__.py index 2d11a81..0ace832 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -37,12 +37,12 @@ author = "Rocky Bernstein" author_email = "rb@dustyfeet.com" ftp_url = None -install_requires = ["xdis >= 6.1.0"] +install_requires = ["xdis >= 6.1.8"] license = "GPL-2.0" mailing_list = "python-debugger@googlegroups.com" modname = "xasm" py_modules = [] -setup_requires = ["pytest-runner", "xdis >= 6.1.0"] +setup_requires = ["pytest-runner"] # scripts = ['bin/pydisasm'] short_desc = "Python cross-version byte-code assembler" tests_require = ["pytest"] From ac7318842c3ed7686a3e18772a290a6a8ff71877 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 24 Jun 2026 05:30:46 -0400 Subject: [PATCH 17/17] Merge stuff --- .github/workflows/ubuntu.yml | 34 ---------------------------------- __pkginfo__.py | 4 ++-- pytest/test_write_pyc.py | 18 +++++++++++++----- requirements.txt | 9 --------- xasm/assemble.py | 10 ++++++---- xasm/write_pyc.py | 2 ++ 6 files changed, 23 insertions(+), 54 deletions(-) delete mode 100644 .github/workflows/ubuntu.yml delete mode 100644 requirements.txt diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml deleted file mode 100644 index 6af0daa..0000000 --- a/.github/workflows/ubuntu.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: xdis (Ubuntu) - -on: - push: - branches: [ python-3.6-to-3.10 ] - pull_request: - branches: [ python-3.6-to-3.10 ] - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ['3.8', '3.9', '3.10'] - steps: - - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - # Install the latest xdis release tarball from GitHub Releases (asset named xdis_36-*.tar.gz) - XDIS_URL=$(curl -s https://api.github.com/repos/rocky/python-xdis/releases/latest \ - | python -c "import sys,json; j=json.load(sys.stdin); assets=j.get('assets',[]); print(next((a.get('browser_download_url') for a in assets if a.get('name','').startswith('xdis_36-') and a.get('name','').endswith('.tar.gz')), ''))") - if [ -z "$XDIS_URL" ]; then - echo "ERROR: no xdis_36-*.tar.gz asset found on the latest release"; exit 1 - fi - python -m pip install "$XDIS_URL" - pip install -e . - pip install -r requirements-dev.txt - - name: Test xasm - run: | - make check diff --git a/__pkginfo__.py b/__pkginfo__.py index 0ace832..2d11a81 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -37,12 +37,12 @@ author = "Rocky Bernstein" author_email = "rb@dustyfeet.com" ftp_url = None -install_requires = ["xdis >= 6.1.8"] +install_requires = ["xdis >= 6.1.0"] license = "GPL-2.0" mailing_list = "python-debugger@googlegroups.com" modname = "xasm" py_modules = [] -setup_requires = ["pytest-runner"] +setup_requires = ["pytest-runner", "xdis >= 6.1.0"] # scripts = ['bin/pydisasm'] short_desc = "Python cross-version byte-code assembler" tests_require = ["pytest"] diff --git a/pytest/test_write_pyc.py b/pytest/test_write_pyc.py index d4c9d65..ed925ec 100644 --- a/pytest/test_write_pyc.py +++ b/pytest/test_write_pyc.py @@ -26,14 +26,22 @@ def get_srcdir() -> str: def test_roundtrip3() -> None: fp = NamedTemporaryFile(mode="wb+", suffix=".pyc", prefix="test_pyc-", delete=False) orig_path = "testdata/test_pyc.pyc" - version, timestamp, magic_int, co, is_pypy, source_size, sip_hash = load_module( - orig_path - ) - write_pycfile(fp, [co], timestamp, version) + ( + version_tuple, + timestamp, + _magic_int, + co_module, + is_pypy, + source_size, + sip_hash, + _file_offsets, + ) = load_module(orig_path) + + write_pycfile(fp, [co_module], timestamp, version_tuple) new_path = fp.name size = fp.tell() fp.close() - print("Wrote Python %s bytecode file %s; %d bytes" % (version, fp.name, size)) + print("Wrote Python %s bytecode file %s; %d bytes" % (version_tuple, fp.name, size)) old_fp = open(orig_path, "rb") new_fp = open(new_path, "rb") if PYTHON_VERSION_TRIPLE < (3, 6): diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 4969fbe..0000000 --- a/requirements.txt +++ /dev/null @@ -1,9 +0,0 @@ -click~=8.0.3 -pip -wheel~=0.38.1 -cryptography~>44.0.1 -lxml~>4.9.1 -keyring~=23.5.0 -colorama~=0.4.4 -setuptools~=~>65.5.1 -xdis>=6.1.0 diff --git a/xasm/assemble.py b/xasm/assemble.py index fb6418f..58761f3 100644 --- a/xasm/assemble.py +++ b/xasm/assemble.py @@ -170,11 +170,11 @@ def asm_file(path) -> Optional[Assembler]: # FIXME: extract all code options below the top-level and asm.code_list elif line.startswith("#"): - match = re.match("^# (Pypy )?Python bytecode ", line) + match = re.match("^# (PyPy )?Python bytecode ", line) if match: if match.group(1): + is_pypy = True pypy_str = match.group(1) - is_pypy = len(pypy_str) else: is_pypy = False pypy_str = "" @@ -197,7 +197,7 @@ def asm_file(path) -> Optional[Assembler]: elif line.startswith("# Timestamp in code: "): text = line[len("# Timestamp in code: ") :].strip() time_str = text.split()[0] - if is_int(time_str): + if is_int(time_str) and hasattr(asm, "timestamp"): asm.timestamp = int(time_str) elif line.startswith("# Method Name: "): if method_name: @@ -248,7 +248,9 @@ def asm_file(path) -> Optional[Assembler]: elif line.startswith("# Number of locals: "): l_str = line[len("# Number of locals: ") :].strip() asm.code.co_nlocals = int(l_str) - elif line.startswith("# Source code size mod 2**32: "): + elif line.startswith("# Source code size mod 2**32: ") and hasattr( + asm, "size" + ): l_str = line[ len("# Source code size mod 2**32: ") : -len(" bytes") ].strip() diff --git a/xasm/write_pyc.py b/xasm/write_pyc.py index b1fbcf3..2f9cfef 100644 --- a/xasm/write_pyc.py +++ b/xasm/write_pyc.py @@ -18,6 +18,8 @@ def write_pycfile( ) -> int: rc = 0 version_str = version_tuple_to_str(version_triple, end=2) + if is_pypy: + version_str += "pypy" magic_bytes = magics[version_str] magic_int = magic2int(magic_bytes) fp.write(magic_bytes)