Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add jupyter_packaging conversion wrapper #36

Merged
merged 4 commits into from
Jun 27, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion hatch_jupyter_builder/migration/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
runner = subprocess.check_call
runner([python, "-m", "pip", "install", "build"])
runner([python, "-m", "pip", "install", "packaging"])
runner([python, "-m", "pip", "install", "jupyter_packaging"])
runner([python, "-m", "pip", "install", "tomli_w"])
runner([python, "-m", "pip", "install", "tomli"])
runner([python, "-m", "pip", "install", "hatch"])
Expand Down
171 changes: 71 additions & 100 deletions hatch_jupyter_builder/migration/_migrate.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import json
import os
import re
import subprocess
import sys
from pathlib import Path
Expand All @@ -21,6 +20,21 @@

warnings = []

# Read pyproject before migration to get old build requirements.
pyproject = Path("pyproject.toml")
data = tomli.loads(pyproject.read_text("utf-8"))
requires = data["build-system"]["requires"]
# Install the old build reqs into this venv.
subprocess.run([sys.executable, "-m", "pip", "install"] + requires)
requires = [
r
for r in requires
if not r.startswith("jupyter-packaging")
and not r.startswith("setuptools")
and not r.startswith("jupyter_packaging")
and not r.startswith("wheel")
]

# Extract the current version before beginning any migration.
setup_py = Path("setup.py")
if setup_py.exists():
Expand All @@ -33,27 +47,25 @@
warnings.append("Fill in '[project][version]' in 'pyproject.toml'")
current_version = "!!UNKONWN!!"

# Get the original requires list.
pyproject = Path("pyproject.toml")
text = pyproject.read_text("utf-8")
data = tomli.loads(text)
requires = data["build-system"]["requires"]
requires = [
r
for r in requires
if not r.startswith("jupyter-packaging")
and not r.startswith("setuptools")
and not r.startswith("jupyter_packaging")
and not r.startswith("wheel")
]

# Automatic migration from hatch.
# Run the hatch migration script.
print("Running hatch migration")
subprocess.run([sys.executable, "-m", "hatch", "new", "--init"])

# Run the jupyter-packaging migration script - must be done after
# hatch migration to avoid conflicts.
print("Running jupyter-packaging migration")
here = os.path.abspath(os.path.dirname(__file__))
prev_pythonpath = os.environ.get("PYTHONPATH", "")
if prev_pythonpath:
os.environ["PYTHONPATH"] = f"{here}{os.pathsep}{prev_pythonpath}"
else:
os.environ["PYTHONPATH"] = here
subprocess.run([sys.executable, "setup.py", "--version"], capture_output=True)
os.environ["PYTHONPATH"] = prev_pythonpath

# Handle setup.cfg
# Move flake8 config to separate file, preserving comments.
# Add .flake8 file to git.
# Remove file when done.
setup_cfg = Path("setup.cfg")
flake8 = ["[flake8]"]
if setup_cfg.exists():
Expand All @@ -72,15 +84,15 @@

flake8.append(line)

Path(".flake8").write_text("\n".join(flake8) + "\n", "utf-8")
if matches:
Path(".flake8").write_text("\n".join(flake8) + "\n", "utf-8")
subprocess.run(["git", "add", ".flake"])

subprocess.run(["git", "add", ".flake"])


# Handle pyproject.toml config.
# Migrate and remove unused config.
text = pyproject.read_text("utf-8")
data = tomli.loads(text)
# Read in the project.toml after auto migration.
print("Migrating static data")
data = tomli.loads(pyproject.read_text("utf-8"))
tool_table = data.setdefault("tool", {})

# Add the other build requirements.
Expand All @@ -96,7 +108,7 @@
targets_table = build_table.setdefault("targets", {})

# Remove the dynamic version.
if current_version:
if current_version and "version" in hatch_table:
del hatch_table["version"]

# Remove any auto-generated sdist config.
Expand All @@ -107,8 +119,7 @@
targets_table["sdist"] = dict(exclude=[".github"])

hooks_table = build_table.setdefault("hooks", {})
hooks_table["jupyter-builder"] = {}
builder_table: dict = hooks_table["jupyter-builder"]
builder_table = hooks_table.setdefault("jupyter-builder", {})
builder_table["dependencies"] = [f"hatch-jupyter-builder>={builder_version}"]

# Migrate the jupyter-packaging static data.
Expand Down Expand Up @@ -140,85 +151,45 @@
build_table["artifacts"] = artifacts


# Handle setup.py - jupyter_packaging and pre-commit config.
# Remove the file when finished.
# Handle setup.py - pre-commit config.
if setup_py.exists():
text = setup_py.read_text("utf-8")
if "pre-commit" in text:
builder_table["install-pre-commit"] = True

