From b206619877d71503f4e7f257782c32da768e26f3 Mon Sep 17 00:00:00 2001 From: Russ Tokuyama Date: Fri, 18 Oct 2024 21:41:14 -1000 Subject: [PATCH 1/4] Merge upstream changes --- docs/school | 0 scripts/setup-test-deps | 0 scripts/test | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 docs/school mode change 100755 => 100644 scripts/setup-test-deps mode change 100755 => 100644 scripts/test diff --git a/docs/school b/docs/school old mode 100755 new mode 100644 diff --git a/scripts/setup-test-deps b/scripts/setup-test-deps old mode 100755 new mode 100644 diff --git a/scripts/test b/scripts/test old mode 100755 new mode 100644 From 69908d473f7e3e76271e9be61a433fc01a010f6e Mon Sep 17 00:00:00 2001 From: Russ Tokuyama Date: Sat, 16 Nov 2024 23:53:18 -1000 Subject: [PATCH 2/4] Improve Python evaluation and add examples to sandbox.py --- dev/python/sandbox.py | 63 ++++++++++++++++++++-- fnl/conjure/client/python/stdio.fnl | 22 +++++--- lua/conjure/client/python/stdio.lua | 81 ++++++++++++++++++----------- 3 files changed, 126 insertions(+), 40 deletions(-) diff --git a/dev/python/sandbox.py b/dev/python/sandbox.py index ebcb2230..a148f17b 100644 --- a/dev/python/sandbox.py +++ b/dev/python/sandbox.py @@ -1,3 +1,5 @@ +# Should be able to evaluate all of these. + def add(a, b): return a + b @@ -49,6 +51,63 @@ def fn_with_multiline_str(): fn_with_multiline_str() +import csv +from datetime import datetime + + +# Class definition +# - from https://docs.python.org/3/tutorial/classes.html +class Dog: + + def __init__(self, name): + self.name = name + self.tricks = [] + + def add_trick(self, trick): + self.tricks.append(trick) + +d = Dog('Fido') +e = Dog('Buddy') +d.add_trick('roll_over') +e.add_trick('play dead') +d.tricks +e.tricks + + +# Class definition with decorator +# - from https://docs.python.org/3.10/tutorial/classes.html +from dataclasses import dataclass + +@dataclass +class Employee: + name: str + dept: str + salary: int + +john = Employee('john', 'computer lab', 1000) +john.dept +john.salary + + +# Function definition with decorator +# - https://docs.python.org/3.8/library/functools.html?highlight=decorator#functools.cached_property +from functools import lru_cache + +@lru_cache(maxsize=None) +def fib(n): + if n < 2: + return n + return fib(n-1) + fib(n-2) + +[fib(n) for n in range(16)] +# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610] + +fib.cache_info() +# CacheInfo(hits=28, misses=16, maxsize=None, currsize=16) + + +# Asyncio samples +# - Add '-m asyncio' to the python command to evaluate these. """ async def slow_fn(): @@ -68,7 +127,3 @@ async def capture(): await capture() result """ - - -import csv -from datetime import datetime diff --git a/fnl/conjure/client/python/stdio.fnl b/fnl/conjure/client/python/stdio.fnl index 48c4e736..6dbf9a8c 100644 --- a/fnl/conjure/client/python/stdio.fnl +++ b/fnl/conjure/client/python/stdio.fnl @@ -38,13 +38,21 @@ ; "current form" and not be surprised that it wasn't what you thought. (fn form-node? [node] - (or (= "expression_statement" (node:type)) - (= "import_statement" (node:type)) - (= "import_from_statement" (node:type)) - (= "with_statement" (node:type)) - (= "function_definition" (node:type)) - (= "for_statement" (node:type)) - (= "call" (node:type)))) + (log.dbg "form-node?: node:type =" (node:type)) + (log.dbg "form-node?: node:parent =" (node:parent)) + (let [parent (node:parent)] + (if (= "expression_statement" (node:type)) true + (= "import_statement" (node:type)) true + (= "import_from_statement" (node:type)) true + (= "with_statement" (node:type)) true + (= "decorated_definition" (node:type)) true + (= "for_statement" (node:type)) true + (= "call" (node:type)) true + (and (= "class_definition" (node:type)) + (not (= "decorated_definition" (parent:type)))) true + (and (= "function_definition" (node:type)) + (not (= "decorated_definition" (parent:type)))) true + false))) (fn with-repl-or-warn [f opts] (let [repl (state :repl)] diff --git a/lua/conjure/client/python/stdio.lua b/lua/conjure/client/python/stdio.lua index 3da6ad12..a3d56258 100644 --- a/lua/conjure/client/python/stdio.lua +++ b/lua/conjure/client/python/stdio.lua @@ -26,7 +26,30 @@ state = client["new-state"](_3_) local buf_suffix = ".py" local comment_prefix = "# " local function form_node_3f(node) - return (("expression_statement" == node:type()) or ("import_statement" == node:type()) or ("import_from_statement" == node:type()) or ("with_statement" == node:type()) or ("function_definition" == node:type()) or ("for_statement" == node:type()) or ("call" == node:type())) + log.dbg("form-node?: node:type =", node:type()) + log.dbg("form-node?: node:parent =", node:parent()) + local parent = node:parent() + if ("expression_statement" == node:type()) then + return true + elseif ("import_statement" == node:type()) then + return true + elseif ("import_from_statement" == node:type()) then + return true + elseif ("with_statement" == node:type()) then + return true + elseif ("decorated_definition" == node:type()) then + return true + elseif ("for_statement" == node:type()) then + return true + elseif ("call" == node:type()) then + return true + elseif (("class_definition" == node:type()) and not ("decorated_definition" == parent:type())) then + return true + elseif (("function_definition" == node:type()) and not ("decorated_definition" == parent:type())) then + return true + else + return false + end end local function with_repl_or_warn(f, opts) local repl = state("repl") @@ -37,12 +60,12 @@ local function with_repl_or_warn(f, opts) end end local function is_assignment_3f(node) - local and_5_ = (node:child_count() == 1) - if and_5_ then + local and_6_ = (node:child_count() == 1) + if and_6_ then local child = node:child(0) - and_5_ = (child:type() == "assignment") + and_6_ = (child:type() == "assignment") end - return and_5_ + return and_6_ end local function is_expression_3f(node) return (("expression_statement" == node:type()) and not is_assignment_3f(node)) @@ -69,19 +92,19 @@ local function is_dots_3f(s) return (string.sub(s, 1, 3) == "...") end local function format_msg(msg) - local function _8_(_241) + local function _9_(_241) return not is_dots_3f(_241) end - local function _9_(_241) + local function _10_(_241) return ("" ~= _241) end - return a.filter(_8_, a.filter(_9_, text["split-lines"](msg))) + return a.filter(_9_, a.filter(_10_, text["split-lines"](msg))) end local function get_console_output_msgs(msgs) - local function _10_(_241) + local function _11_(_241) return (comment_prefix .. "(out) " .. _241) end - return a.map(_10_, a.butlast(msgs)) + return a.map(_11_, a.butlast(msgs)) end local function get_expression_result(msgs) local result = a.last(msgs) @@ -92,10 +115,10 @@ local function get_expression_result(msgs) end end local function unbatch(msgs) - local function _12_(_241) + local function _13_(_241) return (a.get(_241, "out") or a.get(_241, "err")) end - return str.join("", a.map(_12_, msgs)) + return str.join("", a.map(_13_, msgs)) end local function log_repl_output(msgs) local msgs0 = format_msg(unbatch(msgs)) @@ -112,8 +135,8 @@ local function log_repl_output(msgs) end end local function eval_str(opts) - local function _15_(repl) - local function _16_(msgs) + local function _16_(repl) + local function _17_(msgs) log_repl_output(msgs) if opts["on-result"] then local msgs0 = format_msg(unbatch(msgs)) @@ -123,9 +146,9 @@ local function eval_str(opts) return nil end end - return repl.send(prep_code(opts.code), _16_, {["batch?"] = true}) + return repl.send(prep_code(opts.code), _17_, {["batch?"] = true}) end - return with_repl_or_warn(_15_) + return with_repl_or_warn(_16_) end local function eval_file(opts) return eval_str(a.assoc(opts, "code", a.slurp(opts["file-path"]))) @@ -159,29 +182,29 @@ local function start() if state("repl") then return log.append({(comment_prefix .. "Can't start, REPL is already running."), (comment_prefix .. "Stop the REPL with " .. config["get-in"]({"mapping", "prefix"}) .. cfg({"mapping", "stop"}))}, {["break?"] = true}) else - local function _20_() + local function _21_() if vim.treesitter.language.require_language then return vim.treesitter.language.require_language("python") else return vim.treesitter.require_language("python") end end - if not pcall(_20_) then + if not pcall(_21_) then return log.append({(comment_prefix .. "(error) The python client requires a python treesitter parser in order to function."), (comment_prefix .. "(error) See https://github.com/nvim-treesitter/nvim-treesitter"), (comment_prefix .. "(error) for installation instructions.")}) else - local function _22_() - local function _23_(repl) - local function _24_(msgs) + local function _23_() + local function _24_(repl) + local function _25_(msgs) return nil end - return repl.send(prep_code(initialise_repl_code), _24_, nil) + return repl.send(prep_code(initialise_repl_code), _25_, nil) end - return display_repl_status("started", with_repl_or_warn(_23_)) + return display_repl_status("started", with_repl_or_warn(_24_)) end - local function _25_(err) + local function _26_(err) return display_repl_status(err) end - local function _26_(code, signal) + local function _27_(code, signal) if (("number" == type(code)) and (code > 0)) then log.append({(comment_prefix .. "process exited with code " .. code)}) else @@ -192,10 +215,10 @@ local function start() end return stop() end - local function _29_(msg) + local function _30_(msg) return log.dbg(format_msg(unbatch({msg})), {["join-first?"] = true}) end - return a.assoc(state(), "repl", stdio.start({["prompt-pattern"] = cfg({"prompt-pattern"}), cmd = cfg({"command"}), ["delay-stderr-ms"] = cfg({"delay-stderr-ms"}), ["on-success"] = _22_, ["on-error"] = _25_, ["on-exit"] = _26_, ["on-stray-output"] = _29_})) + return a.assoc(state(), "repl", stdio.start({["prompt-pattern"] = cfg({"prompt-pattern"}), cmd = cfg({"command"}), ["delay-stderr-ms"] = cfg({"delay-stderr-ms"}), ["on-success"] = _23_, ["on-error"] = _26_, ["on-exit"] = _27_, ["on-stray-output"] = _30_})) end end end @@ -203,11 +226,11 @@ local function on_exit() return stop() end local function interrupt() - local function _32_(repl) + local function _33_(repl) log.append({(comment_prefix .. " Sending interrupt signal.")}, {["break?"] = true}) return repl["send-signal"](vim.loop.constants.SIGINT) end - return with_repl_or_warn(_32_) + return with_repl_or_warn(_33_) end local function on_load() if config["get-in"]({"client_on_load"}) then From 6ef969d2952f76d8f721b5698a2d2c038189d562 Mon Sep 17 00:00:00 2001 From: Russ Tokuyama Date: Sun, 17 Nov 2024 00:00:48 -1000 Subject: [PATCH 3/4] Remove empty files --- scripts/setup-test-deps | 29 ----------------------------- scripts/test | 6 ------ 2 files changed, 35 deletions(-) delete mode 100644 scripts/setup-test-deps delete mode 100644 scripts/test diff --git a/scripts/setup-test-deps b/scripts/setup-test-deps deleted file mode 100644 index 37bc882a..00000000 --- a/scripts/setup-test-deps +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -PACK_DIR=./.test-config/nvim/pack/conjure-tests/start - -mkdir -p "$PACK_DIR" - -if [ -d "$PACK_DIR/plenary.nvim" ]; then - echo "plenary.nvim already exists" -else - git clone https://github.com/nvim-lua/plenary.nvim.git "$PACK_DIR/plenary.nvim" -fi - -if [ -d "$PACK_DIR/fennel.vim" ]; then - echo "fennel.vim already exists" -else - git clone https://github.com/bakpakin/fennel.vim.git "$PACK_DIR/fennel.vim" -fi - -if [ -d "$PACK_DIR/aniseed" ]; then - echo "aniseed already exists" -else - git clone https://github.com/Olical/aniseed.git "$PACK_DIR/aniseed" -fi - -if [ -d "$PACK_DIR/conjure" ]; then - echo "conjure (symlink) already exists" -else - ln -s "${GITHUB_WORKSPACE:-$(pwd)}" "$PACK_DIR/conjure" -fi diff --git a/scripts/test b/scripts/test deleted file mode 100644 index 61c8e11f..00000000 --- a/scripts/test +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -XDG_CONFIG_HOME=$(pwd)/.test-config -export XDG_CONFIG_HOME - -nvim --headless -c 'PlenaryBustedDirectory lua/conjure-spec' From c39e9b796bd6bd31df5ec1752f17f0d358d73b72 Mon Sep 17 00:00:00 2001 From: Russ Tokuyama Date: Sun, 17 Nov 2024 00:04:39 -1000 Subject: [PATCH 4/4] Restore scripts/setup-test-deps and scripts/test --- scripts/setup-test-deps | 29 +++++++++++++++++++++++++++++ scripts/test | 6 ++++++ 2 files changed, 35 insertions(+) create mode 100755 scripts/setup-test-deps create mode 100755 scripts/test diff --git a/scripts/setup-test-deps b/scripts/setup-test-deps new file mode 100755 index 00000000..37bc882a --- /dev/null +++ b/scripts/setup-test-deps @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +PACK_DIR=./.test-config/nvim/pack/conjure-tests/start + +mkdir -p "$PACK_DIR" + +if [ -d "$PACK_DIR/plenary.nvim" ]; then + echo "plenary.nvim already exists" +else + git clone https://github.com/nvim-lua/plenary.nvim.git "$PACK_DIR/plenary.nvim" +fi + +if [ -d "$PACK_DIR/fennel.vim" ]; then + echo "fennel.vim already exists" +else + git clone https://github.com/bakpakin/fennel.vim.git "$PACK_DIR/fennel.vim" +fi + +if [ -d "$PACK_DIR/aniseed" ]; then + echo "aniseed already exists" +else + git clone https://github.com/Olical/aniseed.git "$PACK_DIR/aniseed" +fi + +if [ -d "$PACK_DIR/conjure" ]; then + echo "conjure (symlink) already exists" +else + ln -s "${GITHUB_WORKSPACE:-$(pwd)}" "$PACK_DIR/conjure" +fi diff --git a/scripts/test b/scripts/test new file mode 100755 index 00000000..61c8e11f --- /dev/null +++ b/scripts/test @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +XDG_CONFIG_HOME=$(pwd)/.test-config +export XDG_CONFIG_HOME + +nvim --headless -c 'PlenaryBustedDirectory lua/conjure-spec'