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

Encapsulating package managers #4918

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions cookiecutter.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"_extensions": ["dependencies.InstallExtension"],
"project_name": "My Awesome Project",
"project_slug": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_')|replace('.', '_')|trim() }}",
"description": "Behold My Awesome Project!",
Expand Down
55 changes: 55 additions & 0 deletions dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from typing import Any

from cookiecutter.environment import StrictEnvironment
from jinja2.ext import Extension


class PackageManager:
managers: dict[str, "PackageManager"] = {}

def __init_subclass__(cls, **kwargs):
cls.managers[cls.__name__.lower()] = cls()

def install(self, obj: str, context: dict[str, Any]) -> str:
raise NotImplementedError("Subclasses must implement the install method")


class PIP(PackageManager):
"""PIP package manager"""

def install(self, obj: str, context: dict[str, Any]) -> str:
if obj == "development":
return "pip install -r requirements/local.txt"

return f"pip install {obj}"


class Poetry(PackageManager):
"""Poetry package manager"""

def install(self, obj: str, context: dict[str, Any]) -> str:
if obj == "development":
return "poetry install --with dev"

return f"poetry add {obj}"


class UV(PackageManager):
"""Poetry package manager"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be out of scope apologies: this can be the exact same as pip install section except you would prepend pip with uv like uv pip install etc.

Regarding lock files, you should be able to run uv pip compile requirements.txt -o requirements-lock.txt

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So UV can extend PIP just by prepending the command with uv?

Copy link
Contributor

@Andrew-Chen-Wang Andrew-Chen-Wang Mar 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not feature complete I think, but for the basics, like pip install -r which is the extent of 99% of projects, yes, prepending uv suffices.



class InstallExtension(Extension):
"""Jinja2 extension to convert a Python object to JSON."""

def __init__(self, environment: StrictEnvironment):
"""Initialize the extension with the given environment."""
super().__init__(environment)

def install(obj, context):
# TODO we need to retrieve the package manager from the context or in another way
# manager_name = context.package_manager
manager_name = "pip"
package_manager = PackageManager.managers[manager_name]
return package_manager.install(obj, context)

environment.filters["install"] = install
4 changes: 2 additions & 2 deletions {{cookiecutter.project_slug}}/.drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ steps:
path: ${PRE_COMMIT_HOME}
commands:
- export PRE_COMMIT_HOME=$CI_PROJECT_DIR/.cache/pre-commit
- pip install -q pre-commit
- {{ "-q pre-commit"|install(cookiecutter)}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that's rendered out to either pip install, or the package manager equivalent, when the template is rendered?

- pre-commit run --show-diff-on-failure --color=always --all-files

- name: test
Expand All @@ -38,7 +38,7 @@ steps:
{%- else %}
image: python:3.11
commands:
- pip install -r requirements/local.txt
- {{ "development"|install(cookiecutter)}}
- pytest
{%- endif%}

Expand Down
4 changes: 2 additions & 2 deletions {{cookiecutter.project_slug}}/.travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
include:
- name: "Linter"
before_script:
- pip install -q ruff
- {{ "ruff"|install(cookiecutter)}}
script:
- ruff check .

Expand Down Expand Up @@ -39,7 +39,7 @@ jobs:
python:
- "3.11"
install:
- pip install -r requirements/local.txt
- {{ "development"|install(cookiecutter)}}
script:
- pytest
{%- endif %}