basilisp 0.5.0.dev2__tar.gz → 0.5.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/PKG-INFO +22 -19
  2. basilisp-0.5.1/README.md +45 -0
  3. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/pyproject.toml +9 -5
  4. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/cli.py +35 -5
  5. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/core.lpy +19 -13
  6. basilisp-0.5.1/src/basilisp/csv.lpy +59 -0
  7. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/compiler/generator.py +11 -4
  8. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/interfaces.py +13 -7
  9. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/map.py +2 -2
  10. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/obj.py +3 -2
  11. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/reader.py +1 -1
  12. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/runtime.py +143 -55
  13. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/set.py +1 -1
  14. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/typing.py +2 -0
  15. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/vector.py +20 -0
  16. basilisp-0.5.1/src/basilisp/reflect.lpy +250 -0
  17. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/test.lpy +1 -1
  18. basilisp-0.5.0.dev2/README.md +0 -47
  19. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/LICENSE +0 -0
  20. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/__init__.py +0 -0
  21. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/contrib/__init__.py +0 -0
  22. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/contrib/bencode.lpy +0 -0
  23. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/contrib/nrepl_server.lpy +0 -0
  24. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/contrib/pytest/__init__.py +0 -0
  25. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/contrib/pytest/testrunner.py +0 -0
  26. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/contrib/sphinx/__init__.py +0 -0
  27. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/contrib/sphinx/autodoc.py +0 -0
  28. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/contrib/sphinx/domain.py +0 -0
  29. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/contrib/sphinx/linkcode.py +0 -0
  30. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/core/protocols.lpy +0 -0
  31. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/data.lpy +0 -0
  32. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/edn.lpy +0 -0
  33. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/importer.py +0 -0
  34. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/io.lpy +0 -0
  35. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/json.lpy +0 -0
  36. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/__init__.py +0 -0
  37. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/atom.py +0 -0
  38. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/compiler/__init__.py +0 -0
  39. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/compiler/analyzer.py +0 -0
  40. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/compiler/constants.py +0 -0
  41. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/compiler/exception.py +0 -0
  42. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/compiler/nodes.py +0 -0
  43. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/compiler/optimizer.py +0 -0
  44. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/compiler/utils.py +0 -0
  45. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/delay.py +0 -0
  46. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/exception.py +0 -0
  47. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/futures.py +0 -0
  48. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/keyword.py +0 -0
  49. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/list.py +0 -0
  50. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/multifn.py +0 -0
  51. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/numbers.py +0 -0
  52. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/promise.py +0 -0
  53. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/queue.py +0 -0
  54. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/reduced.py +0 -0
  55. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/reference.py +0 -0
  56. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/seq.py +0 -0
  57. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/source.py +0 -0
  58. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/symbol.py +0 -0
  59. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/tagged.py +0 -0
  60. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/util.py +0 -0
  61. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/lang/volatile.py +0 -0
  62. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/logconfig.py +0 -0
  63. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/main.py +0 -0
  64. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/pprint.lpy +0 -0
  65. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/process.lpy +0 -0
  66. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/prompt.py +0 -0
  67. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/repl.lpy +0 -0
  68. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/set.lpy +0 -0
  69. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/shell.lpy +0 -0
  70. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/sitecustomize.py +0 -0
  71. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/stacktrace.lpy +0 -0
  72. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/string.lpy +0 -0
  73. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/template.lpy +0 -0
  74. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/test/fixtures.lpy +0 -0
  75. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/url.lpy +0 -0
  76. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/util.py +0 -0
  77. {basilisp-0.5.0.dev2 → basilisp-0.5.1}/src/basilisp/walk.lpy +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basilisp
3
- Version: 0.5.0.dev2
4
- Summary: A Clojure-like lisp written for Python
3
+ Version: 0.5.1
4
+ Summary: A Clojure-compatible(-ish) Lisp dialect hosted on Python 3 with seamless Python interop.
5
5
  License-Expression: EPL-1.0
6
6
  License-File: LICENSE
7
7
  Author: Christopher Rink
@@ -28,19 +28,25 @@ Requires-Dist: pygments (>=2.9.0,<3.0.0) ; extra == "pygments"
28
28
  Requires-Dist: pyrsistent (>=0.18.0,<1.0.0)
