<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.0">Jekyll</generator><link href="https://rustpython.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://rustpython.github.io/" rel="alternate" type="text/html" /><updated>2020-08-22T00:47:42+00:00</updated><id>https://rustpython.github.io/feed.xml</id><title type="html">RustPython</title><subtitle>An open source Python-3 (CPython &gt;= 3.5.0) Interpreter written in Rust 🐍 😱 🤘</subtitle><entry><title type="html">How to contribute to RustPython by CPython unittest</title><link href="https://rustpython.github.io/guideline/2020/04/04/how-to-contribute-by-cpython-unittest.html" rel="alternate" type="text/html" title="How to contribute to RustPython by CPython unittest" /><published>2020-04-04T16:45:00+00:00</published><updated>2020-04-04T16:45:00+00:00</updated><id>https://rustpython.github.io/guideline/2020/04/04/how-to-contribute-by-cpython-unittest</id><content type="html" xml:base="https://rustpython.github.io/guideline/2020/04/04/how-to-contribute-by-cpython-unittest.html">&lt;p&gt;At the very end of 2019, we finally reached one of the short-term goals: CPython unittest support. Due to this enhancement, finding CPython compatibility is easier than before.
Probably this will be the major source of contribution spots for the new contributors this year. Here is a simple guideline.&lt;/p&gt;

&lt;h2 id=&quot;fix-known-compatibility-bugs&quot;&gt;Fix known compatibility bugs&lt;/h2&gt;
&lt;p&gt;Let’s find an incompatibility issue and fix it.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;See &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Lib/test&lt;/code&gt; directory of the project. There are many &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test_&lt;/code&gt; prefixed files like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test_unicode.py&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Try to open one of them. It might look just fine at a glance - but search for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TODO: RUSTPYTHON&lt;/code&gt; in the files. There are tons of skipped, marked as an expected failure or commented out tests.&lt;/li&gt;
  &lt;li&gt;Alternatively, try looking at the &lt;a href=&quot;/pages/regression-tests-results.html&quot;&gt;regression tests results&lt;/a&gt; to find skipped or expected failure tests; some of them have
notes for a way to resolve the issue.&lt;/li&gt;
  &lt;li&gt;Choose one or two interesting bugs. Remove the test blocker - skip, expectedFailure or comments.&lt;/li&gt;
  &lt;li&gt;Try to fix them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is a quick tip to run single unittest file.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ RUSTPYTHONPATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;Lib cargo run &lt;span class=&quot;nt&quot;&gt;--release&lt;/span&gt; Lib/test/test_unicode.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;add-a-new-unittest-file&quot;&gt;Add a new unittest file&lt;/h2&gt;
&lt;p&gt;Because CPython unittest is not perfectly working in RustPython, we are doing this one by one with editings.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Download CPython source code.&lt;/li&gt;
  &lt;li&gt;Check out a specific version of CPython. For now, 3.8.2 is recommended. (We are testing against CPython 3.8 and 3.8.2 is the most recent version for now)&lt;/li&gt;
  &lt;li&gt;Copy a file from CPython &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Lib/test&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Commit the file without editing. Specify copied CPython version to commit message.&lt;/li&gt;
  &lt;li&gt;Try to edit it until it runs without a crash or failure.&lt;/li&gt;
  &lt;li&gt;Commit the changes to make it run. This is the core contribution.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because RustPython is not perfect, “try to edit it until it runs” doesn’t mean to make 100% successful running. The common editing methods here:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;At least it must be able to start to run the test. Fix the test code or bug until it runs at least a single unit of the test. Typically, unimplemented stdlib or missing files of unittest can make issues. Sometimes RustPython bugs make issues too.&lt;/li&gt;
  &lt;li&gt;If any test is not loadable by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SyntaxError&lt;/code&gt;, that part is required to be commented out.&lt;/li&gt;
  &lt;li&gt;If any test leads to a crash of RustPython, this code is not possible to run. Mark the test to skip.&lt;/li&gt;
  &lt;li&gt;If any test is run but fails, this is an incompatibility issue. Mark the test as an expected failure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We prefer the reversed order of upper methods. The later the more strict so easy to detect any progress or regression.
When we temporarily disable parts of unittest due to RustPython caveats, we mark them to find it out easily later. Please check the examples below or search for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TODO: RUSTPYTHON&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Lib/test&lt;/code&gt; directory to check actual usage.&lt;/p&gt;

