Giter VIP home page Giter VIP logo

rustpython's Introduction

A Python-3 (CPython >= 3.12.0) Interpreter written in Rust ๐Ÿ ๐Ÿ˜ฑ ๐Ÿค˜.

Build Status codecov License: MIT Contributors Discord Shield docs.rs Crates.io dependency status WAPM package Open in Gitpod

Usage

Check out our online demo running on WebAssembly.

RustPython requires Rust latest stable version (e.g 1.67.1 at February 7th 2023). If you don't currently have Rust installed on your system you can do so by following the instructions at rustup.rs.

To check the version of Rust you're currently running, use rustc --version. If you wish to update, rustup update stable will update your Rust installation to the most recent stable release.

To build RustPython locally, first, clone the source code:

git clone https://github.com/RustPython/RustPython

Then you can change into the RustPython directory and run the demo (Note: --release is needed to prevent stack overflow on Windows):

$ cd RustPython
$ cargo run --release demo_closures.py
Hello, RustPython!

Or use the interactive shell:

$ cargo run --release
Welcome to rustpython
>>>>> 2+2
4

NOTE: For windows users, please set RUSTPYTHONPATH environment variable as Lib path in project directory. (e.g. When RustPython directory is C:\RustPython, set RUSTPYTHONPATH as C:\RustPython\Lib)

You can also install and run RustPython with the following:

$ cargo install --git https://github.com/RustPython/RustPython
$ rustpython
Welcome to the magnificent Rust Python interpreter
>>>>>

If you'd like to make https requests, you can enable the ssl feature, which also lets you install the pip package manager. Note that on Windows, you may need to install OpenSSL, or you can enable the ssl-vendor feature instead, which compiles OpenSSL for you but requires a C compiler, perl, and make.

Once you've installed rustpython with SSL support, you can install pip by running:

cargo install --git https://github.com/RustPython/RustPython --features ssl
rustpython --install-pip

You can also install RustPython through the conda package manager, though this isn't officially supported and may be out of date:

conda install rustpython -c conda-forge
rustpython

WASI

You can compile RustPython to a standalone WebAssembly WASI module so it can run anywhere.

Build

cargo build --target wasm32-wasi --no-default-features --features freeze-stdlib,stdlib --release

Run by wasmer

wasmer run --dir `pwd` -- target/wasm32-wasi/release/rustpython.wasm `pwd`/extra_tests/snippets/stdlib_random.py

Run by wapm

$ wapm install rustpython
$ wapm run rustpython
>>>>> 2+2
4

Building the WASI file

You can build the WebAssembly WASI file with:

cargo build --release --target wasm32-wasi --features="freeze-stdlib"

Note: we use the freeze-stdlib to include the standard library inside the binary. You also have to run once rustup target add wasm32-wasi.

JIT (Just in time) compiler

RustPython has a very experimental JIT compiler that compile python functions into native code.

Building

By default the JIT compiler isn't enabled, it's enabled with the jit cargo feature.

cargo run --features jit

This requires autoconf, automake, libtool, and clang to be installed.

Using

To compile a function, call __jit__() on it.

def foo():
    a = 5
    return 10 + a

foo.__jit__()  # this will compile foo to native code and subsequent calls will execute that native code
assert foo() == 15

Embedding RustPython into your Rust Applications

Interested in exposing Python scripting in an application written in Rust, perhaps to allow quickly tweaking logic where Rust's compile times would be inhibitive? Then examples/hello_embed.rs and examples/mini_repl.rs may be of some assistance.

Disclaimer

RustPython is in development, and while the interpreter certainly can be used in interesting use cases like running Python in WASM and embedding into a Rust project, do note that RustPython is not totally production-ready.

Contribution is more than welcome! See our contribution section for more information on this.

Conference videos

Checkout those talks on conferences:

Use cases

Although RustPython is a fairly young project, a few people have used it to make cool projects:

  • GreptimeDB: an open-source, cloud-native, distributed time-series database. Using RustPython for embedded scripting.
  • pyckitup: a game engine written in rust.
  • Robot Rumble: an arena-based AI competition platform
  • Ruff: an extremely fast Python linter, written in Rust

Goals

  • Full Python-3 environment entirely in Rust (not CPython bindings)
  • A clean implementation without compatibility hacks

Documentation

