Typorithm · medium

Source archives and wheels that actually contain the package

pythonlibrariespackagingindependent-practice
Saved on this device
Full lesson · 4 learning steps Open any exercise for focused practice
1

Step 1 of 4 · intro card

Source archives and wheels that actually contain the package

0%

Concept and contract

Build real distributions and inspect their metadata, resources and typed-package marker.

A source distribution and a wheel serve different consumers. The source archive carries material needed to build the project, while the wheel represents an installable built distribution. A successful build command alone does not show which files either artifact contains.

The owned project uses a src layout, explicit setuptools discovery and declared package data. Its import package is pye_owned while its distribution name is applydjinn-owned-report. The example builds both formats locally and inspects their actual contents; it never uploads the teaching distribution to a public package index.

Mechanism and worked example

Each case receives a fresh owned project directory.

Each case receives a fresh owned project directory. The driver changes its declared version, builds with the already installed pinned backend and opens the generated artifacts. It reads Version from the wheel's METADATA rather than inferring the release from a source constant.

The report checks the defaults resource in the wheel, pyproject.toml in the source archive and the absence of that build configuration at the wheel's root. These observations reflect this fixture's backend output. They should not be generalized into a claim that every possible backend must include identical file paths or arbitrary source-tree files.

Complete worked example

python

from email.parser import BytesParser
from pathlib import Path
import subprocess
import sys
import tarfile
from zipfile import ZipFile

def inspect_example(version):
    project = Path('project')
    config = project / 'pyproject.toml'
    config.write_text(config.read_text().replace('version = "1.0.0"', f'version = "{version}"'))
    subprocess.run([sys.executable, '-m', 'build', '--no-isolation', '--sdist', '--wheel',
                    '--outdir', 'dist'], cwd=project, capture_output=True, text=True, check=True)
    wheel = next((project / 'dist').glob('*.whl'))
    source = next((project / 'dist').glob('*.tar.gz'))
    with ZipFile(wheel) as bundle:
        names = bundle.namelist()
        metadata = BytesParser().parsebytes(bundle.read(next(n for n in names if n.endswith('/METADATA'))))
    with tarfile.open(source) as archive:
        source_names = archive.getnames()
    return {'version': metadata['Version'], 'resource': 'pye_owned/defaults.json' in names,
            'sourceConfig': any(n.endswith('/pyproject.toml') for n in source_names),
            'wheelConfig': 'pyproject.toml' in names}
Reasoning
Each case receives a fresh owned project directory. The driver changes its declared version, builds with the already installed pinned backend and opens the generated artifacts. It reads Version from the wheel's METADATA rather than inferring the release from a source constant.
Download the reusable Python and packaging computer lab ↗

Focused decision: use the complete example for context

bash

python -m build --no-isolation --sdist --wheel --outdir dist
Decision
Inspect the built wheel and source archive separately, and verify that the typed-package marker ships in the wheel.

Owned project file: pyproject.toml

text

[build-system]
requires = ["setuptools==84.2.1", "wheel==0.48.0"]
build-backend = "setuptools.build_meta"

[project]
name = "applydjinn-owned-report"
version = "1.0.0"
requires-python = ">=3.13"
description = "Owned teaching fixture: never publish to an index"
license = "MIT"
dependencies = []

[project.scripts]
pye-report = "pye_owned.cli:main"

[tool.setuptools.packages.find]
where = ["src"]

[tool.setuptools.package-data]
pye_owned = ["defaults.json", "py.typed"]
Owned project fixture
This exact file is included in the downloaded lab and in the fresh project used by the executable acceptance cases. Read it alongside the complete driver.

Counterexamples and common mistakes

The controlled bug looks for defaults.json at the wheel's root instead of inside the import package.

The controlled bug looks for defaults.json at the wheel's root instead of inside the import package. The resource was shipped, but the inspection uses the wrong package-relative path and reports it missing. The verifier rejects that false packaging observation.

