This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-05-06
Channels
- # announcements (37)
- # babashka (17)
- # beginners (20)
- # calva (2)
- # clj-kondo (15)
- # cljs-dev (1)
- # clojure (6)
- # clojure-austin (2)
- # clojure-china (3)
- # clojure-europe (27)
- # clojure-korea (1)
- # clojure-nl (1)
- # clojure-norway (18)
- # clojurescript (13)
- # conjure (3)
- # datomic (31)
- # events (3)
- # honeysql (14)
- # jobs-discuss (33)
- # leiningen (4)
- # lsp (57)
- # membrane (3)
- # missionary (5)
- # off-topic (1)
- # releases (3)
- # shadow-cljs (18)
- # slack-help (2)
- # specter (2)
- # yamlscript (10)
Introducing https://pypi.org/project/basilisp-kernel/1.0.0/ of the Jupyter https://github.com/ikappaki/basilisp-kernel for the https://basilisp.readthedocs.io/en/latest/ Clojure compatible dialect implemented in Python. Check out the https://github.com/ikappaki/basilisp-kernel/tree/v1.0.0/notebooks directory for some demos, showcasing interoperability with pandas and displaying of matplotlib plots. Features • Full integration with Jupyter Notebook and Jupyter Lab • Autocompletion support • Syntax highlighting and indentation (via https://github.com/nextjournal/clojure-mode) • Seamless interoperability with Python libraries (via https://github.com/basilisp-lang/basilisp)
how does basilisp compare to hy?
You can think of Basilisp as a port of Clojure to Python, it supports (or plans to support) the same data types, collections, API and core libraries as Clojure. If you're interested in the differences between Basilisp and Clojure, please have a look at https://basilisp.readthedocs.io/en/latest/differencesfromclojure.html section for an overview or check out the https://basilisp.readthedocs.io/en/latest/reference.html for more information about the API. On the other hand, https://hylang.org/ is a different lisp dialect, not related to Clojure as far as I can tell. In my opinion a Clojurian should feel at home with Basilisp, but there would be a learning curve to get started with Hy.
I just created #C071RFV2Z1D if anyone wants to chat about it there (it all looks great btw!)
Very interesting - in the early days Hy stuck quite close to Clojure but as it strayed further away I found it harder to use. Great to see an alternative!
Just wanted to say that basilisp is amazing! Basically Clojure on Python, I think this can solve all my needs for scripting.
as i remember it, hy is like squint or fennel: borrows some syntax from clojure but stays closer to the host language (python) in semantics.
I guess I will try to use it to ease some of my Blender scripting (what a convoluted API... specially in the UI!), great work!
Have used Hy with Blender and I can confirm it is fun. I am sure Basilisp would be even better!
@U5R6XUARE did you get Basilisp working with Blender? I tried to get it working but didn't quite understand yet what is the proper way to bootstrap and run Basilisp files (or repl/nrepl) withing the Blender Python process (messed some time with the interactive Python prompt). Gotta familiarize a bit more with the usage in general..
@U06C3BLAH98 No, sorry o/
@U5R6XUARE ok, thank's. I looked at some Vybe-library Python scripting. Cool stuff.
Hi @U06C3BLAH98, I had a quick look at the Blender scripting module, and here some ways you can invoke Basilisp code from the Python Console 1. Install Basilisp using pip
PYTHON INTERACTIVE CONSOLE 3.11.7 (main, Feb 5 2024, 18:45:06) [MSC v.1928 64 bit (AMD64)]
Builtin Modules: bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, bpy.utils, bgl, gpu, blf, mathutils
Convenience Imports: from mathutils import *; from math import *
Convenience Variables: C = bpy.context, D = bpy.data
>>> import pip
>>> pip.main(['install', 'basilisp'])
Collecting basilisp
Obtaining dependency information for basilisp from
# ...
Using cached basilisp-0.1.0b2-py3-none-any.whl (269 kB)
Installing collected packages: basilisp
Successfully installed basilisp-0.1.0b2
# ...
>>>
2. Create a text block in the Blender text editor to bootstrap Basilisp and define some convenient functions. I’ve named this text block bas-eval
:
import bpy
from basilisp import main as basilisp, cli
from basilisp.lang import compiler, runtime
opts = compiler.compiler_opts()
basilisp.init(opts)
ctx = compiler.CompilerContext(filename="blender", opts=opts)
ns = runtime.Namespace.get_or_create(runtime.CORE_NS_SYM)
ns_var = runtime.set_current_ns("blender-user")
eof = object()
def eval_str(code):
return cli.eval_str(code, ctx, ns_var.value, eof)
def eval_editor(text):
code = bpy.data.texts[text].as_string()
return eval_str(code)
def eval_file(filepath):
return cli.eval_file(filepath, ctx, ns_var.value)
eval_str("(ns blender-user (:require clojure.core))")
3. Load the script as a module in the console and evaluate some Clojure code
>>> bas = D.texts["bas-eval"].as_module()
>>> bas.eval_str('(+ 2 1)')
3
Say that you've written some Clojure code in C:/clj/bas-blender/blender.lpy
to clear the scene and add three random monkey heads
(import bpy)
(def objs (-> bpy/data .-objects))
(def mesh (-> bpy/ops .-mesh))
(def outliner (-> bpy .-ops .-outliner))
;; clear scene
(doseq [nm (keys objs)]
(when (re-matches #"Cube|Suzanne.*" nm)
(.remove objs (aget objs nm) ** :do_unlink true)))
(-> bpy .-ops .-outliner .orphans-purge)
;; add three random monkey heads
(dotimes [_ 3]
(.primitive_monkey_add mesh **
:size 2
:location #py ((rand-int 7) (rand-int 7) (rand-int 3))))
You can invoke the script from the console using eval_file
. Three monkey heads should appear in the scene in random locations around the origin
>>> bas.eval_file("C:/clj/bas-blender/blender.lpy")
Info: Deleted 4 data-block(s)
You can also write Clojure code in the blender editor and invoke it by its name. For example, if you save the following in a text block named bas-text
(+ 1 2)
and then invoke it from the console using the eval_editor
fn
>>> bas.eval_editor("bas-test")
3
Let me know of any issuesIt is possible to bring up the nrepl server up in a separate thread using the following script in the editor
from basilisp import cli
import argparse
def start_server():
cli.nrepl_server(None, argparse.Namespace(host="127.0.0.1", port=8889, port_filepath=None))
import threading
server_thread = threading.Thread(target=start_server, daemon=True)
server_thread.start()
and connect to it from CIDER or Calva at port 8889. You can then evaluate any code as normal, but calling any modifying blender API is most likely to crash the application because https://docs.blender.org/api/current/info_gotcha.html#strange-errors-when-using-the-threading-module. Perhaps I can modify the server to yield
where there is no incoming data as an optional feature, but this will require changes in Blender to support it ...Wow, nice @U012BL6D9GE, thank's.
While trying to get it working with my friend earlier it seems that we got stuck running compiler.CompilerContext()
and runtime.Namespace.get_or_create()
without arguments and almost gave up.
With your example evaluating Basilisp in Blender's Python prompt works. Will try out other aspects of it as well..
Pity that nrepl has this threading issue. We looked on it a bit and maybe nrepl could be made to work better if it was written in Blender friendly way. [Basilisp nrepl](https://github.com/ikappaki/basilisp/blob/d539daa7df196702f64160dd95581ce553357e6c/src/basilisp/contrib/nrepl_server.lpy) code seems bit too advanced to understand for now but found a simpler python-nrepl implementation that might be easier as starting point https://gitlab.com/sasanidas/python-nrepl/-/blob/master/nrepl_python/server.py?ref_type=heads.
Introducing https://github.com/favila/enhanced-entity-map, which is a Datomic entity-map replacement with additional enhancements: • Can support metadata. • Can assoc arbitrary keys and values on to it. • Can compute and cache derived attributes via a multimethod. • Can do database reads using the :aevt index selectively. The audience for this library is those who have a large existing codebase using Datomic entity maps already and are encountering modeling or performance problems that are ergonomically uncomfortable to solve without refactoring away from entity maps completely. Please follow up in #datomic
;; associng shadows attributes and derived-attributes (discussed below)
(= :shadowed (:my/id (assoc enhanced-em :my/id :shadowed)))
;; => :shadowed
Extra (= :shadowed
or => true
I use a lot of repl demonstrations in my docs generally, and I should really solve the problem of the doc code not running as expected
entity-map-derived-attribute
looks great!
> This multimethod is only called if the attribute does not exist in the entity map's database! As a consequence, you can't use this feature compute a value for an existing attribute.
I think you can update the doc to make it clear if the multimethod will be called when the attribute do exists in db (it is a valid installed db ident with type and cardinality), but do not exists in the current entity.
I struggled with expressing that, and agree it could be clearer. The actual restriction is specifically if d/attribute
returns non-nil for the attribute after attribute-direction normalization, the multimethod won’t ever be called.
So essentially, if the attribute is in the database, the multimethod won’t be called.
There were some early implementation reasons for this restriction but I’m not sure they hold anymore.
The only downside I can think of now is it will bloat the multimethod and entity-multimethod-value cache if it’s common for calling code to “miss” an attribute lookup on an entity.
seems more like "undefined behavior" currently "don't install multimethod of attributes that exists in the DB. this is an undefined behavior"
Well I did specifically make it act the way it does today (multimethod not called), so I’m not sure I’d call it undefined
Also the multimethod is independent of dbs, so this really isn’t an installation restriction. Some dbs may have the attr, some may not.
Very cool, @U09R86PA4! I'm curious about this: > However you should be really cautious about equality of even normal Datomic entity maps--its semantics are a bit surprising. are you perhaps aware of a place where the 'surprises' are documented?
Most commonly I see people expecting dbs with different basis-t/as-of-t to compare unequal for the same entity id, but that isn’t so
ah ok, thanks @U09R86PA4 - that it's equal even with different basis-ts is a big benefit imho 😄