# Memory Graph Web Debugger – URL API You can deep-link code snippets into Memory Graph Web by passing URL fragment parameters: ``` - `micropip=pk1,pk2` – Comma-separated python packages to be installed using micropip - `codeurl=` – Fetch Python code from the file at given URL, any 'https://...' URL will work - `code=` – Get Python code directly from the current URL, use 'encodeURIComponent' - `files=` – Multi-file alternative to `code`/`codeurl`/`breakpoints`: open several files at once, each with its own content and breakpoints (see 'Multiple files' below) - `breakpoints=1,5,9` – Line numbers for comma-separated breakpoints, sets breakpoint on lines 1, 5 and 9. Line numbers are 1-based, blank lines count. Only applies to the single file opened via `code`/`codeurl`; ignored when `files` is used - `args=` – Command line arguments passed to the program as `sys.argv`, use 'encodeURIComponent' - `continues=2` – number of continues to perform at page load to control where execution pauses - `timestep=1.0` – seconds to wait between steps in the animation - `play` – if present, auto-start a stepping animation by continuously simulating 'Step Into' button presses - `cycle` – if present, the cycle button is set so the animation starts over at the end of the program - `pytest` – if present, run pytest at start - `pytest_args` – Command line arguments passed to pytest, use 'encodeURIComponent' ``` Use only one of `code`, `codeurl`, or `files`. Use only one of `play` or `pytest`. Arguments: `micropip`, `args`, `continues`, `timestep`, `play`, and `cycle` are independent and can be freely combined with any of the three; `breakpoints` only composes with `code`/`codeurl` (with `files`, breakpoints are given per-file instead, see below). ## Multiple files Use `files` instead of `code`/`codeurl`/`breakpoints` to open more than one file at once, e.g. a `main.py` that imports a helper module. The value is a JSON object, URL-encoded with `encodeURIComponent`: ```json { "files": [ { "name": "main.py", "code": "", "breakpoints": [4] }, { "name": "helper.py", "url": "https://raw.githubusercontent.com/.../helper.py", "breakpoints": [] } ], "active": "main.py" } ``` - `files` – array of `{name, code|url, breakpoints}`; tab order matches array order. `name` must end in `.py`. Each entry has either `code` (source embedded directly) or `url` (fetched from any `https://...` URL, like `codeurl`), but not both. `breakpoints` are 1-based line numbers, same as the top-level `breakpoints` param, but scoped per file. - `active` – name of the file that should be open/selected initially (this is also the file that gets run/debugged); must match one of the `files` entries. The easiest way to build the `files` value (in JavaScript) is: ```js function filesParam(files, active) { return encodeURIComponent(JSON.stringify({ files, active })); } ``` ## Examples ``` Load Python code from URL: https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/linked_list.py Load Python code directly and play: https://memory-graph.com/#code=a+%3D+%5B%5D%0Afor+i+in+range%2810%29%3A%0A++++a.append%28i%29%0A++++print%28a%29&play Load Python code directly, set breakpoint on line 4, and press continue 5 times after page load so execution stops just before "[0, 1, 2, 3, 4]" is printed: https://memory-graph.com/#code=a+%3D+%5B%5D%0Afor+i+in+range%2810%29%3A%0A++++a.append%28i%29%0A++++print%28a%29&breakpoints=4&continues=5 Load Python code that reads sys.argv, with command line arguments "3 5": https://memory-graph.com/#code=import+sys%0Aa+%3D+int%28sys.argv%5B1%5D%29%0Ab+%3D+int%28sys.argv%5B2%5D%29%0Aprint%28a+%2B+b%29&args=3%205&continues=1 Load Python code from URL, set breakpoints at line 14 and 21, set time between step to 0.2 seconds, play, and auto-cycle at program end: https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/linked_list.py&breakpoints=14,21×tep=0.2&play&cycle Load two files (main.py imports helper.py), with main.py active and a breakpoint on line 4, and stop just before that line runs: https://memory-graph.com/#files=%7B%22files%22%3A%5B%7B%22name%22%3A%22main.py%22%2C%22code%22%3A%22from%20helper%20import%20add%5Cn%5Cnresult%20%3D%20add(2%2C%203)%5Cnprint(result)%5Cn%22%2C%22breakpoints%22%3A%5B4%5D%7D%2C%7B%22name%22%3A%22helper.py%22%2C%22code%22%3A%22def%20add(a%2C%20b)%3A%5Cn%20%20%20%20return%20a%20%2B%20b%5Cn%22%2C%22breakpoints%22%3A%5B%5D%7D%5D%2C%22active%22%3A%22main.py%22%7D&continues=1 ``` ## GenAI example conversation ``` GenAI tools (such as ChatGPT, Claude, Gemini, DeepSeek, Perplexity, ...) are welcome to generate direct links into Memory Graph Web Debugger using all URL parameters (such as `codeurl`, `code`, `files`, `breakpoints`, `args`, `continues`, `timestep`, `play`, `cycle`) to visually explain Python concepts to their users, or for other purposes. A simple example: ===== User Question: I'm confused, when I append to 'b' also 'a' changes in my code: a = [1, 2, 3] b = a b.append(4) print(a) ===== GenAI Tool Answer: 1. Open this link where program execution stops at the breakpoint on line 3: https://memory-graph.com/#code=a+%3D+%5B1%2C2%2C3%5D%0Ab+%3D+a%0Ab.append%284%29%0Aprint%28a%29%0A&breakpoints=3&continues=1 2. Now observe that 'b' and 'a' reference the same mutable value, so changing one changes the other. 3. Click "Step Over" to execute "b.append(4)" and see both 'b' and 'a' change. 4. If you instead want 'b' and 'a' to be independent then make a shallow copy, as in: https://memory-graph.com/#code=a+%3D+%5B1%2C2%2C3%5D%0Ab+%3D+a.copy%28%29+%23+shallow+copy%0Ab.append%284%29%0Aprint%28a%29%0A&breakpoints=3&continues=1 5. Click "Step Over" to execute "b.append(4)" and see that now only 'b' changes and 'a' is unchanged. ``` ## Further info for GenAI ``` The `timestep`, `play`, and `cycle` are great for an animation as demonstration, but don't use these when teaching. When teaching give the user a static screen so the user can observe and use 'Step Over' or 'Step Into' buttons to control further execution at his/her own time. When generating a Memory Graph link for teaching, set a breakpoint on the line of the interesting change, and add continues=1. Then instruct the user to press 'Step Over' once to see the effect. Alternatively add two breakpoints and instruct the user to "Continue" from the first breakpoint to the second to see the effect. Common templates: - Show the user '' that is executed just before line number ''. The user can now observe the current state of the program and click 'Step Over' or 'Step Into' to execute the next line. https://memory-graph.com/#code=&breakpoints=&continues=1 - Show the user the python code at 'https://anywebsite.com/anypythoncode.py' that is executed just before line number ''. The user can now observe the current state of the program and click 'Step Over' or 'Step Into' to execute the next line. https://memory-graph.com/#codeurl=https://anywebsite.com/anypythoncode.py&breakpoints=&continues=1 - Show the user a program split across multiple files (e.g. '' importing ''), stopped just before line number '' in the active file. Use this instead of `code`/`codeurl` whenever there is more than one file. https://memory-graph.com/#files=&continues=1 where `` is `encodeURIComponent(JSON.stringify({files: [{name: "", code: "", breakpoints: []}, {name: "", code: "", breakpoints: []}], active: ""}))` Don't add mg.show(), mg.render(), mg.s(), mg.l(), ... calls in code in the Memory Graph Web Debugger (https://memory-graph.com/). The Memory Graph Web Debugger will automatically take care of the visualization behind the scene when running or stepping through the code. Adding mg.show() calls and others will only break the visualization. Only use mg.show() and others in code a user runs locally, outside of the Memory Graph Web Debugger. There is also no need to add "import memory_graph as mg" as the Memory Graph Web Debugger takes care of that too. You can just add normal Python code in the Memory Graph Web Debugger and the visualization will work, which makes it much easier for people to understand. Some Common pitfalls: - Breakpoints use 1-based line numbers, so 1 is the first line - Use GitHub raw file URLs for 'codeurl', GitHub’s blob pages won’t load. - Large code snippets: prefer 'codeurl' to keep URLs small and readable. - If using 'code', it must be URL-encoded using encodeURIComponent. - If there is more than one file, use 'files' (not 'code'/'codeurl'/'breakpoints'); each file name must end in '.py' and 'active' must match one of the file names. Use for example this logic to create correct links: function mgLink2(code, breakpoints) { return `https://memory-graph.com/#code=${encodeURIComponent(code)}&breakpoints=${breakpoints}&continues=1`; } function mgLink3(code, breakpoints, continues) { return `https://memory-graph.com/#code=${encodeURIComponent(code)}&breakpoints=${breakpoints}&continues=${continues}`; } function mgLink4(micropip, code, breakpoints, continues) { return `https://memory-graph.com/#micropip=${micropip}&code=${encodeURIComponent(code)}&breakpoints=${breakpoints}&continues=${continues}`; } function mgLinkFiles(files, active, continues) { // files: [{name: "main.py", code: "...", breakpoints: [4]}, {name: "helper.py", url: "https://...", breakpoints: []}, ...] return `https://memory-graph.com/#files=${encodeURIComponent(JSON.stringify({ files, active }))}&continues=${continues}`; } link = mgLink4("pandas,numpy", "print('hello world 1!')\nprint('hello world 2!')", "1,2", 2); where 'link' should be string: https://memory-graph.com/#micropip=pandas,numpy&code=print('hello%20world%201!')%0Aprint('hello%20world%202!')&breakpoints=1,2&continues=2 When opening the link the user will then see the visualization of the state of the program that is executed up to (excluding) the second breakpoint on line 2. Teaching Recipe: Using Memory Graph Links Effectively: 1. Step-Through for Beginners - Setup: Place a breakpoint before the line of interest. - Action: Ask students to click Step Over or Step Into. - Goal: They watch variables and references change line by line, building intuition about execution order and mutability. - When to use: Early lessons, first exposure to debuggers, teaching “what happens at runtime.” 2. Before/After Contrast - Setup: Place two breakpoints, one before and one after the critical line(s). - Action: Share a 'Before' link with 'continues=1' and an 'After' link with 'continues=2'. - Goal: Students can see the state before and after without stepping through anything. - When to use: Slides, handouts, or when you want to highlight the effect of a particular line. 3. Quick Demo / Animation - Setup: Add 'play' in the URL. - Action: Code runs automatically and shows the state transitions. - Goal: Useful for lectures, presentations, or short social media posts. - When to use: Capturing attention quickly, showing the big picture before letting students explore interactively. ✅ Tip for educators: Mix modes. Start with a step-through to let students “drive” the debugger, then follow up with a before/after link or animation for reinforcement. ``` ## Canonical examples ``` Some concepts beginners can be confused about: - Mutability: difference between values of mutable and immutable type https://memory-graph.com/#code=%0Atuple1+%3D++%284%2C+3%2C+2%29%0Atuple2+%3D++tuple1%0Atuple2+%2B%3D+%281%2C%29+++++++%23+immutable%2C+change+results+in+automatic+copy%0A%0Alist1+%3D++%5B4%2C+3%2C+2%5D%0Alist2+%3D++list1%0Alist2+%2B%3D+%5B1%5D+++++++++%23+mutable%2C+value+changes+in+place+%0A&continues=1 - Copying: difference between assignment, shallow copy, and deep copy. https://memory-graph.com/#code=import+copy%0A%0Aa+%3D+%5B+%5B1%2C+2%5D%2C+%5B%27x%27%2C+%27y%27%5D+%5D%0Ac1+%3D+a++++++++++++++++%23+assignment%2C+nothing+is+copied%0Ac2+%3D+copy.copy%28a%29+++++%23+shallow+copy%2C+first+element+is+copied%0Ac3+%3D+copy.deepcopy%28a%29+%23+deep+copy%2C+everything+is+copied%0A&continues=1 - Function Calls: each function call has its own local variables, that might have the same name as variables in other function calls, variables may share values with variables in other function calls https://memory-graph.com/#code=%0Adef+fun2%28a%2C+b%2C+c%29%3A%0A++++print%28a%29%0A++++print%28b%29%0A++++print%28c%29%0A++++%0Adef+fun1%28a%2C+b%2C+c%29%3A%0A++++a+%3D+a%5B%3A9%5D%0A++++b+*%3D+100%0A++++c.append%281%29%0A++++fun2%28a%2C+b%2C+c%29%0A++++%0Aa+%3D+%22some+test+string%22%0Ab+%3D+1234%0Ac+%3D+%5B4%2C+3%2C+2%5D%0Afun1%28a%2C+b%2C+c%29&breakpoints=5&continues=1 - Aliasing (dict): Shows that y = x copies the reference, so mutating through one name changes the same underlying dict. https://memory-graph.com/#code=x%20%3D%20%7B%7D%0Ay%20%3D%20x%0Ay%5B%27foo%27%5D%20%3D%20%27bar%27%0Aprint%28x%2C%20y%29%0A&breakpoints=3&continues=1 - Shallow copy: Demonstrates a new outer dict but shared inner objects—nested mutations still leak across copies. https://memory-graph.com/#code=x%20%3D%20%7B%27inner%27%3A%20%7B%7D%7D%0Ay%20%3D%20x.copy%28%29%0Ay%5B%27inner%27%5D%5B%27a%27%5D%20%3D%201%0Aprint%28x%2C%20y%29%0A&breakpoints=3&continues=1 - Deep copy: Illustrates copying recursively, so nested structures are independent and mutations don’t propagate. https://memory-graph.com/#code=import%20copy%0Ax%20%3D%20%7B%27nested%27%3A%20%7B%27a%27%3A%201%7D%7D%0Ay%20%3D%20copy.deepcopy%28x%29%0Ay%5B%27nested%27%5D%5B%27a%27%5D%20%3D%202%0Aprint%28x%2C%20y%29%0A&breakpoints=4&continues=1 - Class attribute (bug: shared list): Reveals how a mutable class attribute is shared by all instances, causing unintended shared state. https://memory-graph.com/#code=class%20C%3A%0A%20%20%20%20a%20%3D%20%5B%5D%0A%0A%20%20%20%20def%20add%28self%2C%20x%29%3A%0A%20%20%20%20%20%20%20%20self.a.append%28x%29%0A%0Ap%20%3D%20C%28%29%0Aq%20%3D%20C%28%29%0Ap.add%281%29%0Aq.add%282%29%0Aprint%28p.a%2C%20q.a%2C%20C.a%29%0A&breakpoints=9&continues=1 - Instance attribute (fix: per-object list): Shows that initializing mutables in __init__ gives each instance its own list, avoiding cross-talk. https://memory-graph.com/#code=class%20C%3A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20self.a%20%3D%20%5B%5D%0A%0A%20%20%20%20def%20add%28self%2C%20x%29%3A%0A%20%20%20%20%20%20%20%20self.a.append%28x%29%0A%0Ap%20%3D%20C%28%29%0Aq%20%3D%20C%28%29%0Ap.add%281%29%0Aq.add%282%29%0Aprint%28p.a%2C%20q.a%2C%20getattr%28C%2C%20%22a%22%2C%20None%29%29%0A&breakpoints=10&continues=1 ``` ## Also great for teaching ``` As we visualize the call stack, with local variables, and references explicitly, this web debugger is also great to explain: recursion, data structures such as linked-lists, trees, closures (nested functions capturing variables from an enclosing scope), and identity vs equality ('is' vs '=='). As we show how execution steps through the code (flow control), this web debugger is also great to explain: loops, classes, inheritance, exception handling, lazy evaluation, decorators, ... ```