&lt;p&gt;Comment out:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# TODO: RUSTPYTHON
#
# def ...  # commented out tests
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;skip:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unittest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;skip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;TODO: RUSTPYTHON&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;...  # &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;skipped&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;expectedFailure:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# TODO: RUSTPYTHON
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unittest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expectedFailure&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;...  # &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;failed&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;development-guide&quot;&gt;Development guide&lt;/h2&gt;
&lt;p&gt;For the general source of the development, please visit the &lt;a href=&quot;https://github.com/RustPython/RustPython/blob/master/DEVELOPMENT.md&quot;&gt;RustPython development guide&lt;/a&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">At the very end of 2019, we finally reached one of the short-term goals: CPython unittest support. Due to this enhancement, finding CPython compatibility is easier than before. Probably this will be the major source of contribution spots for the new contributors this year. Here is a simple guideline.</summary></entry><entry><title type="html">Introduction to the RustPython parser</title><link href="https://rustpython.github.io/2020/04/02/thing-explainer-parser.html" rel="alternate" type="text/html" title="Introduction to the RustPython parser" /><published>2020-04-02T15:34:01+00:00</published><updated>2020-04-02T15:34:01+00:00</updated><id>https://rustpython.github.io/2020/04/02/thing-explainer-parser</id><content type="html" xml:base="https://rustpython.github.io/2020/04/02/thing-explainer-parser.html">&lt;p&gt;This post goes over the RustPython parser. You can see the source code at &lt;a href=&quot;https://github.com/RustPython/RustPython/tree/master/parser&quot;&gt;RustPython/parser/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When you write code in python and run it, an interpreter, such as the RustPython interpreter, acts as the translator between you and your machine.&lt;/p&gt;

&lt;p&gt;The interpreter has the job of turning your human code into byte code that a python virtual machine can run. Bytecode is an intermediate code between source code and machine code. This makes it portable across multiple hardware and operating systems. Bytecode “works” as long as you implement a virtual machine(vm) that can run it. There is a performance penalty for this flexibility. RustPython has a vm under &lt;a href=&quot;https://github.com/RustPython/RustPython/tree/master/vm&quot;&gt;RustPython/vm/&lt;/a&gt;. Other posts, will go into the details of that vm but now let’s figure out how to turn code into bytecode.&lt;/p&gt;

&lt;h2 id=&quot;how-does-bytecode-look-like&quot;&gt;How does bytecode look like&lt;/h2&gt;

&lt;p&gt;Seeing is believing. To see what bytecode looks like, you can use a Python module called &lt;a href=&quot;https://docs.python.org/3/library/dis.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dis&lt;/code&gt;&lt;/a&gt;. dis stands for disassembler. You can write source code then see how its bytecode looks like. Here is an example:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/media/bytecode.jpg&quot; alt=&quot;bytecode&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;how-rustpython-turns-your-code-to-bytecode&quot;&gt;How RustPython turns your code to bytecode&lt;/h2&gt;

&lt;p&gt;Here are the main steps that RustPython currently does:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;parse the line of source code into tokens&lt;/li&gt;
  &lt;li&gt;determine if the tokens have a valid syntax&lt;/li&gt;
  &lt;li&gt;create an Abstract Syntax Tree (AST)&lt;/li&gt;
  &lt;li&gt;compile the AST into bytecode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This list of steps introduces some new concepts like: tokens and abstract syntax trees. We’ll explain and demistify those.&lt;/p&gt;

&lt;h3 id=&quot;step-1-parsing-source-code-into-tokens&quot;&gt;Step 1: parsing source code into tokens&lt;/h3&gt;

&lt;p&gt;The fastest way to understand what tokens are, is to see them. Conveniently, Python comes with a &lt;a href=&quot;https://docs.python.org/3/library/tokenize.html&quot;&gt;tokenizer&lt;/a&gt;.   Here is what happen if I run the tokenizer on the function that I created earlier.&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ python -m tokenize file.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file.py&lt;/code&gt; has the function that I used in the previous example.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;def add(x,y):
    return x+y
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Tokenize output:&lt;/strong&gt;&lt;br /&gt;
&lt;img src=&quot;/assets/media/tokenizing.jpg&quot; alt=&quot;tokenzizing&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A picture IS worth a thousand word 😛 Those are the tokens. They are the basic “units” in the programming language. They are the keywords and operators that you typed. Even new lines and identations count.&lt;/p&gt;

