Skip to content

Commit 7c0aa93

Browse files
authored
Add tests and test directories to PYTHONPATH in basilisp test CLI command (#1326)
Fixes #1069
1 parent ccc2239 commit 7c0aa93

6 files changed

Lines changed: 72 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Changed
9+
* Add `test` and `tests` directories to `PYTHONPATH` automatically during `basilisp test` CLI invocations (#1069)
810

911
## [v0.5.0]
1012
### Added
@@ -777,6 +779,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
777779
### Added
778780
- Basilisp language and compiler base.
779781

782+
[Unreleased]: https://github.com/basilisp-lang/basilisp/compare/v0.5.0..HEAD
780783
[v0.5.0]: https://github.com/basilisp-lang/basilisp/compare/v0.4.0..v0.5.0
781784
[v0.4.0]: https://github.com/basilisp-lang/basilisp/compare/v0.3.8..v0.4.0
782785
[v0.3.8]: https://github.com/basilisp-lang/basilisp/compare/v0.3.7..v0.3.8

docs/cli.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ If you installed the `PyTest <https://docs.pytest.org/en/7.0.x/>`_ extra, you ca
205205
206206
Because Basilisp defers all testing logic to PyTest, you can use any standard PyTest arguments and flags from this entrypoint.
207207

208+
.. seealso::
209+
210+
:ref:`testing`
211+
208212
.. _bootstrap_cli_command:
209213

210214
Bootstrap Python Installation

docs/gettingstarted.rst

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,25 @@ If you believe you have discovered a bug, please review the :ref:`Contributing G
7373
Using Basilisp in a Project
7474
---------------------------
7575

76+
.. _project_template:
77+
78+
Project Template
79+
^^^^^^^^^^^^^^^^
80+
81+
Basilisp has a `Leiningen project template <https://github.com/basilisp-lang/lein-template-basilisp>`_ which can be used to create a new project.
82+
83+
.. code-block::
84+
85+
lein new org.basilisp/basilisp myproject
86+
87+
The template uses ``pip`` as the default dependency management tool.
88+
This is not meant to be prescriptive, but rather to enable users to get setup with minimum effort since most Python installations ship with ``pip`` by default.
89+
The generated project works with ``uv`` without any changes.
90+
91+
.. note::
92+
93+
The template handles :ref:`bootstrapping` for you.
94+
7695
.. _project_structure:
7796

7897
Project Structure
@@ -89,7 +108,6 @@ Basilisp source files should always have a ``.lpy`` extension.
89108
90109
.
91110
├── README.md
92-
├── poetry.lock
93111
├── pyproject.toml
94112
├── src
95113
│ └── myproject
@@ -108,7 +126,7 @@ Basilisp source files should always have a ``.lpy`` extension.
108126
A single ``__init__.py`` file may be required for running tests with Pytest -- see :ref:`testing_path` for more information.
109127

110128
Basilisp apps can use any of Python's myriad dependency management options, such as `pip <https://pip.pypa.io/en/stable/>`_, `uv <https://docs.astral.sh/uv/>`_, `Poetry <https://python-poetry.org/>`_, and many others.
111-
Basilisp itself uses Poetry and that is the recommended dependency management tool for new Basilisp projects.
129+
Basilisp itself uses Poetry.
112130

113131
.. _bootstrapping:
114132

docs/testing.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ In this case, the test namespace can start at ``myproject``:
8686
(ns myproject.core-test)
8787
8888
89-
However, the ``test`` directory must be explicitly added to the ``PYTHONPATH`` using the ``--include-path`` (or ``-p``) option when running the tests:
89+
However, the ``test`` directory must be explicitly added to the ``PYTHONPATH`` using the ``--include-path`` (or ``-p`` or the ``PYTHONPATH`` environment variable) option when running the tests:
9090

9191
.. code-block:: shell
9292
@@ -99,6 +99,14 @@ However, the ``test`` directory must be explicitly added to the ``PYTHONPATH`` u
9999
In the first example above (``tests``, a Python convention), the top-level directory is already in the ``PYTHONPATH``, allowing ``tests.myproject.core-test`` to be resolvable.
100100
In the second example (``test``, a Clojure convention), the test directory is explicitly added to the ``PYTHONPATH``, enabling ``myproject.core-test`` to be resolvable.
101101

102+
.. warning::
103+
104+
In versions of Basilisp prior to v0.5.1, you will also want to specify ``--include-unsafe-path=false`` to disable Python prepending the empty string ``""`` (meaning the current directory) to the path.
105+
Without this, PyTest will attempt to collect your namespace from ``./test`` first, which will attempt to import your test namespaces as ``test.{namespace}``, which will fail collection.
106+
107+
After version v0.5.1, ``basilisp test`` automatically prepends ``tests`` and ``test`` (if either exist) to the ``PYTHONPATH``.
108+
You can disable this behavior by passing ``--include-default-test-path=false`` or ``-d false``.
109+
102110
.. _test_settings:
103111

104112
Test Settings

src/basilisp/cli.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,9 @@ def _add_debug_arg_group(parser: argparse.ArgumentParser) -> None:
324324
)
325325

326326

327-
def _add_import_arg_group(parser: argparse.ArgumentParser) -> None:
327+
def _add_import_arg_group(
328+
parser: argparse.ArgumentParser, include_unsafe_path_default: bool = True
329+
) -> None:
328330
group = parser.add_argument_group(
329331
"path options",
330332
description=(
@@ -336,14 +338,16 @@ def _add_import_arg_group(parser: argparse.ArgumentParser) -> None:
336338
"--include-unsafe-path",
337339
action="store",
338340
nargs="?",
339-
const=True,
340-
default=os.getenv("BASILISP_INCLUDE_UNSAFE_PATH", "true"),
341+
const=include_unsafe_path_default,
342+
default=os.getenv(
343+
"BASILISP_INCLUDE_UNSAFE_PATH", str(include_unsafe_path_default)
344+
),
341345
type=_to_bool,
342346
help=(
343347
"if true, automatically prepend a potentially unsafe path to `sys.path`; "
344348
"setting `--include-unsafe-path=false` is the Basilisp equivalent to "
345349
"setting PYTHONSAFEPATH to a non-empty string for CPython's REPL "
346-
"(env: BASILISP_INCLUDE_UNSAFE_PATH; default: true)"
350+
f"(env: BASILISP_INCLUDE_UNSAFE_PATH; default: {str(include_unsafe_path_default).lower()})"
347351
),
348352
)
349353
group.add_argument(
@@ -732,12 +736,23 @@ def test(
732736
args: argparse.Namespace,
733737
extra: list[str],
734738
) -> None: # pragma: no cover
739+
# Add `test` or `tests` directory to the current working directory
740+
if args.include_default_test_path:
741+
if not getattr(args, "include_path", []):
742+
args.include_path = []
743+
for d in ("tests", "test"):
744+
p = Path.cwd() / d
745+
if p.exists():
746+
args.include_path.append(str(p))
747+
735748
init_path(args)
736749
basilisp.init(_compiler_opts(args))
750+
737751
# parse_known_args leaves the `--` separator as the first element if it is present
738752
# but retaining that causes PyTest to interpret all the arguments as positional
739753
if extra and extra[0] == "--":
740754
extra = extra[1:]
755+
741756
try:
742757
import pytest
743758
except (ImportError, ModuleNotFoundError):
@@ -784,8 +799,23 @@ def test(
784799
allows_extra=True,
785800
)
786801
def _add_test_subcommand(parser: argparse.ArgumentParser) -> None:
802+
parser.add_argument(
803+
"-d",
804+
"--include-default-test-path",
805+
action="store",
806+
nargs="?",
807+
const=True,
808+
default=os.getenv("BASILISP_INCLUDE_DEFAULT_TEST_PATH", "true"),
809+
type=_to_bool,
810+
help=(
811+
"if true, automatically prepend a 'test' or 'tests' directory to the "
812+
"PYTHONPATH enabling discovery and importing of test namespaces "
813+
"(env: BASILISP_INCLUDE_DEFAULT_TEST_PATH; default: true)"
814+
),
815+
)
816+
787817
_add_compiler_arg_group(parser)
788-
_add_import_arg_group(parser)
818+
_add_import_arg_group(parser, include_unsafe_path_default=False)
789819
_add_runtime_arg_group(parser)
790820
_add_debug_arg_group(parser)
791821

tests/basilisp/testrunner_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ def test_basilisp_test_noargs(pytester: pytest.Pytester):
271271
runtime.Namespace.remove(sym.symbol("a.test-path"))
272272

273273
code = """
274-
(ns tests.test-path
274+
(ns test-path
275275
(:require
276276
[basilisp.test :refer [deftest is]]))
277277
(deftest passing-test

0 commit comments

Comments
 (0)