Skip to content

Commit ec2c6a0

Browse files
authored
basilisp.io namespace (#645)
* basilisp.io namespace * Text text text * Add input-stream and output-stream * writable * Use the existing mode * Fix the thing * Changelog * Not the right place for optimizations * Fun juice * Simpler test init * More stuff and also tests * Unused import * Fix missing paren * Documint * Tests r gud * Additional reader tests * More tests * input-stream tests * output stream test * Copy impl * copy tests * C o p y * Comments * Sure * Lol
1 parent 570079c commit ec2c6a0

File tree

7 files changed

+968
-28
lines changed

7 files changed

+968
-28
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
* Added support for Taps (#631)
1212
* Added support for hierarchies (#633)
1313
* Added support for several more utility Namespace and Var utility functions (#636)
14+
* Added `basilisp.io` namespace with polymorphic reader and writer functions (#645)
1415

1516
### Changed
1617
* PyTest is now an optional extra dependency, rather than a required dependency (#622)
1718
* Generated Python functions corresponding to nested functions are now prefixed with the containing function name, if one exists (#632)
1819
* `basilisp.test/are` docstring now indicates that line numbers may be suppressed on assertion failures created using `are` (#643)
20+
* Multimethods now support providing a custom hierarchy and dispatch to registered values using `isa?` (#644)
1921

2022
### Fixed
2123
* Fixed a bug where `seq`ing co-recursive lazy sequences would cause a stack overflow (#632)

src/basilisp/core.lpy

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1500,6 +1500,17 @@
15001500
(throw
15011501
(python/ValueError (str "cannot coerce " (python/repr x) " to byte"))))))
15021502

1503+
(defn byte-string
1504+
"Coerce x to a byte string (Python `bytes` object).
1505+
1506+
Arguments shall be interpreted exactly as with that object's constructor."
1507+
([x]
1508+
(python/bytes x))
1509+
([x encoding]
1510+
(python/bytes x encoding))
1511+
([x encoding errors]
1512+
(python/bytes x encoding errors)))
1513+
15031514
(defn char
15041515
"Coerce x to a string of length 1.
15051516

@@ -4937,7 +4948,15 @@
49374948
(vector? parent)
49384949
(->> (map (partial isa? h) tag parent)
49394950
(every? identity)))
4940-
(contains? (ancestors h tag) parent))))
4951+
(contains? (ancestors h tag) parent)
4952+
;; in certain cases, in particular with the Python `io` module, the types
4953+
;; in a class's MRO are not identical to the types users have access to.
4954+
;; this is likely the case due to so-called "virtual" subclasses such as
4955+
;; those supported by Python's `abc` module. we need to use `issubclass`
4956+
;; to detect those edge cases.
4957+
(and (instance? python/type tag)
4958+
(instance? python/type parent)
4959+
(python/issubclass tag parent)))))
49414960

49424961
(defn derive
49434962
"Derive a parent/child relationship between `tag` and `parent`.
@@ -6425,6 +6444,53 @@
64256444

64266445
~type-name)))
64276446

6447+
;;;;;;;;;;;;;;;;;;
6448+
;; IO Utilities ;;
6449+
;;;;;;;;;;;;;;;;;;
6450+
6451+
;; This is a circular import since namespaces using 'ns will always try to refer all
6452+
;; symbols from 'basilisp.core. This should be fine since we won't be using anything
6453+
;; from core defined below this section, but still this is a bad pattern and should
6454+
;; not be replicated.
6455+
(require 'basilisp.io)
6456+
6457+
(defn slurp
6458+
"Open a `basilisp.io/reader` instance on `f` and read the contents of `f` into a
6459+
string.
6460+
6461+
Options may be provided as key value pairs and will be passed directly to
6462+
`basilisp.io/reader`. Supported reader options depend on which type of reader is
6463+
selected for `f`. Most readers support the `:encoding` option.
6464+
6465+
If `f` is a string, it first is resolved as a URL (via `urllib.parse.urlparse`).
6466+
If the URL is invalid or refers to a filesystem location (via `file://` scheme),
6467+
then it will be resolved as a local filesystem path.
6468+
6469+
Return the string contents."
6470+
[f & opts]
6471+
(with-open [reader (apply basilisp.io/reader f opts)]
6472+
(.read reader)))
6473+
6474+
(defn spit
6475+
"Open a `basilisp.io/writer` instance on `f` and write `content` out to `f` before
6476+
closing the writer.
6477+
6478+
Options may be provided as key value pairs and will be passed directly to
6479+
`basilisp.io/writer`. Supported writer options depend on which type of writer is
6480+
selected for `f`. Most writers support the `:encoding` option.
6481+
6482+
If `f` is a string, it first is resolved as a URL (via `urllib.parse.urlparse`).
6483+
If the URL is invalid or refers to a filesystem location (via `file://` scheme),
6484+
then it will be resolved as a local filesystem path.
6485+
6486+
`spit` does not support writing to non-file URLs.
6487+
6488+
Return `nil`."
6489+
[f content & opts]
6490+
(with-open [writer (apply basilisp.io/writer f opts)]
6491+
(.write writer content)
6492+
nil))
6493+
64286494
;;;;;;;;;;;;;;;;;
64296495
;; Transducers ;;
64306496
;;;;;;;;;;;;;;;;;

0 commit comments

Comments
 (0)