build_kwargs = builder_table.setdefault("build-kwargs", {})
editable_build_command = None
if "build_cmd" in text:
match = re.search("build_cmd=['\"](.*?)['\"]", text, re.MULTILINE)
if match:
editable_build_command = match.groups()[0]

if "source_dir" in text or "build_dir" in text and editable_build_command:
builder_table["editable-build-kwargs"] = {}
editable_build_kwargs: dict = builder_table["editable-build-kwargs"]
if not editable_build_command:
editable_build_command = "!!! needs manual input !!!"
warnings.append(
"Fill in [tool.hatch.build.hooks.jupyter-builder.editable-build-kwargs][build_cmd]' in 'pyproject.toml', which was the 'build_cmd' argument to 'npm_builder' in 'setup.py'"
)
editable_build_kwargs["build_cmd"] = editable_build_command

for name in ["source_dir", "build_dir"]:
if name not in text:
continue
match = re.search(f"{name}=['\"](.*?)['\"]", text, re.MULTILINE)
if match is not None:
editable_build_kwargs[name] = match.groups()[0]
else:
warnings.append(
f"Fill in '[tool.hatch.build.hooks.jupyter-builder.editable-build-kwargs][{name}]' in 'pyproject.toml', which was the '{name}' argument to 'npm_builder' in 'setup.py'"
)
editable_build_kwargs[name] = "!!! needs manual input !!!"

elif editable_build_command or "build_cmd" in text:
if not editable_build_command:
editable_build_command = "!!! needs manual input !!!"
warnings.append(
"Fill in [tool.hatch.build.hooks.jupyter-builder.editable_build_cmd]' in 'pyproject.toml', which was the 'build_cmd' argument to 'npm_builder' in 'setup.py'"
)
build_kwargs["editable_build_cmd"] = editable_build_command

# Handle versioning with tbump - allows for static versioning and makes
# it easier to use jupyter_releaser.
data["project"]["version"] = current_version
data["project"].pop("dynamic", None)

tbump_table = tool_table.setdefault("tbump", {})
tbump_table["version"] = dict(
current=current_version,
regex=r"""
(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)((?P<channel>a|b|rc|.dev)(?P<release>\d+))?
""".strip(),
)
tbump_table["git"] = dict(
message_template=r"Bump to {new_version}", tag_template=r"v{new_version}"
)
tbump_table["field"] = [dict(name="channel", default=""), dict(name="release", default="")]
tbump_table["file"] = [dict(src="pyproject.toml")]

# Add entry for _version.py if it exists.
version_py = Path(project_name) / "_version.py"
if version_py.exists():
tbump_table["file"].append(dict(src=str(version_py)))
text = version_py.read_text(encoding="utf-8")
if current_version not in text:
warnings.append(
f'Add the static version string "{current_version}" to "{version_py}" instead of dynamic version handling'
)

# Add entry for package.json if it exists and has the same version.
package_json = Path("package.json")
if package_json.exists():
text = package_json.read_text(encoding="utf-8")
npm_version = json.loads(text)["version"]
if npm_version == current_version:
tbump_table["file"].append(dict(src="package.json"))
# Handle versioning with tbump - allows for static versioning and makes
# it easier to use jupyter_releaser.
data["project"]["version"] = current_version
data["project"].pop("dynamic", None)

tbump_table = tool_table.setdefault("tbump", {})
tbump_table["version"] = dict(
current=current_version,
regex=r"""
(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)((?P<channel>a|b|rc|.dev)(?P<release>\d+))?
""".strip(),
)
tbump_table["git"] = dict(message_template=r"Bump to {new_version}", tag_template=r"v{new_version}")
tbump_table["field"] = [dict(name="channel", default=""), dict(name="release", default="")]
tbump_table["file"] = [dict(src="pyproject.toml")]

# Add entry for _version.py if it exists.
version_py = Path(project_name) / "_version.py"
if version_py.exists():
tbump_table["file"].append(dict(src=str(version_py)))
text = version_py.read_text(encoding="utf-8")
if current_version not in text:
warnings.append(
f'Add the static version string "{current_version}" to "{version_py}" instead of dynamic version handling'
)

# Add entry for package.json if it exists and has the same version.
package_json = Path("package.json")
if package_json.exists():
text = package_json.read_text(encoding="utf-8")
npm_version = json.loads(text)["version"]
if npm_version == current_version:
tbump_table["file"].append(dict(src="package.json"))

# Add a setup.py shim.
shim_text = """# setup.py shim for use with applications that require it.
Expand Down