Currently along with other areas of the project, documentation is still in an early phase.

You can read the online documentation for the latest release, or the user guide.

You can also generate documentation locally by running:

cargo doc # Including documentation for all dependencies
cargo doc --no-deps --all # Excluding all dependencies

Documentation HTML files can then be found in the target/doc directory or you can append --open to the previous commands to have the documentation open automatically on your default browser.

For a high level overview of the components, see the architecture document.

Contributing

Contributions are more than welcome, and in many cases we are happy to guide contributors through PRs or on Discord. Please refer to the development guide as well for tips on developments.

With that in mind, please note this project is maintained by volunteers, some of the best ways to get started are below:

Most tasks are listed in the issue tracker. Check issues labeled with good first issue if you wish to start coding.

To enhance CPython compatibility, try to increase unittest coverage by checking this article: How to contribute to RustPython by CPython unittest

Another approach is to checkout the source code: builtin functions and object methods are often the simplest and easiest way to contribute.

You can also simply run ./whats_left.py to assist in finding any unimplemented method.

Compiling to WebAssembly

See this doc

Community

Discord Banner

Chat with us on Discord.

Code of conduct

Our code of conduct can be found here.

Credit

The initial work was based on windelbouwman/rspython and shinglyu/RustPython

Links

These are some useful links to related projects:

License

This project is licensed under the MIT license. Please see the LICENSE file for more details.

The project logo is licensed under the CC-BY-4.0 license. Please see the LICENSE-logo file for more details.

rustpython's People

Contributors

adrian17 avatar carbotaniuman avatar chjr avatar coolreader18 avatar cthulahoops avatar deantvv avatar dimitrisjim avatar fanninpm avatar harupy avatar hyeockjinkim avatar jgirardet avatar jopemachine avatar lynskylate avatar masorubka1 avatar moreal avatar nakanomiku39 avatar oddbloke avatar oddcoincidence avatar palaviv avatar qingshi163 avatar rmliddle avatar shinglyu avatar skinnybat avatar snowapril avatar sobolevn avatar theanykey avatar windelbouwman avatar youknowone avatar yt2b avatar zapanton avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rustpython's Issues

Implement the top level binary

The top level project should be able to just cargo run file.py

We need to:

  1. Make the parser and VM crates
  2. Make parser emits VM-compatiable bytecode
  3. Connect them in the top level project src

Can't call __new__ directly to create instances.

This should work, but doesn't:

int.__new__(int, 5)

I think type.__new__ gets called instead of int.__new__, given this:

>>>>> object.__new__(object) 
<class 'type'>

I was pretty sure there was a problem with getattribute, but I've been waiting for a good example to fix.

REPL crashes on Windows newlines

When I execute cargo run and type 1<ENTER> on the REPL, the parser crashes:

Welcome to the magnificent Rust Python 0.0.1 interpreter
>>>>> 1
thread 'main' panicked at 'Not impl Some('\r')', parser\src\lexer.rs:582:21

This is somehow related to Windows newlines (\r\n), so I'll try to come up with a PR which fixes this issue on Windows.

Single element tuples not supported

$ python -c 'print((1,))'
(1,)
$ cargo run -- -c 'print((1,))'
    Finished dev [unoptimized + debuginfo] target(s) in 0.07s
     Running `/home/daniel/personal_dev/RustPython/target/debug/rustpython -c 'print((1,))'`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "UnrecognizedToken { token: Some((0, Rpar, 0)), expected: [\"\\\"(\\\"\", \"\\\"+\\\"\", \"\\\"-\\\"\", \"\\\"False\\\"\", \"\\\"None\\\"\", \"\\\"True\\\"\", \"\\\"[\\\"\", \"\\\"lambda\\\"\", \"name\", \"number\", \"string\"] }"', libcore/result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Create a webassembly demo

Somehow it should be easy to port rustpython to the web using the wasm backend of rust. We require a sort of manual / script on how to do this and a nice website which is automatically updated with the latest version of rustpython.

Lazily load rust stdlib modules

Currently we will initialise all Rust stdlib modules on start-up; it would be preferable to only load modules once they are actually imported, to reduce the amount of work we do at startup (and memory usage throughout the process).

Sub-classes of `str` appear to just operate as aliases of `str`

