Skip to content

Commit

Permalink
Add the pyproject directory to the path (#24)
Browse files Browse the repository at this point in the history
When walking up the tree to find the pyproject.toml, use the directory the pyproject.toml is in as the pythonpath rather than the current working directory.
  • Loading branch information
ryanhiebert authored Jan 11, 2025
1 parent 30ceff2 commit 2f4749f
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 17 deletions.
6 changes: 6 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
2.6 (2025-01-10)
++++++++++++++++

* Use the ``pyproject.toml`` directory as the path
when discovered by walking up the tree.

2.5 (2025-01-09)
++++++++++++++++

Expand Down
14 changes: 8 additions & 6 deletions django_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,29 @@ def locate() -> Path:

def configure():
"""Run Django, getting the default from a file if needed."""
settings_module = None
settings_module = path = None

# Load from pyproject.toml first
if pyproject := locate():
with pyproject.open("rb") as f:
config = tomllib.load(f)
settings_module = (
config.get("tool", {}).get("django", {}).get("settings_module")
)
settings_module = (
config.get("tool", {}).get("django", {}).get("settings_module")
)
path = None if settings_module is None else pyproject.parent

if settings_module is None:
# Try loading configuration from setup.cfg next
parser = configparser.RawConfigParser()
parser.read("setup.cfg")
if parser.has_option("django", "settings_module"):
settings_module = parser.get("django", "settings_module")
path = None if settings_module is None else Path.cwd()

if settings_module is not None:
if settings_module is not None and path is not None:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", settings_module)
if settings_module == os.environ["DJANGO_SETTINGS_MODULE"]:
sys.path.insert(0, os.getcwd())
sys.path.insert(0, str(path))


@wraps(django.core.management.ManagementUtility, updated=())
Expand Down
43 changes: 33 additions & 10 deletions django_cmd_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,24 @@ def restore_environ(keys):


@restore_environ(["DJANGO_SETTINGS_MODULE"])
def test_configure_passthru(monkeypatch, tmp_path: Path):
"""It shouldn't change a given DJANGO_SETTINGS_MODULE."""
monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "spam.eggs")
content = "[django]\nsettings_module = ball.yarn\n"
tmp_path.joinpath("setup.cfg").write_text(content, encoding="utf-8")
def test_configure_from_pyproject_toml(tmp_path):
"""Read settings module path from toml file."""
content = '[tool.django]\nsettings_module = "ball.yarn"\n'
tmp_path.joinpath("pyproject.toml").write_text(content, encoding="utf-8")
os.chdir(tmp_path)
configure()
assert os.environ.get("DJANGO_SETTINGS_MODULE") == "spam.eggs"
assert os.environ.get("DJANGO_SETTINGS_MODULE") == "ball.yarn"


@restore_environ(["DJANGO_SETTINGS_MODULE"])
def test_configure_from_pyproject_toml(tmp_path):
"""Read settings module path from toml file."""
def test_configure_passthru(monkeypatch, tmp_path: Path):
"""It shouldn't change a given DJANGO_SETTINGS_MODULE."""
monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "spam.eggs")
content = '[tool.django]\nsettings_module = "ball.yarn"\n'
tmp_path.joinpath("pyproject.toml").write_text(content, encoding="utf-8")
os.chdir(tmp_path)
configure()
assert os.environ.get("DJANGO_SETTINGS_MODULE") == "ball.yarn"
assert os.environ.get("DJANGO_SETTINGS_MODULE") == "spam.eggs"


@restore_environ(["DJANGO_SETTINGS_MODULE"])
Expand Down Expand Up @@ -94,14 +94,33 @@ def test_configure_no_configfile(tmp_path):

@restore_environ(["DJANGO_SETTINGS_MODULE"])
def test_check_with_script_target(tmp_path):
"""Run check without a subprocess for coverage."""
"""Should add the pyproject.toml directory to the path."""
# Run check without a subprocess for coverage.
from django.core.management import execute_from_command_line

os.chdir(tmp_path)
subprocess.run(["django", "startproject", "myproject", "."], check=True)
config = '[tool.django]\nsettings_module = "myproject.settings"\n'
tmp_path.joinpath("pyproject.toml").write_text(config, encoding="utf-8")

execute_from_command_line(["django", "check"])


@restore_environ(["DJANGO_SETTINGS_MODULE"])
def test_check_with_script_target_subdir(tmp_path):
"""Should add the pyproject.toml directory to the path when in a subdir."""
# Run check without a subprocess for coverage.
from django.core.management import execute_from_command_line

os.chdir(tmp_path)
subprocess.run(["django", "startproject", "myproject", "."], check=True)
config = '[tool.django]\nsettings_module = "myproject.settings"\n'
tmp_path.joinpath("pyproject.toml").write_text(config, encoding="utf-8")

subdir = tmp_path.joinpath("subdir")
subdir.mkdir()
os.chdir(subdir)

execute_from_command_line(["django", "check"])


Expand All @@ -127,6 +146,10 @@ def test_new_project(command, tmp_path):
@restore_environ(["DJANGO_SETTINGS_MODULE"])
def test_runserver(command, tmp_path):
"""Should be able to run the development server for several seconds."""
# For reasons I don't understand, this doesn't seem to be cleaning
# up the port after the test run completes. To kill it, run:
#
# lsof -i4:8000 | tail -n 1 | awk '{print $2}' | xargs -n 1 kill -9
os.chdir(tmp_path)
subprocess.run([command, "startproject", "myproject", "."], check=True)
config = '[tool.django]\nsettings_module = "myproject.settings"\n'
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "django-cmd"
version = "2.5"
version = "2.6"
description = "Have a django command"
authors = [{ name = "Ryan Hiebert", email = "[email protected]" }]
license = "MIT"
Expand Down

0 comments on commit 2f4749f

Please sign in to comment.