<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>emre şahin's digital garden 🍃 - python-bindings</title>
    <link>https://emresahin.net/tags/python-bindings/</link>
    <description>Posts in the python-bindings tag</description>
    <language>en</language>
    <managingEditor>contact@emresahin.net (Emre Şahin)</managingEditor>
    <lastBuildDate>Tue, 15 Sep 2026 19:46:32 +0000</lastBuildDate>
    <atom:link href="https://emresahin.net/tags/python-bindings/rss.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>devlog 2</title>
      <published>2024-05-26T17:29:09+00:00</published>
      <updated>2024-05-26T17:29:09+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Sun, 26 May 2024 17:29:09 +0000</pubDate>
      <link>https://emresahin.net/devlog-2/</link>
      <guid isPermaLink="true">https://emresahin.net/devlog-2/</guid>
      <description>We were debugging Python bindings for Xvc. xvc.file.track enters an infinite loop when given a non-existent path. To make debugging easier, we can add file deletions in the ./start-readme script to the notebook itself. Instead, I’ll run my watcher run-after-commit.sh to ensure that the files are ...</description>
      <category>devlog</category>
      <category>xvc</category>
      <category>xvc</category>
      <category>jupyter</category>
      <category>xvc-config</category>
      <category>xvc-file</category>
      <category>repr</category>
      <category>python-bindings</category>
      <category>debugging</category>
      <content:encoded><![CDATA[<p>We were debugging Python bindings for Xvc. <code>xvc.file.track</code> enters an infinite
loop when given a non-existent path.</p>
<p>To make debugging easier, we can add file deletions in the <code>./start-readme</code> script
to the notebook itself.</p>
<p>Instead, I’ll run my watcher <code>run-after-commit.sh</code> to ensure that the files
are deleted after commits.</p>
<p>That may also work; you can use both as well.</p>
<p>I noticed cli-opts pass <code>--no-system-config</code> etc. by default. Let’s deal with
this first.</p>
<p>I fixed that.</p>
<p>I’m testing whether we are in the directory that we should be in with
<code>xvc.root("--absolute")</code>, but it looks like it’s not possible to pass a string
argument to the command.</p>
<p>Let me take a look at this.</p>
<p>It looks like there have been some changes in optional parameter handling in PyO3.
You may need to deal with keyword arguments with decorators.</p>
<p>Now, let’s try <code>xvc.file().track()</code> once more with <code>dir-0001/</code>.</p>
<p>It seems to be working now. With an existing directory, it doesn’t show an
error.</p>
<p>What does <code>xvc.file().list()</code> show?</p>
<p>It shows a single string with <code>\n</code> in it. It looks like we need to handle this in
the output thread.</p>
<p>I added a <code>replace("\\n", "\n")</code> to <code>output_str</code> at the end, but it didn’t make a
difference. I tested in the notebook with <code>list_result.split("\n")</code>, and these
<code>\n</code> characters are indeed CRLF. So Jupyter shows CRLF in strings with <code>\n</code>, and
this is not something we should try to fix, I think.</p>
<p>You can search how to show <code>\n</code> characters in a Jupyter notebook with CRLF.</p>
<p>The output string should be fed into <code>repr</code>, as in:</p>
<pre><code class="language-python"># Define a string with CRLF characters
text_crlf = "Hello\r\nWorld\r\nThis is a test string."

# Use repr to show the \r\n characters explicitly
print(repr(text_crlf))
</code></pre>
<p>I tested this, and GPT misleads. <code>repr</code> is when you <em>want</em> to show <code>\n</code>, not
vice versa. When I <code>print(list_result)</code>, it prints the results properly.</p>
<p>It looks like we don’t need to make this a priority now. We can tell the user in the
notebook that the commands are intentionally returning strings, and they can
process or print them however they want.</p>]]></content:encoded>
    </item>
    <item>
      <title>Devlog 1: XVC Root and Python Bindings Debugging</title>
      <published>2024-05-24T10:12:50+00:00</published>
      <updated>2024-05-24T10:12:50+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Fri, 24 May 2024 10:12:50 +0000</pubDate>
      <link>https://emresahin.net/devlog-1/</link>
      <guid isPermaLink="true">https://emresahin.net/devlog-1/</guid>
      <description>I should have a dispatch method that receives an XvcRootOpt and runs a command with it. The dispatcher can also update the XvcRoot from None to Some(XvcRoot) in some cases, so it should receive a mutable XvcRootOpt or return one after receiving ownership. The issue with having a mutable element i...</description>
      <category>Devlog</category>
      <category>XVC</category>
      <category>xvc</category>
      <category>debugging</category>
      <category>shell</category>
      <category>jupyter-lab</category>
      <category>rust</category>
      <category>python-bindings</category>
      <content:encoded><![CDATA[<p>I should have a dispatch method that receives an <code>XvcRootOpt</code> and runs a command
with it. The dispatcher can also update the <code>XvcRoot</code> from <code>None</code> to <code>Some(XvcRoot)</code>
in some cases, so it should receive a mutable <code>XvcRootOpt</code> or return one after
receiving ownership.</p>
<p>The issue with having a mutable element is that we need to update <code>XvcRoot</code> from
<code>Arc&lt;XvcRootInner&gt;</code> to <code>Arc&lt;RwLock&lt;XvcRootInner&gt;&gt;</code>, which will cause almost all
machinery around <code>XvcRoot</code> to require locking the object first. This is too
large a refactoring.</p>
<p>However, I can write an <code>xvc_root!</code> macro to replace <code>xvc_root.read()</code> or
whatever is required to minimize the code changes. <code>XvcRoot</code> can also be a wrapper
object, but that’s too much fuss, and the responsibility may be misplaced.</p>
<p>Let’s update the type and let the dispatcher update <code>XvcRootInner</code> only
when necessary. Let’s see what will require updating.</p>
<hr>
<p>We have a bug in the Python bindings where <code>xvc.file.track()</code> enters an infinite loop.</p>
<p>There can be multiple reasons, but are you sure that the <code>xvc</code> CLI works with the
same command?</p>
<p>Let’s start testing by creating another notebook server.</p>
<p>The notebook creates an Xvc repo successfully and returns the root with
<code>xvc.root()</code>, but <code>xvc.file().track("test-data/dir-0001/")</code> never finishes.</p>
<p>It’s likely that this is caused by something in the background threads.</p>
<p>The CLI command completes successfully, but we may be passing the command
incorrectly. Let’s try <code>dir-0001</code> only.</p>
<p>Even if an incorrect path is provided, it shouldn’t enter an infinite loop.</p>
<p>When I provide the correct path, <code>dir-0001</code>, it returns. There may be something going on with finding the root of the Xvc repo.</p>
<p>It returns, but it’s also giving an error that it cannot find a repository. I should take a closer look.</p>
<p>The <code>Xvc</code> struct wasn’t implementing <code>Debug</code>, so I added it.</p>
<p>Let’s add it to others, <code>XvcFile</code>, etc.</p>
<p>Added it. Recompiling to get more info when we run <code>track</code> with an incorrect path.</p>
<p>You can also make it run after a commit to avoid starting a new server if one is already running.</p>
<p>Added conditionals, and now it runs the server if none is running in the background.</p>
<pre><code class="language-zsh">PORT=7979
if [[ ! -s "$(ps ax | rg -v ps | rg jupyter-lab | rg $PORT)" ]] ; then
  jupyter lab --port=$PORT --notebook-dir=Readme/ &amp;
  open http://localhost:${PORT}/lab/workspaces/auto-H/tree/Readme.ipynb
fi
</code></pre>]]></content:encoded>
    </item>
  </channel>
</rss>