>>>>> class String(str):
.....     def foo(self):
.....         return "foo"
..... 
>>>>> String()
'' 
>>>>> String().foo()
Traceback (most recent call last):
  File <unknown>, line 0, in <module>
AttributeError: RefCell { value: [PyObj class "str"] } object has no attribute foo
>>>>> type(String())
<class 'str'> 

Implement the builtin `format` function.

This is a large task. Head over to vm/src/builtins.rs and implement the builtin_format function. Try to start with a simple example and extend from there.

Also add a snippet in the tests/snippets directory to test your implementation.

Implement the builtin 'ord' function.

This is a good instant reward issue ๐Ÿ‘

Go to the file vm/src/builtins.rs and implement the builtin_ord function.

See the documentation for its description:

file:///usr/share/doc/python/html/library/functions.html#ord

Panic when running on files that don't end with a newline

Reproducer:

$ echo 'print(4)' > test.py
$ cargo run test.py
    Finished dev [unoptimized + debuginfo] target(s) in 0.09s
     Running `target/debug/rustpython test.py`
4 
$ echo -n 'print(4)' > test.py
$ cargo run test.py
    Finished dev [unoptimized + debuginfo] target(s) in 0.10s
     Running `target/debug/rustpython test.py`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "UnrecognizedToken { token: None, expected: [\"\\\"!=\\\"\", \"\\\"%\\\"\", \"\\\"%=\\\"\", \"\\\"&\\\"\", \"\\\"&=\\\"\", \"\\\"(\\\"\", \"\\\")\\\"\", \"\\\"*\\\"\", \"\\\"**\\\"\", \"\\\"**=\\\"\", \"\\\"*=\\\"\", \"\\\"+\\\"\", \"\\\"+=\\\"\", \"\\\",\\\"\", \"\\\"-\\\"\", \"\\\"-=\\\"\", \"\\\".\\\"\", \"\\\"/\\\"\", \"\\\"//\\\"\", \"\\\"//=\\\"\", \"\\\"/=\\\"\", \"\\\":\\\"\", \"\\\"<\\\"\", \"\\\"<<=\\\"\", \"\\\"<=\\\"\", \"\\\"=\\\"\", \"\\\"==\\\"\", \"\\\">\\\"\", \"\\\">=\\\"\", \"\\\">>=\\\"\", \"\\\"@\\\"\", \"\\\"@=\\\"\", \"\\\"[\\\"\", \"\\\"\\\\\\\\n\\\"\", \"\\\"]\\\"\", \"\\\"^\\\"\", \"\\\"^=\\\"\", \"\\\"and\\\"\", \"\\\"as\\\"\", \"\\\"in\\\"\", \"\\\"is\\\"\", \"\\\"not\\\"\", \"\\\"or\\\"\", \"\\\"|\\\"\", \"\\\"|=\\\"\"] }"', libcore/result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Enable `is` comparisons for True and False

CPython:

>>> True is True
True
>>> False is False
True
>>> t = not False
>>> t is True
True
>>> t is False
False

RustPython:

>>>>> True is True
False 
>>>>> False is False
False 
>>>>> t = not False
>>>>> t is True
False 
>>>>> t is False
False 

Create converters from cpython bytecode

We need converters from cpython's bytecode into rustpython bytecode. The sourcefile can be found in py_code_object/src/convert.rs. The idea is to take cpython bytecode (which differs per cpython version) and convert it into rustpython bytecode.

Cargo run failure

cargo run is failing on my windows 7 machine.
I am using rust 1.26. I am getting this error