A more operational defect would omit package data from the build configuration and then rely on tests run directly from the checkout. Those source-tree tests could still see the file. Inspecting the archive and later installing it outside the source tree supply separate evidence that the delivered artifact contains what its runtime code needs.

Controlled bug: the executable contract rejects this version

python

from email.parser import BytesParser
from pathlib import Path
import subprocess
import sys
import tarfile
from zipfile import ZipFile

def inspect_example(version):
    project = Path('project')
    config = project / 'pyproject.toml'
    config.write_text(config.read_text().replace('version = "1.0.0"', f'version = "{version}"'))
    subprocess.run([sys.executable, '-m', 'build', '--no-isolation', '--sdist', '--wheel',
                    '--outdir', 'dist'], cwd=project, capture_output=True, text=True, check=True)
    wheel = next((project / 'dist').glob('*.whl'))
    source = next((project / 'dist').glob('*.tar.gz'))
    with ZipFile(wheel) as bundle:
        names = bundle.namelist()
        metadata = BytesParser().parsebytes(bundle.read(next(n for n in names if n.endswith('/METADATA'))))
    with tarfile.open(source) as archive:
        source_names = archive.getnames()
    return {'version': metadata['Version'], 'resource': 'defaults.json' in names,
            'sourceConfig': any(n.endswith('/pyproject.toml') for n in source_names),
            'wheelConfig': 'pyproject.toml' in names}
Reasoning
The controlled bug looks for defaults.json at the wheel's root instead of inside the import package. The resource was shipped, but the inspection uses the wrong package-relative path and reports it missing. The verifier rejects that false packaging observation.
Download the reusable Python and packaging computer lab ↗

Independent practice

Add a typed boolean showing that pye_owned/py.typed is present in the wheel.

Add a typed boolean showing that pye_owned/py.typed is present in the wheel. Preserve the version and resource observations and the source-versus-wheel configuration distinction. The first hint is to inspect the same wheel name list already used for defaults.json.

The second hint is to check the package-relative marker path, not a local source path. The marker communicates that a package distributes typing information; its presence does not prove every function is correctly typed. Keep the existing metadata version cases, including the release candidate, so the new observation does not replace the broader artifact contract.

Step 1: Inspect the built wheel and source archive separately, and verify that the typed-package marker ships in the wheel. Step 2: Run the accepted baseline, edit the exercise, then check its independent solution cases; preserve caller inputs and the documented exception behavior.

Practice starter: solve before reading the solution

python

from email.parser import BytesParser
from pathlib import Path
import subprocess
import sys
import tarfile
from zipfile import ZipFile

def inspect_example(version):
    project = Path('project')
    config = project / 'pyproject.toml'
    config.write_text(config.read_text().replace('version = "1.0.0"', f'version = "{version}"'))
    subprocess.run([sys.executable, '-m', 'build', '--no-isolation', '--sdist', '--wheel',
                    '--outdir', 'dist'], cwd=project, capture_output=True, text=True, check=True)
    wheel = next((project / 'dist').glob('*.whl'))
    source = next((project / 'dist').glob('*.tar.gz'))
    with ZipFile(wheel) as bundle:
        names = bundle.namelist()
        metadata = BytesParser().parsebytes(bundle.read(next(n for n in names if n.endswith('/METADATA'))))
    with tarfile.open(source) as archive:
        source_names = archive.getnames()
    return {'version': metadata['Version'], 'resource': 'pye_owned/defaults.json' in names,
            'sourceConfig': any(n.endswith('/pyproject.toml') for n in source_names),
            'wheelConfig': 'pyproject.toml' in names}

