Skip to content

Commit

Permalink
Add jupyter_packaging conversion wrapper (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
blink1073 authored Jun 27, 2022
1 parent cdf72b3 commit c6f68f6
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 102 deletions.
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
Loading

0 comments on commit c6f68f6

Please sign in to comment.