29
29
  Requires-Dist: pytest (>=7.0.0,<9.0.0) ; extra == "pytest"
30
30
  Requires-Dist: typing-extensions (>=4.7.0,<5.0.0)
31
+ Project-URL: Bug Tracker, https://github.com/basilisp-lang/basilisp/issues
32
+ Project-URL: Changelog, https://github.com/basilisp-lang/basilisp/blob/main/CHANGELOG.md
33
+ Project-URL: Documentation, https://docs.basilisp.org
34
+ Project-URL: Homepage, https://github.com/basilisp-lang/basilisp
35
+ Project-URL: Repository, https://github.com/basilisp-lang/basilisp
31
36
  Description-Content-Type: text/markdown
32
37
 
33
38
  # 🐍 basilisp 🐍
34
39
 
35
- A Clojure-compatible(-ish) Lisp dialect targeting Python 3.10+.
40
+ A Clojure-compatible(-ish) Lisp dialect hosted on Python 3 with seamless Python
41
+ interop.
36
42
 
37
- [![PyPI](https://img.shields.io/pypi/v/basilisp.svg?style=flat-square)](https://pypi.org/project/basilisp/) [![python](https://img.shields.io/pypi/pyversions/basilisp.svg?style=flat-square)](https://pypi.org/project/basilisp/) [![pyimpl](https://img.shields.io/pypi/implementation/basilisp.svg?style=flat-square)](https://pypi.org/project/basilisp/) [![readthedocs](https://img.shields.io/readthedocs/basilisp.svg?style=flat-square)](https://basilisp.readthedocs.io/) [![Run tests](https://github.com/basilisp-lang/basilisp/actions/workflows/run-tests.yml/badge.svg?branch=main)](https://github.com/basilisp-lang/basilisp/actions/workflows/run-tests.yml) [![Coveralls github](https://img.shields.io/coveralls/github/basilisp-lang/basilisp.svg?style=flat-square)](https://coveralls.io/github/basilisp-lang/basilisp) [![license](https://img.shields.io/github/license/basilisp-lang/basilisp.svg?style=flat-square)](https://github.com/basilisp-lang/basilisp/blob/master/LICENSE) [![Slack](https://img.shields.io/badge/Slack-Clojurians-green?style=flat-square)](https://clojurians.slack.com/archives/C071RFV2Z1D)
43
+ [![PyPI](https://img.shields.io/pypi/v/basilisp.svg?style=flat-square)](https://pypi.org/project/basilisp/) [![python](https://img.shields.io/pypi/pyversions/basilisp.svg?style=flat-square)](https://pypi.org/project/basilisp/) [![pyimpl](https://img.shields.io/pypi/implementation/basilisp.svg?style=flat-square)](https://pypi.org/project/basilisp/) [![readthedocs](https://img.shields.io/readthedocs/basilisp.svg?style=flat-square)](https://basilisp.readthedocs.io/) [![Run tests](https://github.com/basilisp-lang/basilisp/actions/workflows/run-tests.yml/badge.svg?branch=main)](https://github.com/basilisp-lang/basilisp/actions/workflows/run-tests.yml) [![Run clojure-test-suite](https://github.com/basilisp-lang/basilisp/actions/workflows/run-clojure-test-suite.yml/badge.svg?branch=main)](https://github.com/basilisp-lang/basilisp/actions/workflows/run-clojure-test-suite.yml) [![Coveralls github](https://img.shields.io/coveralls/github/basilisp-lang/basilisp.svg?style=flat-square)](https://coveralls.io/github/basilisp-lang/basilisp) [![license](https://img.shields.io/github/license/basilisp-lang/basilisp.svg?style=flat-square)](https://github.com/basilisp-lang/basilisp/blob/master/LICENSE) [![Slack](https://img.shields.io/badge/Slack-Clojurians-green?style=flat-square)](https://clojurians.slack.com/archives/C071RFV2Z1D)
38
44
 
39
45
  ## Getting Started
40
46
 
41
47
  Basilisp is developed on [GitHub](https://github.com/basilisp-lang/basilisp) and
42
48
  hosted on [PyPI](https://pypi.python.org/pypi/basilisp). You can fetch Basilisp
43
- using `pip`:
49
+ using `pip` (or any other Python dependency manager which can pull from PyPI):
44
50
 
45
51
  ```bash
46
52
  pip install basilisp
@@ -52,27 +58,24 @@ Once Basilisp is installed, you can enter into the REPL using:
52
58
  basilisp repl
53
59
  ```
54
60
 
55
- Basilisp [documentation](https://basilisp.readthedocs.io) can help guide your
56
- exploration at the REPL. Additionally, Basilisp features many of the same functions
57
- and idioms as [Clojure](https://clojure.org/), so you may find guides and
58
- documentation there helpful for getting started.
61
+ ## Documentation
62
+
63
+ Basilisp [documentation](https://docs.basilisp.org) can help guide your
64
+ exploration at the REPL and beyond. Additionally, Basilisp features many of the
65
+ same functions and idioms as [Clojure](https://clojure.org/), so you may find
66
+ guides and documentation there helpful for getting started.
59
67
 
60
68
  For those who prefer a video introduction, feel free to check out this
61
69
  [talk](https://youtu.be/ruGRHYpq448?si=0jr2a6uWlq6Vi2_k) hosted by the
62
70
  [London Clojurians](https://www.meetup.com/london-clojurians/) group about Basilisp.
63
71
 
64
- ## Why does this project exist?
65
-
66
- Basilisp is a project I (@chrisrink10) created to learn about Python, Clojure,
67
- hosted languages, and compilers.
72
+ ## Contributing
68
73
 
69
- That said, it is generally stable at this point with reasonably high test
70
- coverage, linting, and type checking. Work is ongoing to complete the rest of the
71
- standard library implementations. I suspect it could be used to build small
72
- applications and tools at this point, though I would not recommend it unless you
73
- like being an early adopter.
74
+ Contributions are welcome, but please review the [contributing guidelines](https://docs.basilisp.org/en/latest/contributing.html)
75
+ before submitting an issue or pull request.
74
76
 
75
- _Use in a production setting at your own risk._
77
+ If you have a question, please use [Github Discussions](https://github.com/basilisp-lang/basilisp/discussions)
78
+ or post in the [`#basilisp` channel](https://clojurians.slack.com/archives/C0A2CQQQVPB) in the Clojurians Slack.
76
79
 
77
80
  ## License
78
81
 
@@ -0,0 +1,45 @@
1
+ # 🐍 basilisp 🐍
2
+
3
+ A Clojure-compatible(-ish) Lisp dialect hosted on Python 3 with seamless Python
4
+ interop.
5
+
6
+ [![PyPI](https://img.shields.io/pypi/v/basilisp.svg?style=flat-square)](https://pypi.org/project/basilisp/) [![python](https://img.shields.io/pypi/pyversions/basilisp.svg?style=flat-square)](https://pypi.org/project/basilisp/) [![pyimpl](https://img.shields.io/pypi/implementation/basilisp.svg?style=flat-square)](https://pypi.org/project/basilisp/) [![readthedocs](https://img.shields.io/readthedocs/basilisp.svg?style=flat-square)](https://basilisp.readthedocs.io/) [![Run tests](https://github.com/basilisp-lang/basilisp/actions/workflows/run-tests.yml/badge.svg?branch=main)](https://github.com/basilisp-lang/basilisp/actions/workflows/run-tests.yml) [![Run clojure-test-suite](https://github.com/basilisp-lang/basilisp/actions/workflows/run-clojure-test-suite.yml/badge.svg?branch=main)](https://github.com/basilisp-lang/basilisp/actions/workflows/run-clojure-test-suite.yml) [![Coveralls github](https://img.shields.io/coveralls/github/basilisp-lang/basilisp.svg?style=flat-square)](https://coveralls.io/github/basilisp-lang/basilisp) [![license](https://img.shields.io/github/license/basilisp-lang/basilisp.svg?style=flat-square)](https://github.com/basilisp-lang/basilisp/blob/master/LICENSE) [![Slack](https://img.shields.io/badge/Slack-Clojurians-green?style=flat-square)](https://clojurians.slack.com/archives/C071RFV2Z1D)
7
+
8
+ ## Getting Started
9
+
10
+ Basilisp is developed on [GitHub](https://github.com/basilisp-lang/basilisp) and
11
+ hosted on [PyPI](https://pypi.python.org/pypi/basilisp). You can fetch Basilisp
12
+ using `pip` (or any other Python dependency manager which can pull from PyPI):
13
+
14
+ ```bash
15
+ pip install basilisp
16
+ ```
17
+
18
+ Once Basilisp is installed, you can enter into the REPL using:
19
+
20
+ ```bash
21
+ basilisp repl
22
+ ```
23
+
24
+ ## Documentation
25
+
26
+ Basilisp [documentation](https://docs.basilisp.org) can help guide your
27
+ exploration at the REPL and beyond. Additionally, Basilisp features many of the
28
+ same functions and idioms as [Clojure](https://clojure.org/), so you may find
29
+ guides and documentation there helpful for getting started.
30
+
31
+ For those who prefer a video introduction, feel free to check out this
32
+ [talk](https://youtu.be/ruGRHYpq448?si=0jr2a6uWlq6Vi2_k) hosted by the
33
+ [London Clojurians](https://www.meetup.com/london-clojurians/) group about Basilisp.
34
+
35
+ ## Contributing
36
+
37
+ Contributions are welcome, but please review the [contributing guidelines](https://docs.basilisp.org/en/latest/contributing.html)
38
+ before submitting an issue or pull request.
39
+
40
+ If you have a question, please use [Github Discussions](https://github.com/basilisp-lang/basilisp/discussions)
41
+ or post in the [`#basilisp` channel](https://clojurians.slack.com/archives/C0A2CQQQVPB) in the Clojurians Slack.
42
+
43
+ ## License
44
+
45
+ Eclipse Public License 1.0
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "basilisp"
3
- version = "0.5.0.dev2"
4
- description = "A Clojure-like lisp written for Python"
3
+ version = "0.5.1"
4
+ description = "A Clojure-compatible(-ish) Lisp dialect hosted on Python 3 with seamless Python interop."
5
5
  authors = [
6
6
  { name = "Christopher Rink", email = "chris@crink.dev" },
7
7
  ]
@@ -11,8 +11,6 @@ requires-python = ">=3.10"
11
11
  packages = [
12
12
  { include = "basilisp", from = "src" },
13
13
  ]
14
- repository = "https://github.com/basilisp-lang/basilisp"
15
- documentation = "https://basilisp.readthedocs.io/"
16
14
  classifiers = [
17
15
  # Trove classifiers
18
16
  # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
@@ -38,6 +36,13 @@ dependencies = [
38
36
  "typing-extensions (>=4.7.0,<5.0.0)",
39
37
  ]
40
38
 
39
+ [project.urls]
40
+ Homepage = "https://github.com/basilisp-lang/basilisp"
41
+ Documentation = "https://docs.basilisp.org"
42
+ Repository = "https://github.com/basilisp-lang/basilisp"
43
+ "Bug Tracker" = "https://github.com/basilisp-lang/basilisp/issues"
44
+ Changelog = "https://github.com/basilisp-lang/basilisp/blob/main/CHANGELOG.md"
45
+
41
46
  [dependency-groups]
42
47
  dev = [
43
48
  "black >=24.0.0",
@@ -108,7 +113,6 @@ omit = [
108
113
  "*/__version__.py",
109
114
  "*/basilisp/contrib/sphinx/*",
110
115
  ]
111
- patch = ["subprocess"]
112
116
 
113
117
  [tool.coverage.paths]
114
118
  source = [
@@ -324,7 +324,9 @@ def _add_debug_arg_group(parser: argparse.ArgumentParser) -> None:
324
324
  )
325
325
 
326
326
 
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:
328
330
  group = parser.add_argument_group(
329
331
  "path options",
330
332
  description=(
@@ -336,14 +338,16 @@ def _add_import_arg_group(parser: argparse.ArgumentParser) -> None:
336
338
  "--include-unsafe-path",
337
339
  action="store",
338
340
  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
+ ),
341
345
  type=_to_bool,
342
346
  help=(
343
347
  "if true, automatically prepend a potentially unsafe path to `sys.path`; "
344
348
  "setting `--include-unsafe-path=false` is the Basilisp equivalent to "
345
349
  "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()})"
347
351
  ),
348
352
  )
349
353
  group.add_argument(
@@ -732,12 +736,23 @@ def test(
732
736
  args: argparse.Namespace,
733
737
  extra: list[str],
734
738
  ) -> 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
+
735
748
  init_path(args)
736
749
  basilisp.init(_compiler_opts(args))
750
+
737
751
  # parse_known_args leaves the `--` separator as the first element if it is present
738
752
  # but retaining that causes PyTest to interpret all the arguments as positional
739
753
  if extra and extra[0] == "--":
740
754
  extra = extra[1:]
755
+
741
756
  try:
742
757
  import pytest
743
758
  except (ImportError, ModuleNotFoundError):
@@ -784,8 +799,23 @@ def test(
784
799
  allows_extra=True,
785
800
  )
786
801
  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
+
787
817
  _add_compiler_arg_group(parser)
788
- _add_import_arg_group(parser)
818
+ _add_import_arg_group(parser, include_unsafe_path_default=False)
789
819
  _add_runtime_arg_group(parser)
790
820
  _add_debug_arg_group(parser)
791
821
 
@@ -23,7 +23,7 @@
23
23
  (def ^{:doc "Create a list from the arguments."
24
24
  :arglists '([& args])}
25
25
  list
26
- (fn* list [& args] (if args args '())))
26
+ (fn* list [& args] (if args (basilisp.lang.list/list args) '())))
27
27
 
28
28
  (def
29
29
  ^{:doc "If ``seq`` is a Seq, return the first element from ``seq``. If ``seq``
@@ -209,11 +209,17 @@
209
209
  (fn iterator-seq [it]
210
210
  (basilisp.lang.runtime/to-iterator-seq it)))
211
211
 
212
-
213
212
  (def ^{:doc "Apply function ``f`` to the arguments provided.
214
213
 
215
214
  The last argument must always be coercible to a Seq. Intermediate
216
- arguments are not modified."
215
+ arguments are not modified. The Seq in the last argument may be
216
+ infinite if the called function ``f`` is lazy.
217
+
218
+ .. warning::
219
+
220
+ Applying arguments to Python functions (rather than Basilisp
221
+ functions) will consume the argument Seq eagerly. Infinite
222
+ Seqs are **not** supported for Python functions."
217
223
  :arglists '([f & args])}
218
224
  apply
219
225
  (fn apply [f & args]
@@ -231,7 +237,7 @@
231
237
  :arglists '([& seqs])}
232
238
  concat
233
239
  (fn concat [& seqs]
234
- (apply basilisp.lang.runtime/concat seqs)))
240
+ (basilisp.lang.runtime/concat-from-seq seqs)))
235
241
 
236
242
  (def
237
243
  ^{:doc "Create a hash map from pairs of input arguments."
@@ -2840,11 +2846,13 @@
2840
2846
  (cons (f (first coll)) (map f (rest coll))))))
2841
2847
  ([f coll & colls]
2842
2848
  (lazy-seq
2843
- (when-let [coll (seq coll)]
2844
- (let [colls (map seq colls)]
2845
- (when (every? identity colls)
2846
- (cons (apply f (first coll) (map first colls))
2847
- (apply map f (rest coll) (map rest colls)))))))))
2849
+ (let [step-elems (fn step-elems [colls]
2850
+ (lazy-seq
2851
+ (let [colls (map seq colls)]
2852
+ (when (every? identity colls)
2853
+ (cons (map first colls)
2854
+ (step-elems (map rest colls)))))))]
2855
+ (map #(apply f %) (step-elems (cons coll colls)))))))
2848
2856
 
2849
2857
  (def ^{:doc "Return a vector of ``(f elem)`` for elements in ``coll``\\. More than one
2850
2858
  collection may be supplied. If more than one collection is supplied, the
@@ -2878,10 +2886,8 @@
2878
2886
  "Return a lazy sequence of the concatenated results of mapping ``f`` over ``colls``\\."
2879
2887
  ([f]
2880
2888
  (comp (map f) cat))
2881
- ([f coll]
2882
- (apply concat (map f coll)))
2883
- ([f coll & colls]
2884
- (apply concat (apply map f coll colls))))
2889
+ ([f & colls]
2890
+ (apply concat (apply map f colls))))
2885
2891
 
2886
2892
  (defn filter
2887
2893
  "Return a lazy sequence of elements from ``coll`` where ``(pred elem)`` returns a
@@ -0,0 +1,59 @@
1
+ (ns basilisp.csv
2
+ "Wrapper functions for :external:py:mod:`csv` which reads and writes CSVs."
3
+ (:require
4
+ [basilisp.io :as bio])
5
+ (:import
6
+ csv))
7
+
8
+ (defn read-csv
9
+ "Returns a lazy sequence of vectors corresponding to the rows of a CSV file.
10
+
11
+ If ``input`` is a string, it will be treated as the contents of a CSV. Otherwise,
12
+ it will be treated as a :external:py:class:`io.TextIOBase`.
13
+
14
+ The reader function supports the following keyword arguments:
15
+
16
+ :keyword ``:separator``: the character used as the separator for a fields in a row
17
+ default is \",\"
18
+ :keyword ``:quote``: the quote character used on quoted fields; default is ``true``"
19
+ [input & {:keys [separator quote] :or {separator "," quote "\""}}]
20
+ (let [f (if (string? input)
21
+ (io/StringIO input)
22
+ input)
23
+ reader (csv/reader f ** :delimiter separator :quotechar quote)
24
+ do-read (fn read-csv*
25
+ []
26
+ (when-some [row (python/next reader nil)]
27
+ (cons (vec row) (lazy-seq (read-csv*)))))]
28
+ (lazy-seq (do-read))))
29
+
30
+ (defn rows->maps
31
+ "Returns a lazy sequence mapping over a sequence of CSV data (as vectors)
32
+ converting them to maps.
33
+
34
+ The first row will be used as the headers. The ``:key-fn`` keyword argument
35
+ names a function which will be used to map over the keys."
36
+ [rows & {:keys [key-fn] :or {key-fn keyword}}]
37
+ (let [header (mapv key-fn (first rows))]
38
+ (map #(zipmap header %) (rest rows))))
39
+
40
+ (defn write-csv
41
+ "Write a sequence of rows in CSV format to ``writer``, which should be an
42
+ :external:py:class:`io.TextIOBase`.
43
+
44
+ The writing function supports the following keyword arguments:
45
+
46
+ :keyword ``:separator``: the character used as the separator for a fields in a row
47
+ default is \",\"
48
+ :keyword ``:quote``: the quote character used on quoted fields; default is ``true``
49
+ :keyword ``:newline``: the newline character to use between rows (``:lf`` or
50
+ ``:cr+lf``)"
51
+ [writer data & {:keys [separator quote newline] :or {separator "," quote "\"" newline :lf}}]
52
+ (let [nl (cond
53
+ (= newline :lf) "\n"
54
+ (= newline :cr+lf) "\r\n"
55
+ :else (throw
56
+ (ex-info "newline must be one of: :lf or :cr+lf"
57
+ {:newline newline})))
58
+ w (csv/writer writer ** :delimiter separator :quotechar quote :lineterminator nl)]
59
+ (.writerows w (map #(mapv str %) data))))
@@ -799,6 +799,7 @@ _ATTR_FROZEN_DECORATOR_NAME = _load_attr(f"{_ATTR_ALIAS}.frozen")
799
799
  _ATTRIB_FIELD_FN_NAME = _load_attr(f"{_ATTR_ALIAS}.field")
800
800
  _BASILISP_LOAD_CONSTANT_NAME = _load_attr(f"{_RUNTIME_ALIAS}._load_constant")
801
801
  _COERCE_SEQ_FN_NAME = _load_attr(f"{_RUNTIME_ALIAS}.to_seq")
802
+ _UNWRAP_REST_ARGS_FN_NAME = _load_attr(f"{_RUNTIME_ALIAS}._unwrap_rest_args")
802
803
  _BASILISP_FN_FN_NAME = _load_attr(f"{_RUNTIME_ALIAS}._basilisp_fn")
803
804
  _FN_WITH_ATTRS_FN_NAME = _load_attr(f"{_RUNTIME_ALIAS}._with_attrs")
804
805
  _BASILISP_TYPE_FN_NAME = _load_attr(f"{_RUNTIME_ALIAS}._basilisp_type")
@@ -1707,7 +1708,7 @@ def __fn_args_to_py_ast(
1707
1708
  value=ast.IfExp(
1708
1709
  test=ast.Name(id=arg_name, ctx=ast.Load()),
1709
1710
  body=ast.Call(
1710
- func=_NEW_LIST_FN_NAME,
1711
+ func=_UNWRAP_REST_ARGS_FN_NAME,
1711
1712
  args=[ast.Name(id=arg_name, ctx=ast.Load())],
1712
1713
  keywords=[],
1713
1714
  ),
@@ -1738,6 +1739,8 @@ def __fn_args_to_py_ast(
1738
1739
  def __fn_decorator(
1739
1740
  arities: Iterable[int],
1740
1741
  has_rest_arg: bool = False,
1742
+ *,
1743
+ max_fixed_arity: int,
1741
1744
  ) -> ast.Call:
1742
1745
  return ast.Call(
1743
1746
  func=_BASILISP_FN_FN_NAME,
@@ -1767,7 +1770,8 @@ def __fn_decorator(
1767
1770
  ),
1768
1771
  ctx=ast.Load(),
1769
1772
  ),
1770
- )
1773
+ ),
1774
+ ast.keyword(arg="max_fixed_arity", value=ast.Constant(max_fixed_arity)),
1771
1775
  ],
1772
1776
  )
1773
1777
 
@@ -1875,6 +1879,7 @@ def __single_arity_fn_to_py_ast( # pylint: disable=too-many-locals
1875
1879
  __fn_decorator(
1876
1880
  (len(fn_args),),
1877
1881
  has_rest_arg=method.is_variadic,
1882
+ max_fixed_arity=node.max_fixed_arity,
1878
1883
  )
1879
1884
  ],
1880
1885
  (
@@ -1905,10 +1910,11 @@ def __multi_arity_dispatch_fn( # pylint: disable=too-many-arguments,too-many-lo
1905
1910
  ctx: GeneratorContext,
1906
1911
  name: str,
1907
1912
  arity_map: Mapping[int, str],
1913
+ *,
1908
1914
  return_tags: Iterable[Node | None],
1909
1915
  default_name: str | None = None,
1910
1916
  rest_arity_fixed_arity: int | None = None,
1911
- max_fixed_arity: int | None = None,
1917
+ max_fixed_arity: int,
1912
1918
  meta_node: MetaNode | None = None,
1913
1919
  is_async: bool = False,
1914
1920
  ) -> GeneratedPyAST[ast.expr]:
@@ -2085,6 +2091,7 @@ def __multi_arity_dispatch_fn( # pylint: disable=too-many-arguments,too-many-lo
2085
2091
  )
2086
2092
  ),
2087
2093
  has_rest_arg=default_name is not None,
2094
+ max_fixed_arity=max_fixed_arity,
2088
2095
  )
2089
2096
  ],
2090
2097
  )
@@ -3688,7 +3695,7 @@ def _const_val_to_py_ast(
3688
3695
  `_const_node_to_py_ast`."""
3689
3696
  try:
3690
3697
  serialized = pickle.dumps(form)
3691
- except (pickle.PicklingError, RecursionError) as e:
3698
+ except (pickle.PicklingError, RecursionError) as e: # pragma: no cover
3692
3699
  # For types without custom "constant" handling code, we defer to pickle
3693
3700
  # to generate a representation that can be reloaded from the generated
3694
3701
  # byte code. There are a few cases where that may not be possible for one
@@ -76,18 +76,28 @@ class ICounted(Sized, ABC):
76
76
  __slots__ = ()
77
77
 
78
78
 
79
- class IIndexed(ICounted, ABC):
80
- """``IIndexed`` is a marker interface for types can be accessed by index.
79
+ K = TypeVar("K")
80
+ V = TypeVar("V")
81
+
82
+
83
+ class IIndexed(ICounted, Generic[V], ABC):
84
+ """``IIndexed`` is an interface for types can be accessed by index.
81
85
 
82
86
  Of the builtin collections, only Vectors are ``IIndexed`` . ``IIndexed`` types
83
87
  respond ``True`` to the :lpy:fn:`indexed?` predicate.
84
88
 
85
89
  .. seealso::
86
90
 
87
- :lpy:fn:`indexed?`"""
91
+ :lpy:fn:`indexed?`, :lpy:fn:`nth`"""
88
92
 
89
93
  __slots__ = ()
90
94
 
95
+ NTH_SENTINEL = object()
96
+
97
+ @abstractmethod
98
+ def nth(self, k: int, notfound: V | None = NTH_SENTINEL) -> V | None: # type: ignore[assignment]
99
+ raise NotImplementedError()
100
+
91
101
 
92
102
  T_ExceptionInfo = TypeVar("T_ExceptionInfo", bound="IPersistentMap")
93
103
 
@@ -109,10 +119,6 @@ class IExceptionInfo(Exception, Generic[T_ExceptionInfo], ABC):
109
119
  raise NotImplementedError()
110
120
 
111
121
 
112
- K = TypeVar("K")
113
- V = TypeVar("V")
114
-
115
-
116
122
  class IMapEntry(Generic[K, V], ABC):
117
123
  """``IMapEntry`` values are produced :lpy:fn:`seq` ing over any
118
124
  :py:class:`IAssociative` (such as a Basilisp map).
@@ -21,7 +21,7 @@ from basilisp.lang.interfaces import (
21
21
  ReduceKVFunction,
22
22
  )
23
23
  from basilisp.lang.obj import (
24
- PRINT_SEPARATOR,
24
+ MAP_PRINT_SEPARATOR,
25
25
  SURPASSED_PRINT_LENGTH,
26
26
  SURPASSED_PRINT_LEVEL,
27
27
  PrintSettings,
@@ -194,7 +194,7 @@ def map_lrepr( # pylint: disable=too-many-locals
194
194
  else:
195
195
  items = list(entry_reprs())
196
196
 
197
- seq_lrepr = PRINT_SEPARATOR.join(items + trailer)
197
+ seq_lrepr = MAP_PRINT_SEPARATOR.join(items + trailer)
198
198
 
199
199
  ns_prefix = ("#:" + ns_name_shared) if ns_name_shared else ""
200
200
  if kwargs["print_meta"] and meta:
@@ -26,7 +26,8 @@ PRINT_LEVEL: PrintCountSetting = None
26
26
  PRINT_META = False
27
27
  PRINT_NAMESPACE_MAPS = False
28
28
  PRINT_READABLY = True
29
- PRINT_SEPARATOR = " "
29
+ SEQ_PRINT_SEPARATOR = " "
30
+ MAP_PRINT_SEPARATOR = ", "
30
31
 
31
32
 
32
33
  class PrintSettings(TypedDict, total=False):
@@ -115,7 +116,7 @@ def seq_lrepr(
115
116
  kw_items = kwargs.copy()
116
117
  kw_items["human_readable"] = False
117
118
  items = list(map(lambda o: lrepr(o, **kw_items), items))
118
- seq_lrepr = PRINT_SEPARATOR.join(items + trailer)
119
+ seq_lrepr = SEQ_PRINT_SEPARATOR.join(items + trailer)
119
120
 
120
121
  print_meta = kwargs["print_meta"]
121
122
  if print_meta and meta:
@@ -1797,7 +1797,7 @@ def _read_next_consuming_comment(ctx: ReaderContext) -> RawReaderForm:
1797
1797
  while True:
1798
1798
  v = _read_next(ctx)
1799
1799
  if v is ctx.eof:
1800
- return ctx.eof
1800
+ return cast(RawReaderForm, ctx.eof)
1801
1801
  if v is COMMENT or isinstance(v, Comment):
1802
1802
  continue
1803
1803
  return v