Arthur Pastel PRO
Co-Founder @ CodSpeed.io
Open-source:
Building
@art049
Arthur Pastel
Software Engineer
Python:
The compiler
Memory safety
Package manager (cargo
)
def increment_all(nums):
for i in range(len(nums)):
nums[i] += 1
fn increment_all(nums: &mut Vec<i32>) {
for num in nums.iter_mut() {
*num += 1;
}
}
A DOT graph format parser
graph MyCoolGraph {
a -- b -- c;
b -- d;
}
graph CoolGraph {
a -- b -- c ;
b -- d ;
}
Graph
Identifier
Edge
SemiColon
LeftBracket
RightBracket
from dataclasses import dataclass
from enum import Enum, auto
class BasicToken(Enum):
Graph = auto()
LeftBracket = auto()
RightBracket = auto()
Semicolon = auto()
Edge = auto()
@dataclass
class IdentifierToken:
name: str
Token = BasicToken | IdentifierToken
enum Token {
Graph,
LeftBracket,
RightBracket,
Semicolon,
Edge,
Identifier(String),
}
// (i32, f64, u64)
let t = (500, 6.4, 1u64);
// [i32; 5] fixed size of 5 elements
let a = [1, 2, 3, 4, 5];
// Vec<i32> vector of i32s (dynamic)
let a = vec![1, 2, 3, 4, 5];
//This is a builtin enum
enum Option<T> {
Some(T),
None,
}
// Option<i32> type is inferred
let a = Some(3);
// The option type is specified
let b: Option<u32> = None;
//This is a builtin enum too
enum Result<T, E> {
Ok(T),
Err(E),
}
fn div(a: i32, b: i32) -> Result<i32, &str>{
if b != 0 {
Ok(a / b)
} else {
Err("Cannot divide by zero")
}
}
struct User {
active: bool,
name: Option<String>,
sign_in_count: u64,
}
// Option<User>
let u = Option::Some(
User {
active: true,
name: Some("john".to_string()),
sign_in_count: 1,
}
);
enum Token {
Graph,
LeftBracket,
RightBracket,
Semicolon,
Edge,
Identifier(String),
}
def word_to_token(word: str) -> Token:
if word == "graph":
return BasicToken.DiGraph
elif word == "{":
return BasicToken.LeftBracket
elif word == "}":
return BasicToken.RightBracket
elif word == ";":
return BasicToken.Semicolon
elif word == "--":
return BasicToken.Edge
else:
return IdentifierToken(word)
def word_to_token(word: str) -> Token:
match word:
case "graph":
return BasicToken.DiGraph
case "{":
return BasicToken.LeftBracket
case "}":
return BasicToken.RightBracket
case ";":
return BasicToken.Semicolon
case "--":
return BasicToken.Edge
case _:
return IdentifierToken(word)
Introduced with Python 3.10 (PEP 634)
⚠️ not backward compatible
fn word_to_token(word: &str) -> Token {
match word {
"graph" => Token::Graph,
"{" => Token::LeftBracket,
"}" => Token::RightBracket,
";" => Token::Semicolon,
"->" => Token::DirectedEdgeOp,
"--" => Token::UndirectedEdgeOp,
_ => Token::Identifier(word.to_string()),
}
}
Graph
Identifier
Edge
SemiColon
LeftBracket
RightBracket
Identifier
Edge
SemiColon
Graph
LeftBracket
RightBracket
Identifier
Identifier
class ParserState(Enum):
Start = auto()
ExpectGraphName = auto()
ExpectLBracket = auto()
ExpectNodeName = auto()
ExpectEdgeOrSemicolon = auto()
ExpectNodeNameOrRBracket = auto()
End = auto()
class Parser:
def __init__(self):
self.state = ParserState.Start
# ...
def parse_token(self, token: Token):
"""Transition to the next state"""
match (self.state, token):
# first Graph token
case (ParserState.Start, BasicToken.GRAPH):
self.state = ParserState.ExpectGraphName
# Identifier defining the name of the graph
case (ParserState.ExpectGraphName, IdentifierToken(name)):
self.graph_name = name
self.state = ParserState.ExpectLBracket
# ...
# Error cases (unexpected tokens)
case _:
raise Exception(f"Unexpected {token} in state {self.state}")
enum ParserState {
Start,
ExpectGraphName,
ExpectLBracket,
ExpectNodeName,
ExpectEdgeOrSemicolon,
ExpectNodeNameOrRBracket,
End,
}
pub struct Parser {
state: ParserState,
// ...
}
impl Parser {
pub fn new() -> Self {
Self {
state: ParserState::Start,
// ...
}
}
fn parse_token(&mut self, token: Token) {
match (self.state, token) {
// Parse the first Graph token
(ParserState::Start, Token::Graph) => {
self.state = ParserState::ExpectGraphName;
}
// Parse the graph name
(ParserState::ExpectGraphName, Token::Identifier(name)) => {
self.graph_name = name;
self.state = ParserState::ExpectLBracket;
}
// ...
// Error
(state, token) => {
panic!("Unexpected token {:?} in state {:?}", token, state);
}
}
}
}
(almost)
Py03
maturin
: standard way to ship rust modules
rustimport
: handy for quick PoC
// rustimport:pyo3
use pyo3::prelude::*;
#[pyfunction]
fn square(x: i32) -> i32 {
x * x
}
>>> import rustimport.import_hook
>>> import somecode # Compile the module
>>> somecode.square(9)
81
somecode.rs
maturin
#[pyclass]
pub struct Graph {
pub graph_name: String,
pub nodes: Vec<String>,
pub adjacency: HashMap<usize, Vec<usize>>,
}
#[pyfunction]
pub fn parse_file(filepath: String) -> PyResult<Graph> {
let text = std::fs::read_to_string(filepath)?;
let words_it = split_words(&text).into_iter();
let mut token_it = words_it.map(word_to_token);
let mut parser = Parser::new();
let graph = parser.parse(&mut token_it);
return Ok(graph)
}
class Graph:
graph_name: str
nodes: list[str]
adjacency: dict[int, list[int]]
def parse_file(filepath: str) -> Graph: ...
parser.pyi
⚠️ not automated (yet)
import rustimport.import_hook
from pydot_rs import parse_file
def test_parsing_undir():
graph = parse_file("samples/undir.dot")
assert len(graph.nodes) == 4
assert set(graph.nodes) == {"a", "b", "c", "d"}
import rustimport.import_hook
from pydot_rs import parse_file
def test_parsing_undir(benchmark):
graph = benchmark(parse_file, "samples/undir.dot")
assert len(graph.nodes) == 4
assert set(graph.nodes) == {"a", "b", "c", "d"}
with pytest-codspeed
pydantic
: data validation library (with pydantic-core
)robyn
: a web framework with a Rust runtimetsdownsample
: time series downsampling algorithms
pydantic-core
ome-types
PR migrating to Pydantic V2
@art049
linkedin.com/in/arthurpastel
Arthur
Adrien
Come and chat with us!
By Arthur Pastel
EuroPython 2023 Talk