# Task: Inspect the built wheel and source archive separately, and verify that the typed-package marker ships in the wheel.
# Practice contract: Inspect the built wheel and source archive separately, and verify that the typed-package marker ships in the wheel.
Reasoning
Inspect the built wheel and source archive separately, and verify that the typed-package marker ships in the wheel.
Download the reusable Python and packaging computer lab ↗
  • Hint 1: Add a typed boolean showing that pye_owned/py.typed is present in the wheel. Preserve the version and resource observations and the source-versus-wheel configuration distinction. The first hint is to inspect the same wheel name list already used for defaults.json.
  • Hint 2: The second hint is to check the package-relative marker path, not a local source path. The marker communicates that a package distributes typing information; its presence does not prove every function is correctly typed. Keep the existing metadata version cases, including the release candidate, so the new observation does not replace the broader artifact contract.

Solution, tests and trade-offs

The solution adds one archive-membership observation while retaining actual metadata parsing.

The solution adds one archive-membership observation while retaining actual metadata parsing. Acceptance checks three declared versions and the complete set of expected fields. The fixture's separate package-data declaration makes both defaults.json and py.typed intentional shipped files rather than accidental source-tree neighbors.

The no-isolation flag here is a lab reproducibility choice: the selected environment already contains pinned build requirements. It is not a promise that the build frontend installs them or that arbitrary projects need no isolated build. Record tool versions and rerun installation checks when changing the backend, packaging rules or supported interpreters.

Practice solution and acceptance checks

python

from email.parser import BytesParser
from pathlib import Path
import subprocess
import sys
import tarfile
from zipfile import ZipFile

def inspect_example(version):
    project = Path('project')
    config = project / 'pyproject.toml'
    config.write_text(config.read_text().replace('version = "1.0.0"', f'version = "{version}"'))
    subprocess.run([sys.executable, '-m', 'build', '--no-isolation', '--sdist', '--wheel',
                    '--outdir', 'dist'], cwd=project, capture_output=True, text=True, check=True)
    wheel = next((project / 'dist').glob('*.whl'))
    source = next((project / 'dist').glob('*.tar.gz'))
    with ZipFile(wheel) as bundle:
        names = bundle.namelist()
        metadata = BytesParser().parsebytes(bundle.read(next(n for n in names if n.endswith('/METADATA'))))
    with tarfile.open(source) as archive:
        source_names = archive.getnames()
    return {'version': metadata['Version'], 'resource': 'pye_owned/defaults.json' in names,
            'sourceConfig': any(n.endswith('/pyproject.toml') for n in source_names),
            'wheelConfig': 'pyproject.toml' in names, 'typed': 'pye_owned/py.typed' in names}
Reasoning
The solution adds one archive-membership observation while retaining actual metadata parsing. Acceptance checks three declared versions and the complete set of expected fields. The fixture's separate package-data declaration makes both defaults.json and py.typed intentional shipped files rather than accidental source-tree neighbors.
Download the reusable Python and packaging computer lab ↗

Interview reasoning and next step

Explain why a source archive containing pyproject.toml does not establish that a wheel contains every needed runtime resource.

Explain why a source archive containing pyproject.toml does not establish that a wheel contains every needed runtime resource. Then distinguish the distribution name, import package name and installed metadata version. A useful answer identifies the actual artifact inspected for each claim.

For a stretch, remove the resource declaration in a separate owned copy, rebuild and compare the archive members before running an installed-resource check. Keep the known-good project intact so the contrast is reviewable. Building a file is one step; verifying the consumer's installed behavior is the next independent boundary.

Optional stretch — after the core task works: For a stretch, remove the resource declaration in a separate owned copy, rebuild and compare the archive members before running an installed-resource check. Keep the known-good project intact so the contrast is reviewable. Building a file is one step; verifying the consumer's installed behavior is the next independent boundary.

Computer practice: https://applydjinn.com/typorithm/python-engineering-lab-20261107.zip. Use an isolated Python 3.13 environment, install requirements.txt, then run verify.py. Edit exercises/pye-wheels.py and run --practice pye-wheels. Fixture files are created in fresh temporary directories for every case. Packaging checks build real local artifacts, install the exact wheel without an index and run outside the source tree. No package is published to PyPI. The app includes static examples, prepared results and questions; it does not run Python or provide an editor.

Build real distributions and inspect their metadata, resources and typed-package marker.