Fork me on GitHub
#announcements
<
2024-05-06
>
chaos13:05:12

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)

👍 8
💚 7
🎉 4
Aziz Aldawood15:05:37

how does basilisp compare to hy?

chaos16:05:12

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.

👍 3
clojure-spin 1
refset16:05:03

I just created #C071RFV2Z1D if anyone wants to chat about it there (it all looks great btw!)

Chris McCormick08:05:34

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!

markx04:05:33

Just wanted to say that basilisp is amazing! Basically Clojure on Python, I think this can solve all my needs for scripting.

👍 6
Noah Bogart13:05:55

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.

didibus00:05:57

Nice, I hadn't heard of that one. I love me some Clojure-ports 😄

pfeodrippe03:05:52

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!

Chris McCormick11:05:52

Have used Hy with Blender and I can confirm it is fun. I am sure Basilisp would be even better!

❤️ 2
jasalt18:07:04

@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..

jasalt07:07:52

@U5R6XUARE ok, thank's. I looked at some Vybe-library Python scripting. Cool stuff.

❤️ 1
chaos21:07:23

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 issues

chaos21:07:40

It 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 ...

jasalt17:07:33

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..

jasalt17:07:15

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.

favila13:05:30

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

🎉 7
datomic 4
souenzzo15:05:44

;; associng shadows attributes and derived-attributes (discussed below)
(= :shadowed (:my/id (assoc enhanced-em :my/id :shadowed)))
;; => :shadowed
Extra (= :shadowed or => true

favila15:05:20

Yeah I saw that later :)

favila15:05:31

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

souenzzo15:05:42

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.

favila16:05:30

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.

favila16:05:50

So essentially, if the attribute is in the database, the multimethod won’t be called.

👍 1
favila16:05:15

I’m not 100% on that restriction and may relax it

souenzzo16:05:16

So it can't behave as "default value", right?!

favila16:05:56

Right, essentially

favila16:05:20

There were some early implementation reasons for this restriction but I’m not sure they hold anymore.

favila16:05:42

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.

souenzzo16:05:05

seems more like "undefined behavior" currently "don't install multimethod of attributes that exists in the DB. this is an undefined behavior"

favila16:05:22

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

favila16:05:08

Also the multimethod is independent of dbs, so this really isn’t an installation restriction. Some dbs may have the attr, some may not.

👍 1
robert-stuttaford05:05:07

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?

favila10:05:51

No, but I could write it up

favila10:05:47

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

favila10:05:22

The only factors considered are the invisible db id and the entity id

robert-stuttaford12:05:01

ah ok, thanks @U09R86PA4 - that it's equal even with different basis-ts is a big benefit imho 😄