Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ jobs:
run: ci/install-tools.sh --tests

- name: Type check
run: uv check --quiet --preview-features=check-command --no-sync
uses: j178/prek-action@e98a699c41eb69ab013a45817a0406469a748f8d # v2.0.5
with:
extra-args: "--all-files ty"

build_wheel:
name: Build wheels
Expand Down
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ repos:
hooks:
- id: validate-pyproject
additional_dependencies:
- validate-pyproject-schema-store[all]==2026.07.17
- validate-pyproject-schema-store[all]==2026.07.28

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 2700fd5671c633760d912769c041bfcde2b9a01b # frozen: v0.15.22
rev: cb8c523fd4835aba42af70f4cad5568db4df0b6c # frozen: v0.16.0
hooks:
- id: ruff-check
args: ["--fix", "--show-fixes", "--unsafe-fixes"]
Expand Down Expand Up @@ -59,7 +59,7 @@ repos:
- id: shellcheck

- repo: https://github.com/astral-sh/ty-pre-commit
rev: 73d9ef74d17f01127e8a495a7e77ce9941aae703 # frozen: v0.0.63
rev: 3940f891290063e0fde330228f5bff73e18ad2f2 # frozen: v0.0.64
hooks:
- id: ty
args: [--no-sync]
Expand Down
29 changes: 18 additions & 11 deletions ci/build-wheel.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ else
if [[ $PY_PLATFORM == linux* ]]; then
PLATFORM_TAG=many${PY_PLATFORM/-/_}
PLATFORM_TAG_MASK=${PLATFORM_TAG/_/*_}
if ! [ "$CI" == "true" ] && which podman &>/dev/null; then
export CIBW_CONTAINER_ENGINE=podman
fi
elif [[ $PY_PLATFORM == macosx* ]]; then
PLATFORM_TAG=macosx_universal2
PLATFORM_TAG_MASK="macosx_*"
Expand Down Expand Up @@ -111,20 +108,30 @@ _build_sdist () {
}

_build_wheel () {
local args=$*
local args
read -ra args <<<"$*"
if [ "$IS_CONDA" == "1" ] || [ "$IS_MINGW" == "1" ]; then
$PYTHON -m build -n -x --wheel -o wheelhouse
elif [ "$ZIP_SAFE" == "true" ]; then
uv build -p "$PY_VERSION$PY_ABI_THREAD" --wheel -o wheelhouse
elif [[ $PY_PLATFORM == win* ]] && [[ $args == *--only* ]]; then
uv build -p "$PY_VERSION$PY_ABI_THREAD" --wheel -o wheelhouse
elif [[ $PY_PLATFORM == macos* ]] && [[ $args == *--only* ]]; then
uv build -p "$PY_VERSION$PY_ABI_THREAD" --wheel -o wheelhouse
else
if [ "$CI" == "true" ] && [[ $PY_PLATFORM == win* ]]; then
export UV_LINK_MODE=copy
fi
"$INSTALL_DIR/cibuildwheel" "$args"
if [ "$ZIP_SAFE" == "true" ]; then
uv build -p "$PY_VERSION$PY_ABI_THREAD" --wheel -o wheelhouse
elif [[ $PY_PLATFORM == win* ]] && [[ ${args[0]} == *--only* ]]; then
uv build -p "$PY_VERSION$PY_ABI_THREAD" --wheel -o wheelhouse
elif [[ $PY_PLATFORM == macos* ]] && [[ ${args[0]} == *--only* ]]; then
uv build -p "$PY_VERSION$PY_ABI_THREAD" --wheel -o wheelhouse
else
if ! [ "$CI" == "true" ] && which podman &>/dev/null; then
export CIBW_CONTAINER_ENGINE=podman
fi
if [ -f "$INSTALL_DIR/cibuildwheel" ]; then
"$INSTALL_DIR/cibuildwheel" "${args[@]}"
else
uv tool run cibuildwheel "${args[@]}"
fi
fi
fi
}

Expand Down
36 changes: 32 additions & 4 deletions ci/install-tools.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
# Usage
if [ -n "$1" ] && [ "$1" == "--help" ]; then
echo "Usage:"
echo "$0 [--tests]"
echo "$0 [--dev][--doc][--tests]"
echo "Where:"
echo " --dev Install additional packages for development."
echo " --doc Install additional packages for documentation."
echo " --tests Install additional packages to run 'pytest'."
exit 1
fi

# Get script directory (without using /usr/bin/realpath)
THIS_DIR=$(dirname "${BASH_SOURCE[0]}")
CI_DIR=$(cd "$THIS_DIR" && pwd)

# Detect environment. For mingw and conda environments, python is not required
# to be installed, but will be installed by this script.
IS_CONDA="0"
Expand All @@ -25,7 +30,7 @@ elif which python &>/dev/null; then
if ! [ "$IS_MINGW" == "1" ]; then
IS_UV="1"
fi
python ci/requirements.py
python "$CI_DIR/requirements.py"
else
if [ -n "$MINGW_PACKAGE_PREFIX" ]; then
IS_MINGW="1"
Expand All @@ -39,11 +44,17 @@ fi
INSTALL_DIR="$HOME/bin"
mkdir -p "$INSTALL_DIR"

TOP_DIR=$(dirname "$CI_DIR")
pushd "$TOP_DIR" >/dev/null || exit

INSTALL_DEV=""
INSTALL_DOC=""
INSTALL_TESTS=""
while [ -n "$1" ]; do
if [ "$1" == "--dev" ]; then
INSTALL_DEV="1"
elif [ "$1" == "--doc" ]; then
INSTALL_DOC="1"
elif [ "$1" == "--tests" ]; then
INSTALL_TESTS="1"
else
Expand Down Expand Up @@ -147,11 +158,13 @@ else
fi
fi

# Get Python version
PY_VERSION=$(python -c "import sysconfig; print(sysconfig.get_python_version(), end='')")
PY_ABI_THREAD=$(python -c "import sysconfig; print(sysconfig.get_config_var('abi_thread') or '', end='')")

# Install dev tools
if [ "$INSTALL_DEV" == "1" ]; then
if [ -f requirements-dev.txt ]; then
PY_VERSION=$(python -c "import sysconfig; print(sysconfig.get_python_version(), end='')")
PY_ABI_THREAD=$(python -c "import sysconfig; print(sysconfig.get_config_var('abi_thread') or '', end='')")
PY_VER_ABI="$PY_VERSION$PY_ABI_THREAD"
if [ "$PY_VERSION" == "3.10" ] || [ "$PY_VERSION" == "3.11" ]; then
PY_VER_ABI="3.12"
Expand All @@ -163,6 +176,8 @@ if [ "$INSTALL_DEV" == "1" ]; then
$CONDA_EXE install -c conda-forge "$name" -S -q -y
elif [ "$name" != "cibuildwheel" ] && [ "$IS_UV" == "1" ]; then
uv pip install --upgrade "$name"
elif [ "$IS_UV" == "1" ]; then
uv tool install -p "$PY_VER_ABI" "$line"
else
filename=$INSTALL_DIR/$name
echo "Create $filename"
Expand All @@ -173,4 +188,17 @@ if [ "$INSTALL_DEV" == "1" ]; then
done < requirements-dev.txt
fi
fi

# Install doc tools (sphinx and extensions)
if [ "$INSTALL_DOC" == "1" ]; then
if [ -f doc/requirements.txt ]; then
PY_VER_ABI="$PY_VERSION$PY_ABI_THREAD"
if [ "$PY_VERSION" == "3.10" ] || [ "$PY_VERSION" == "3.11" ]; then
PY_VER_ABI="3.12"
fi
uv tool install -p "$PY_VER_ABI" \
--with-requirements=doc/requirements.txt sphinx
fi
fi
popd >/dev/null || true
echo "::endgroup::"
5 changes: 2 additions & 3 deletions ci/requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@

def main() -> None:
"""Entry point."""
pyproject_toml = Path("pyproject.toml")
root_dir = Path(__file__).resolve().parent.parent
pyproject_toml = root_dir / "pyproject.toml"
if not pyproject_toml.exists():
print("pyproject.toml not found", file=sys.stderr)
sys.exit(1)
with pyproject_toml.open("rb") as file:
config = tomllib.load(file)

root_dir = pyproject_toml.parent
requirements = root_dir / "requirements.txt"

try:
dependencies = config["project"]["dependencies"]
contents = list(dependencies)
Expand Down
11 changes: 3 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ Documentation = "https://docs.python.org/3.12/library/msilib.html"
dev = [
"cibuildwheel>=4.1.0",
"prek>=0.4.10,<0.5.0",
"ty>=0.0.63",
]
tests = [
"coverage>=7.13.0",
Expand Down Expand Up @@ -173,17 +172,13 @@ ignore = [
"D107", # Missing docstring in `__init__`
"D203", # conflict with D211
"D213", # conflict with D212
# should be revised in future - last revised using ruff 0.14.2
"PLR0913", # too-many-arguments
"PLR0917", # too-many-positional-arguments
# should be revised in future - last revised using ruff 0.16.0
"D101", # Missing docstring in public class
"D102", # Missing docstring in public method
"D103", # Missing docstring in public function
"D205", # 1 blank line required between summary line and description
"PLR2004", # Magic value used in comparison, consider replacing
"PLR0912", # too-many-branches
"PLR0913", # too-many-arguments
"PLR0915", # too-many-statements
# prone to false positives (https://github.com/astral-sh/ruff/issues/4045)
"S603",
]

[tool.ruff.lint.per-file-ignores]
Expand Down
1 change: 0 additions & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
cibuildwheel>=4.1.0
prek>=0.4.10,<0.5.0
ty>=0.0.63
48 changes: 27 additions & 21 deletions src/msilib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,15 +433,16 @@ def __init__(
default: str,
componentflags: int | None = None,
) -> None:
"""Create a new directory in the Directory table. There is a current
component at each point in time for the directory, which is either
explicitly created through start_component, or implicitly when files
are added for the first time. Files are added into the current
component, and into the cab file. To create a directory, a base
directory object needs to be specified (can be None), the path to the
physical directory, and a logical directory name. Default specifies the
DefaultDir slot in the directory table. componentflags specifies the
default flags that new components get.
"""Create a new directory in the Directory table.

There is a current component at each point in time for the directory,
which is either explicitly created through start_component, or
implicitly when files are added for the first time. Files are added
into the current component, and into the cab file. To create a
directory, a base directory object needs to be specified (can be None),
the path to the physical directory, and a logical directory name.
Default specifies the DefaultDir slot in the directory table.
componentflags specifies the default flags that new components get.
"""
index = 1
_logical = make_id(_logical)
Expand Down Expand Up @@ -476,11 +477,13 @@ def start_component(
keyfile: str | None = None,
uuid: str | None = None,
) -> None:
"""Add an entry to the Component table, and make this component the
current for this directory. If no component name is given, the
directory name is used. If no feature is given, the current feature is
used. If no flags are given, the directory's default flags are used. If
no keyfile is given, the KeyPath is left null in the Component table.
"""Add an entry to the Component table.

And make this component the current for this directory. If no component
name is given, the directory name is used. If no feature is given, the
current feature is used. If no flags are given, the directory's default
flags are used. If no keyfile is given, the KeyPath is left null in the
Component table.
"""
if flags is None:
flags = self.componentflags or 0
Expand Down Expand Up @@ -556,12 +559,13 @@ def add_file(
version: str | None = None,
language: str | None = None,
) -> str | None:
"""Add a file to the current component of the directory, starting a new
one if there is no current component. By default, the file name in the
source and the file table will be identical. If the src file is
specified, it is interpreted relative to the current directory.
Optionally, a version and a language can be specified for the entry in
the File table.
"""Add a file to the current component of the directory.

Starting a new one if there is no current component. By default, the
file name in the source and the file table will be identical. If the
src file is specified, it is interpreted relative to the current
directory. Optionally, a version and a language can be specified for
the entry in the File table.
"""
if not self.component:
self.start_component(self.logical, current_feature, 0)
Expand Down Expand Up @@ -638,7 +642,9 @@ def add_file(
def glob(
self, pattern: str, exclude: Container[str] | None = None
) -> list[str]:
"""Add a list of files to the current component as specified in the
"""Add a list of files to the current component.

Add a list of files to the current component as specified in the
glob pattern. Individual files can be excluded in the exclude list.
"""
try:
Expand Down
7 changes: 4 additions & 3 deletions src/msilib/schema.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""The standard MSI schema for MSI 2.0, with the tables variable providing a
list of table definitions, and _Validation_records providing the data for MSI
validation.
"""The standard MSI schema for MSI 2.0.

With the tables variable providing a list of table definitions, and
_Validation_records providing the data for MSI validation.
"""

from __future__ import annotations
Expand Down
4 changes: 3 additions & 1 deletion src/msilib/sequence.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""Table contents for the standard sequence tables:
"""Table contents for the standard sequence tables.

The standard sequence tables are:
AdminExecuteSequence, AdminUISequence, AdvtExecuteSequence,
InstallExecuteSequence, and InstallUISequence.
"""
Expand Down
5 changes: 3 additions & 2 deletions src/msilib/text.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Definitions for the UIText and ActionText tables, for the standard installer
actions.
"""Definitions for the UIText and ActionText tables.

For the standard installer actions.
"""

from __future__ import annotations
Expand Down
Loading