error[E0658]: use of unstable library feature 'iterator_step_by': unstable replacement of Range::step_by (see issue #27741)
  --> vm\src\obj\objsequence.rs:56:34
   |
56 |         self[start..stop].iter().step_by(step).cloned().collect()
   |                                  ^^^^^^^

error[E0658]: use of unstable library feature 'iterator_step_by': unstable replacement of Range::step_by (see issue #27741)
   --> vm\src\obj\objstr.rs:220:35
    |
220 |         self[start..stop].chars().step_by(step).collect()
    |                                   ^^^^^^^

error: aborting due to 2 previous errors. 

The active toolchain is stable-x86_64-pc-windows-msvc (default).

Arithmetic operations lose type data

This code:

x = 1
print(type(x))
print(type(x-1))

produces this output:

<class 'int'> 
<class 'type'>

This is caused by VirtualMachine._sub (and its compatriots) using self.get_type() as the type of the new object, rather than using the type information from the arguments.

Expand the standard library

The standard library is now located in the Lib folder. Many modules are still missing (if not all).

If you would like to contribute, this is an easy start. Have a look at the cpython or pypy standard library. Take care about eventual copy rights.

Tuple comparison not supported

$ python -c 'if (1,2) == (1,2): print("matching")'
matching
$ cargo run -- -c 'if (1,2) == (1,2): print("matching")'
    Finished dev [unoptimized + debuginfo] target(s) in 0.07s
     Running `/home/daniel/personal_dev/RustPython/target/debug/rustpython -c 'if (1,2) == (1,2): print("matching")'`
thread 'main' panicked at 'TypeError in COMPARE_OP: can't compare [PyObj tuple] with [PyObj tuple]', vm/src/pyobject.rs:595:18
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Implement Locals Builtin

Running the locals builtin function causes a type exception

>>>>> locals()
thread 'main' panicked at 'Object doesn't have a type!', vm/src/pyobject.rs:379:21

Support relative imports

#54 implements most (perhaps all?) of the import syntax, but it doesn't include support for relative imports (e.g. from .foo import bar, from ..spam import eggs).

Imports are searched for relative to cwd, not relative to the importing file

To reproduce:

mkdir reproducer
echo "import spam" > reproducer/reproducer.py
touch spam.py
python reproducer/reproducer.py
Traceback (most recent call last):
  File "reproducer/reproducer.py", line 1, in <module>
    import spam
ModuleNotFoundError: No module named 'spam'
cargo run reproducer/reproducer.py

We, incorrectly, don't error in this situation.

Explicitly mention Version of CPython Syntax supported

Right now, while it is implicitly understood we are targeting Python-3, it's a good idea to be explicit about it. At-least README.md should be updated to mention this.

This should also help us target compliance, Python's Test suits etc.

Implicit string concatenation is not supported

$ python -c 'print("foo" "bar")'
foobar

$ cargo run -- -c 'print("foo" "bar")'                                                                                                                  STASH master  [ 20:08:55 ]
    Finished dev [unoptimized + debuginfo] target(s) in 0.07s
     Running `/home/daniel/personal_dev/RustPython/target/debug/rustpython -c 'print("foo" "bar")'`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "UnrecognizedToken { token: Some((14, String { value: \"bar\" }, 18)), expected: [\"\\\"!=\\\"\", \"\\\"%\\\"\", \"\\\"%=\\\"\", \"\\\"&\\\"\", \"\\\"&=\\\"\", \"\\\"(\\\"\", \"\\\")\\\"\", \"\\\"*\\\"\", \"\\\"**\\\"\", \"\\\"**=\\\"\", \"\\\"*=\\\"\", \"\\\"+\\\"\", \"\\\"+=\\\"\", \"\\\",\\\"\", \"\\\"-\\\"\", \"\\\"-=\\\"\", \"\\\".\\\"\", \"\\\"/\\\"\", \"\\\"//\\\"\", \"\\\"//=\\\"\", \"\\\"/=\\\"\", \"\\\":\\\"\", \"\\\";\\\"\", \"\\\"<\\\"\", \"\\\"<<=\\\"\", \"\\\"<=\\\"\", \"\\\"=\\\"\", \"\\\"==\\\"\", \"\\\">\\\"\", \"\\\">=\\\"\", \"\\\">>=\\\"\", \"\\\"@\\\"\", \"\\\"@=\\\"\", \"\\\"[\\\"\", \"\\\"\\\\\\\\n\\\"\", \"\\\"]\\\"\", \"\\\"^\\\"\", \"\\\"^=\\\"\", \"\\\"and\\\"\", \"\\\"as\\\"\", \"\\\"in\\\"\", \"\\\"is\\\"\", \"\\\"not\\\"\", \"\\\"or\\\"\", \"\\\"|\\\"\", \"\\\"|=\\\"\"] }"', libcore/result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Constructed ints/floats can't access their values

Both of these statements cause panics:

print(int(1))
print(float(1.0))

when they should be supported. The panics look like this:

thread 'main' panicked at 'Inner error getting int', vm/src/objint.rs:19:9

(This also stops int/float subclasses from being usable; there's no way to instantiate them.)

__name__ is not recognized

If I want to write:

if __name__ == "__main__":
    print("Hello, world!")

I can run this with Python3 but not with RustPython. It fails with this error:

emacs-mbp% cargo run --release test.py
    Finished release [optimized] target(s) in 0.11s
     Running `target/release/rustpython test.py`
Traceback (most recent call last):
  File test.py, line 1, in <module>
NameError: Has not attribute '__name__'
thread 'main' panicked at 'Exception: RefCell { value: [PyObj instance] }', src/main.rs:69:13
note: Run with `RUST_BACKTRACE=1` for a backtrace.
emacs-mbp%

How to document this project?

This is gonna be some sort of a poll. So the question is, how to write proper documentation for this project. Both rust and python have documentation options. For rust, there appears to be some rust format tool, which is the default. For python there is readthedocs and sphinx.

I now see the following options:

  • Document the project in readthedocs with sphinx
  • Document the project in rust
  • Do both options and mix

Proposals are welcome, we can vote them with the like options!

Comparison operations aren't considered valid in function arguments

As evidenced by:

$ python -c 'print((1,2) == (1,2))'
True
$ cargo run -- -c 'print((1,2) == (1,2))'
    Finished dev [unoptimized + debuginfo] target(s) in 0.07s
     Running `/home/daniel/personal_dev/RustPython/target/debug/rustpython -c 'print((1,2) == (1,2))'`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "UnrecognizedToken { token: Some((15, EqEqual, 16)), expected: [\"\\\")\\\"\", \"\\\",\\\"\", \"\\\"in\\\"\", \"\\\"|\\\"\"] }"', libcore/result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Triple-quoted strings are not supported

$ cargo run -- -c 'print("""foo""")'
    Finished dev [unoptimized + debuginfo] target(s) in 0.07s
     Running `/home/daniel/personal_dev/RustPython/target/debug/rustpython -c 'print("""foo""")'`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "UnrecognizedToken { token: Some((10, String { value: \"foo\" }, 14)), expected: [\"\\\"!=\\\"\", \"\\\"%\\\"\", \"\\\"%=\\\"\", \"\\\"&\\\"\", \"\\\"&=\\\"\", \"\\\"(\\\"\", \"\\\")\\\"\", \"\\\"*\\\"\", \"\\\"**\\\"\", \"\\\"**=\\\"\", \"\\\"*=\\\"\", \"\\\"+\\\"\", \"\\\"+=\\\"\", \"\\\",\\\"\", \"\\\"-\\\"\", \"\\\"-=\\\"\", \"\\\".\\\"\", \"\\\"/\\\"\", \"\\\"//\\\"\", \"\\\"//=\\\"\", \"\\\"/=\\\"\", \"\\\":\\\"\", \"\\\";\\\"\", \"\\\"<\\\"\", \"\\\"<<=\\\"\", \"\\\"<=\\\"\", \"\\\"=\\\"\", \"\\\"==\\\"\", \"\\\">\\\"\", \"\\\">=\\\"\", \"\\\">>=\\\"\", \"\\\"@\\\"\", \"\\\"@=\\\"\", \"\\\"[\\\"\", \"\\\"\\\\\\\\n\\\"\", \"\\\"]\\\"\", \"\\\"^\\\"\", \"\\\"^=\\\"\", \"\\\"and\\\"\", \"\\\"as\\\"\", \"\\\"in\\\"\", \"\\\"is\\\"\", \"\\\"not\\\"\", \"\\\"or\\\"\", \"\\\"|\\\"\", \"\\\"|=\\\"\"] }"', libcore/result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Note that the unrecognized token is "foo", so the first "" of the opening quotes have been parsed as the empty string (which shouldn't be immediately followed by another string, hence the error).

Should bytecode contain PyObjectRef references to constants?

It could be argued that bytecode objects may refer to python objects which are immutable, such as tuples, None and integers.

This would mean that the bytecode::Constant enum would disappear:

https://github.com/RustPython/RustPython/blob/master/vm/src/bytecode.rs#L113

This would also mean that the bytecode class becomes depending upon the vm. This might be a downside, so we cannot separate the bytecode package into a seperate package, but on the other hand, I like the idea of referring to PyObjectRef objects straight from bytecode.

This is a voting issue, what do you think?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.