From e4ed784fbffc90a2732bddb12b1fdf828cd393f0 Mon Sep 17 00:00:00 2001 From: Rens Date: Mon, 21 Jul 2025 13:05:44 +0200 Subject: [PATCH 1/3] add writefile --- 00_core.ipynb | 191 +++++++++++++++++++++++++---------------------- pshnb/_modidx.py | 1 + pshnb/core.py | 14 +++- 3 files changed, 112 insertions(+), 94 deletions(-) diff --git a/00_core.ipynb b/00_core.ipynb index 0e0469f..1386aa4 100644 --- a/00_core.ipynb +++ b/00_core.ipynb @@ -31,11 +31,8 @@ "import pexpect, re, os, shutil\n", "from pexpect import TIMEOUT\n", "from pathlib import Path\n", - "from getpass import getpass\n", - "from IPython.core.magic import register_cell_magic, no_var_expand\n", - "from IPython.display import display, Javascript\n", + "from IPython.core.magic import no_var_expand\n", "from IPython.paths import get_ipython_dir\n", - "from IPython.core.interactiveshell import InteractiveShell\n", "from IPython.core.magic_arguments import magic_arguments, argument" ] }, @@ -140,9 +137,22 @@ "name": "stdout", "output_type": "stream", "text": [ + "\n", + "% \r\n", + " \r\n", + "\r\n", + " \r\n", + "\u001b[?2004hls | head -3\u001b[?2004l\r\n", + "\r\n", "00_core.ipynb\r\n", "CHANGELOG.md\r\n", "index.ipynb\r\n", + "% \r\n", + " \r\n", + "\r\n", + " \r\n", + "\u001b[?2004hecho b37d9bf3d74fdd06\u001b[?2004l\r\n", + "\r\n", "\n" ] } @@ -377,7 +387,14 @@ " except Exception as e:\n", " self.o = None\n", " raise e from None\n", - " if disp and res: print(res)" + " if disp and res: print(res)\n", + "\n", + " def writefile(self, line, cell):\n", + " \"Write cell contents to a file in the current shell directory\"\n", + " if not line.strip(): raise ValueError(\"Must specify a filename\")\n", + " if not self.o: self.reset() \n", + " fp = Path(self.o('pwd').strip()) / line.strip().split()[0]\n", + " fp.write_text(cell)" ] }, { @@ -399,17 +416,17 @@ "def create_magic(shell=None):\n", " if not shell: shell = get_ipython()\n", " magic = PshMagic(shell)\n", - " shell.register_magic_function(magic.bash, magic_name='bash', magic_kind='line_cell')" + " shell.register_magic_function(magic.bash, magic_name='bash', magic_kind='line_cell')\n", + " shell.register_magic_function(magic.writefile, magic_name='writefile', magic_kind='cell')\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "858b3925", + "id": "ebb1f44e", "metadata": {}, "outputs": [], "source": [ - "# Only required if you don't load the extension\n", "create_magic()" ] }, @@ -423,7 +440,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "/Users/jhoward/aai-ws/pshnb\n" + "/Users/rensdimmendaal/git/repos/pshnb\n" ] } ], @@ -431,6 +448,18 @@ "%bash pwd" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "e175cbc4", + "metadata": {}, + "outputs": [], + "source": [ + "%%bash\n", + "mkdir -p /tmp/pshnb-demo\n", + "cd /tmp/pshnb-demo" + ] + }, { "cell_type": "code", "execution_count": null, @@ -441,56 +470,67 @@ "name": "stdout", "output_type": "stream", "text": [ - "00_core.ipynb\tLICENSE\t\tpshnb.egg-info\tsettings.ini\r\n", - "CHANGELOG.md\tMANIFEST.in\tpyproject.toml\tsetup.py\r\n", - "index.ipynb\tpshnb\t\tREADME.md\tstyles.css\n" + "/tmp/pshnb-demo\n" ] } ], "source": [ - "%bash ls -h" + "%bash pwd" ] }, { "cell_type": "code", "execution_count": null, - "id": "4c0f8e60", + "id": "52112f28", "metadata": {}, "outputs": [], "source": [ - "%bash cd .." + "%%bash\n", + "cat > tmp << EOF\n", + "hi\n", + "there\n", + "EOF" + ] + }, + { + "cell_type": "markdown", + "id": "a6464647", + "metadata": {}, + "source": [ + "We can also use the writefile magic to write in the current working directory:" ] }, { "cell_type": "code", "execution_count": null, - "id": "9b4392f0", + "id": "5185387f", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "/Users/jhoward/aai-ws\n" - ] - } - ], + "outputs": [], "source": [ - "%bash pwd" + "%%writefile file1.txt\n", + "hello" ] }, { "cell_type": "code", "execution_count": null, - "id": "52112f28", + "id": "ae7d956b", "metadata": {}, "outputs": [], "source": [ - "%%bash\n", - "cat > tmp << EOF\n", - "hi\n", - "there\n", - "EOF" + "%%writefile file2.txt\n", + "good afternoon" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22989860", + "metadata": {}, + "outputs": [], + "source": [ + "%%writefile file3.txt\n", + "goodbye" ] }, { @@ -503,13 +543,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "hi\r\n", - "there\n" + "file1.txt\tfile2.txt\tfile3.txt\ttmp\n" ] } ], "source": [ - "%bash cat tmp" + "%bash ls" ] }, { @@ -532,9 +571,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "_nbs\r\n", - "_proc\r\n", - "addnew.py\n" + "file1.txt\r\n", + "file2.txt\r\n", + "file3.txt\n" ] } ], @@ -580,8 +619,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "_nbs\r\n", - "_proc\n" + "file1.txt\r\n", + "file2.txt\n" ] } ], @@ -600,7 +639,7 @@ "output_type": "stream", "text": [ "starting\r\n", - "[1] 18411\n" + "[1] 80308\n" ] } ], @@ -615,17 +654,7 @@ "execution_count": null, "id": "58be93c1", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "finished\r\n", - "\r\n", - "[1]+ Done ( sleep 1; echo finished )\n" - ] - } - ], + "outputs": [], "source": [ "%bash" ] @@ -678,7 +707,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "/Users/jhoward/aai-ws\n" + "/tmp/pshnb-demo\n" ] } ], @@ -714,7 +743,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "/Users/jhoward/aai-ws/pshnb\n" + "/Users/rensdimmendaal/git/repos/pshnb\n" ] } ], @@ -732,7 +761,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "/opt/homebrew/bin/bash\n" + "/bin/zsh\n" ] } ], @@ -749,31 +778,22 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "8673aa0e", + "cell_type": "markdown", + "id": "1ac6e642", "metadata": {}, - "outputs": [], "source": [ - "%bash -s" + "NB: requires passwordless sudo to use this:" ] }, { "cell_type": "code", "execution_count": null, - "id": "7125b817", + "id": "8673aa0e", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "root\n" - ] - } - ], + "outputs": [], "source": [ - "%bash whoami" + "# %bash -s\n", + "# %bash whoami" ] }, { @@ -789,26 +809,17 @@ "execution_count": null, "id": "1169a0ab", "metadata": {}, - "outputs": [], - "source": [ - "%bash -S" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a2193f7e", - "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "jhoward\n" + "rensdimmendaal\n" ] } ], "source": [ + "%bash -S\n", "%bash whoami" ] }, @@ -849,6 +860,14 @@ "except TIMEOUT: print(\"timed out\")" ] }, + { + "cell_type": "markdown", + "id": "7ccace01", + "metadata": {}, + "source": [ + "## Configuration" + ] + }, { "cell_type": "code", "execution_count": null, @@ -900,14 +919,6 @@ "from nbdev.doclinks import nbdev_export\n", "nbdev_export()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "451d1ea6", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/pshnb/_modidx.py b/pshnb/_modidx.py index bc77bc9..952b5ed 100644 --- a/pshnb/_modidx.py +++ b/pshnb/_modidx.py @@ -13,6 +13,7 @@ 'pshnb.core.PshMagic.bash': ('core.html#pshmagic.bash', 'pshnb/core.py'), 'pshnb.core.PshMagic.help': ('core.html#pshmagic.help', 'pshnb/core.py'), 'pshnb.core.PshMagic.reset': ('core.html#pshmagic.reset', 'pshnb/core.py'), + 'pshnb.core.PshMagic.writefile': ('core.html#pshmagic.writefile', 'pshnb/core.py'), 'pshnb.core.ShellInterpreter': ('core.html#shellinterpreter', 'pshnb/core.py'), 'pshnb.core.ShellInterpreter.__call__': ('core.html#shellinterpreter.__call__', 'pshnb/core.py'), 'pshnb.core.ShellInterpreter.__init__': ('core.html#shellinterpreter.__init__', 'pshnb/core.py'), diff --git a/pshnb/core.py b/pshnb/core.py index f7141ef..1f7454f 100644 --- a/pshnb/core.py +++ b/pshnb/core.py @@ -10,11 +10,8 @@ import pexpect, re, os, shutil from pexpect import TIMEOUT from pathlib import Path -from getpass import getpass -from IPython.core.magic import register_cell_magic, no_var_expand -from IPython.display import display, Javascript +from IPython.core.magic import no_var_expand from IPython.paths import get_ipython_dir -from IPython.core.interactiveshell import InteractiveShell from IPython.core.magic_arguments import magic_arguments, argument # %% ../00_core.ipynb @@ -118,11 +115,20 @@ def bash(self, line, cell=None): raise e from None if disp and res: print(res) + def writefile(self, line, cell): + "Write cell contents to a file in the current shell directory" + if not line.strip(): raise ValueError("Must specify a filename") + if not self.o: self.reset() + fp = Path(self.o('pwd').strip()) / line.strip().split()[0] + fp.write_text(cell) + # %% ../00_core.ipynb def create_magic(shell=None): if not shell: shell = get_ipython() magic = PshMagic(shell) shell.register_magic_function(magic.bash, magic_name='bash', magic_kind='line_cell') + shell.register_magic_function(magic.writefile, magic_name='writefile', magic_kind='cell') + # %% ../00_core.ipynb def load_ipython_extension(ipython): From 5304bb0b1415417c86359880d3703bca482e7904 Mon Sep 17 00:00:00 2001 From: Rens Date: Mon, 21 Jul 2025 13:11:44 +0200 Subject: [PATCH 2/3] default to bash also in first example --- 00_core.ipynb | 30 +++++++++++++----------------- pshnb/core.py | 1 - 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/00_core.ipynb b/00_core.ipynb index 1386aa4..a8653dd 100644 --- a/00_core.ipynb +++ b/00_core.ipynb @@ -29,13 +29,22 @@ "#| export\n", "from fastcore.utils import *\n", "import pexpect, re, os, shutil\n", - "from pexpect import TIMEOUT\n", "from pathlib import Path\n", "from IPython.core.magic import no_var_expand\n", "from IPython.paths import get_ipython_dir\n", "from IPython.core.magic_arguments import magic_arguments, argument" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "d229ee7f", + "metadata": {}, + "outputs": [], + "source": [ + "from pexpect import TIMEOUT" + ] + }, { "cell_type": "code", "execution_count": null, @@ -62,7 +71,7 @@ "outputs": [], "source": [ "env = dict(os.environ, TERM='dumb', PS1='$', PS2='$')\n", - "eshell = os.environ['SHELL']\n", + "eshell = '/bin/bash'\n", "sh = pexpect.spawn(eshell, encoding='utf-8', env=env)" ] }, @@ -137,22 +146,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", - "% \r\n", - " \r\n", - "\r\n", - " \r\n", - "\u001b[?2004hls | head -3\u001b[?2004l\r\n", - "\r\n", "00_core.ipynb\r\n", "CHANGELOG.md\r\n", "index.ipynb\r\n", - "% \r\n", - " \r\n", - "\r\n", - " \r\n", - "\u001b[?2004hecho b37d9bf3d74fdd06\u001b[?2004l\r\n", - "\r\n", "\n" ] } @@ -638,8 +634,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "starting\r\n", - "[1] 80308\n" + "starting\n", + "[1] 81506\n" ] } ], diff --git a/pshnb/core.py b/pshnb/core.py index 1f7454f..1a19f27 100644 --- a/pshnb/core.py +++ b/pshnb/core.py @@ -8,7 +8,6 @@ # %% ../00_core.ipynb from fastcore.utils import * import pexpect, re, os, shutil -from pexpect import TIMEOUT from pathlib import Path from IPython.core.magic import no_var_expand from IPython.paths import get_ipython_dir From ecee7c1d685a292f68e9dabc823fbf38221bc3f7 Mon Sep 17 00:00:00 2001 From: Rens Date: Mon, 21 Jul 2025 13:25:58 +0200 Subject: [PATCH 3/3] add append mode to %%writefile --- 00_core.ipynb | 53 +++++++++++++++++++++++++++++++++++++++++++++------ pshnb/core.py | 11 +++++++---- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/00_core.ipynb b/00_core.ipynb index a8653dd..be25784 100644 --- a/00_core.ipynb +++ b/00_core.ipynb @@ -385,12 +385,15 @@ " raise e from None\n", " if disp and res: print(res)\n", "\n", + " @magic_arguments()\n", + " @argument('-a', '--append', action='store_true', help='Append contents of the cell to an existing file. The file will be created if it does not exist.')\n", + " @argument('filename', help='File to write')\n", + " @no_var_expand\n", " def writefile(self, line, cell):\n", " \"Write cell contents to a file in the current shell directory\"\n", - " if not line.strip(): raise ValueError(\"Must specify a filename\")\n", - " if not self.o: self.reset() \n", - " fp = Path(self.o('pwd').strip()) / line.strip().split()[0]\n", - " fp.write_text(cell)" + " args = self.writefile.parser.parse_args(line.split())\n", + " fp = Path(self.o('pwd').strip()) / args.filename \n", + " with open(fp, 'a' if args.append else 'w') as f: f.write(cell)" ] }, { @@ -529,6 +532,44 @@ "goodbye" ] }, + { + "cell_type": "markdown", + "id": "be0ff6d0", + "metadata": {}, + "source": [ + "we can also append to files" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3492464b", + "metadata": {}, + "outputs": [], + "source": [ + "%%writefile -a file3.txt\n", + "and thanks for all the fish" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9e8baf39", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "goodbye\r\n", + "and thanks for all the fish\n" + ] + } + ], + "source": [ + "%bash cat file3.txt" + ] + }, { "cell_type": "code", "execution_count": null, @@ -634,8 +675,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "starting\n", - "[1] 81506\n" + "starting\r\n", + "[1] 82032\n" ] } ], diff --git a/pshnb/core.py b/pshnb/core.py index 1a19f27..b7c47ed 100644 --- a/pshnb/core.py +++ b/pshnb/core.py @@ -114,12 +114,15 @@ def bash(self, line, cell=None): raise e from None if disp and res: print(res) + @magic_arguments() + @argument('-a', '--append', action='store_true', help='Append contents of the cell to an existing file. The file will be created if it does not exist.') + @argument('filename', help='File to write') + @no_var_expand def writefile(self, line, cell): "Write cell contents to a file in the current shell directory" - if not line.strip(): raise ValueError("Must specify a filename") - if not self.o: self.reset() - fp = Path(self.o('pwd').strip()) / line.strip().split()[0] - fp.write_text(cell) + args = self.writefile.parser.parse_args(line.split()) + fp = Path(self.o('pwd').strip()) / args.filename + with open(fp, 'a' if args.append else 'w') as f: f.write(cell) # %% ../00_core.ipynb def create_magic(shell=None):