&lt;p&gt;If you want to sound fancy:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;The tokens are the basic “lexical components”&lt;/li&gt;
  &lt;li&gt;The parsing process is called “Lexical Analysis”&lt;/li&gt;
  &lt;li&gt;The thing that does the process is a “lexer”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the link to the RustPython lexer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RustPython/parser/lexer.rs&lt;/code&gt;&lt;/strong&gt; »
&lt;a href=&quot;https://github.com/RustPython/RustPython/blob/master/parser/src/lexer.rs&quot;&gt;source code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want dive into the details of lexical analysis, check out &lt;a href=&quot;https://learning.oreilly.com/library/view/python-in-a/9781491913833/ch03.html#python_language-id00003&quot;&gt;Python in a nutshell / Lexical structure&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;step-2--determine-if-the-tokens-are-valid-syntax&quot;&gt;Step 2 : determine if the tokens are valid syntax&lt;/h3&gt;

&lt;p&gt;In the previous step, if you add random stuff to your function and tokenize it, it will work and still tokenize.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/media/tokenizing-with-errors.jpg&quot; alt=&quot;tokenzizing&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So don’t hate on the whole interpreter when you get error messages! or at least don’t hate on the tokenizer!&lt;/p&gt;

&lt;p&gt;To determine if the tokens are valid syntax, first you need a definition of what a valid syntax is. Python has a defined “grammar” or set of rules. The official reference is on &lt;a href=&quot;https://docs.python.org/3/reference/grammar.html&quot;&gt;this link&lt;/a&gt;. There, you will find a machine readable file. You may read a book to know the rules of python, but words are too “fluffy”, the machine needs a very strict set of rules encoded in a file. &lt;a href=&quot;https://www.youtube.com/watch?v=KGMFvy2d5OI&quot;&gt;This video&lt;/a&gt; explains the notation and the Python grammar.
As the presenter puts it, this is the spirit of the beast (python) and it is only ~10KB 😭 (compare that to the size of python books you had to read!)&lt;/p&gt;

&lt;p&gt;So, we have the rules or grammar of a programming language in a machine encoded format… now we need to write something that verifies that those rules were followed… This sounds like something that other people could use and like something that should exist as an open source project! 🤔&lt;/p&gt;

&lt;p&gt;Sure enough, there is a whole Rust framework called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LALRPOP&lt;/code&gt;. It takes the tokens generated by the lexer, verifies the syntax and turns the tokens into an AST (Abstract Syntax Tree). More information and a tutorial can be found in the &lt;a href=&quot;https://lalrpop.github.io/lalrpop/README.html&quot;&gt;LALRPOP book&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;RustPython does one nice extra thing on top of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LALRPOP &lt;/code&gt;. It masks the errors and provides you with safer, nicer errors. You can see the code for this in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RustPython/parser/src/error.rs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using RustPython to generate an AST&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can do:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; use rustpython_parser::{parser, ast};  
 let python_source = &quot;print('Hello world')&quot;;  
 let python_ast = parser::parse_expression(python_source).unwrap();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;recap--&quot;&gt;Recap 🥴 🥵&lt;/h2&gt;

&lt;p&gt;As a recap, when you write a line of python code and “run it”, here is what happens:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;your code&lt;/strong&gt; (in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file.py&lt;/code&gt; or interactive shell)&lt;br /&gt;
 ⭣ parse the line of source code into tokens&lt;br /&gt;
 ⭣ determine if the tokens are valid syntax&lt;br /&gt;
 ⭣ create an Abstract Syntax Tree (AST)   &lt;br /&gt;
 ⭣ compile the AST into bytecode &lt;br /&gt;
 &lt;strong&gt;bytecode&lt;/strong&gt; (in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__pycache__/file.pyc&lt;/code&gt; or in memory)&lt;/p&gt;

&lt;p&gt;The compiler is under &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RustPython/compiler&lt;/code&gt;&lt;/strong&gt; we’ll dive into the details in a next post. In the meantime, check out the parser source code in &lt;a href=&quot;https://github.com/RustPython/RustPython/tree/master/parser&quot;&gt;RustPython/parser/&lt;/a&gt;.&lt;/p&gt;</content><author><name></name></author><summary type="html">This post goes over the RustPython parser. You can see the source code at RustPython/parser/.</summary></entry></feed>