Giter VIP home page Giter VIP logo

colcon-poetry-ros's Introduction

colcon-poetry-ros

An extension for colcon-core that adds support for Python packages that use Poetry within ROS. This extension is a replacement for Colcon's built-in setup.cfg based Python support and the Python-related bits in colcon-ros.

We use this extension with Foxy and Humble, but other versions should work as well. Please create an issue if you see problems!

Getting Started

Start by install this extension with Pip:

pip3 install colcon-poetry-ros

Then, add a pyproject.toml in the root of your package's directory. Each package should have its own pyproject.toml file. It should look something like this:

[tool.poetry]
name = "my_package"
version = "0.1.0"
description = "Does something cool"
authors = ["John Smith <[email protected]>"]
license = "BSD-3-Clause"

[tool.poetry.dependencies]
python = "^3.8"

[tool.poetry.scripts]
node_a = "my_package.node_a:main"
node_b = "my_package.node_b:main"

[tool.colcon-poetry-ros.data-files]
"share/ament_index/resource_index/packages" = ["resource/my_package"]
"share/my_package" = ["package.xml"]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

Finally, run your build like normal:

colcon build

Testing

This extension currently supports projects based on PyTest. Run the following command to start tests:

colcon test

Node Entrypoints

If you want to be able to run your nodes using ros2 run, add your node's entrypoint to the tool.poetry.scripts table. See Poetry's documentation for details.

[tool.poetry.scripts]
node_a = "my_package.node_a:main"
node_b = "my_package.node_b:main"

Data Files

Poetry has only limited support for including data files in an installation, and the current implementation is not flexible enough to be used with ROS. Instead, this extension consults a custom section in your pyproject.toml, called tool.colcon-poetry-ros.data-files.

The format is intended to be mostly identical to the data_files field used by setuptools. The main differences are that copying entire directories is supported, and globbing is not yet implemented.

All ROS packages must have, at minimum, these entries in the tool.colcon-poetry-ros.data-files section (with {package_name} replaced with the name of your package):

[tool.colcon-poetry-ros.data-files]
"share/ament_index/resource_index/packages" = ["resource/{package_name}"]
"share/{package_name}" = ["package.xml"]

These entries take care of adding the package index marker and package.xml file to the installation.

Installing Dependencies

Poetry dependencies are not installed as part of the build process, but they can be installed using a separate tool that's included in this package.

python3 -m colcon_poetry_ros.dependencies.install --base-paths <path to your nodes>

This command installs each package's dependencies to Colcon's base install directory. This means that your dependencies live alongside your package's code after it's built, isolated from the rest of your system.

If you customize colcon build with the --install-base or --merge-install flags, make sure to provide those to this tool as well.

Communicating Dependencies to Colcon

Colcon can be given information on dependencies between packages, which affects build order and can be displayed in tools like colcon graph. These dependencies can be explicitly defined in the pyproject.toml under a custom section called tool.colcon-poetry-ros.dependencies.

[tool.colcon-poetry-ros.dependencies]
depend = ["foo_package"]   # This will add to both `build_depend` and `exec_depend` following `package.xml` standards
build_depend = ["bar_package"]
exec_depend = ["baz_package"]
test_depend = ["qux_package"]

colcon-poetry-ros's People

Contributors

dimaqq avatar francocipollone avatar joncppl avatar nznobody avatar velovix 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

Watchers

 avatar  avatar  avatar

colcon-poetry-ros's Issues

Remove support for dev dependencies

Currently dev dependencies are used to specify test dependencies, but we can't install dev dependencies automatically because they are never included in generated wheels. We should probably instead use a special "test" extra for this purpose.

Dependency install is inconsistent, does not resolve all constraints

The strategy of installing the dependencies of each package sequentially can lead to not all packages' dependent versions being satisified.

Take for example the simple case where my workspace contains two projects, that each depend on (just for sake of example) numpy. One package explicitly requests version 1.19 and the other version 1.20.

Running python3 -m colcon_poetry_ros.dependencies.install ... will appear to install both versions. However, after the install only version 1.19 is in site-packages.

In this scenario surely there should be a warning about unresolvable version constraints.

A second example; project1 requests numpy 1.19 and project2 requests numpy <=1.20. There is a version of numpy that satisfies both of these constraints (1.19). However... guess which version ends up in site-packages. It's 1.20

Docs understanding. Runtime dependencies.

he guys, thx a lot for this great tool.

i have created a package with pyproject.toml, i took ur's and changed executable path within the [tool.poetry.scripts] section. I can colcon build this package and colcon_poetry_ros.dependencies.install installs my_package and it's deps within the install/my_package/local/lib/python3.10/dist-packages dir. but when i run executable with ros2 run my_package my_executable i get runtime error ModuleNotFoundError: No module named 'my_package'. it seems the installed dist-packages are not part of the python path. i thought it will be added automatically or did i misunderstand this?

Usage with bloom

Hello. Thanks for putting the effort into this project. I think it will make a fantastic addition to ROS.

I was hoping to use this with bloom to include python deps in a .deb. I was going to include the pyproject.toml and optionally the poetry.lock in the deb (via setup.py data-files) and then run python3 -m colcon_poetry_ros.dependencies.install --install-base /opt/ros/galactic/share/* to install the deps using poetry. Ideally this would install them into a virtual environment or at least not the main site-packages (so different packages with different versions of the same library are supported).

I was going down this route as I have a bunch of packages with large dependencies such as pytorch and opencv which I don't want to package into the .debs

I got some of this working back in the day but had to disable virtual environments. I'm not very familiar with bloom or how ros launch would play with virtual envs but was hoping you might have an idea.

For example, the dpkg-query for a package bloomed with:

    data_files=[
        ("share/ament_index/resource_index/packages", ["resource/" + package_name]),
        ("share/" + package_name, ["package.xml", "pyproject.toml"]),
    ],

Looks something like:

$ dpkg-query -L ros-galactic-template-py-publisher
/.
/opt
/opt/ros
/opt/ros/galactic
/opt/ros/galactic/bin
/opt/ros/galactic/bin/publisher
/opt/ros/galactic/lib
/opt/ros/galactic/lib/python3.8
/opt/ros/galactic/lib/python3.8/site-packages
/opt/ros/galactic/lib/python3.8/site-packages/template_py_publisher
/opt/ros/galactic/lib/python3.8/site-packages/template_py_publisher/__init__.py
/opt/ros/galactic/lib/python3.8/site-packages/template_py_publisher/__pycache__
/opt/ros/galactic/lib/python3.8/site-packages/template_py_publisher/__pycache__/__init__.cpython-38.pyc
/opt/ros/galactic/lib/python3.8/site-packages/template_py_publisher/__pycache__/publisher.cpython-38.pyc
/opt/ros/galactic/lib/python3.8/site-packages/template_py_publisher/publisher.py
/opt/ros/galactic/lib/python3.8/site-packages/template_py_publisher-0.0.0.egg-info
/opt/ros/galactic/lib/python3.8/site-packages/template_py_publisher-0.0.0.egg-info/PKG-INFO
/opt/ros/galactic/lib/python3.8/site-packages/template_py_publisher-0.0.0.egg-info/dependency_links.txt
/opt/ros/galactic/lib/python3.8/site-packages/template_py_publisher-0.0.0.egg-info/entry_points.txt
/opt/ros/galactic/lib/python3.8/site-packages/template_py_publisher-0.0.0.egg-info/requires.txt
/opt/ros/galactic/lib/python3.8/site-packages/template_py_publisher-0.0.0.egg-info/top_level.txt
/opt/ros/galactic/lib/python3.8/site-packages/template_py_publisher-0.0.0.egg-info/zip-safe
/opt/ros/galactic/share
/opt/ros/galactic/share/ament_index
/opt/ros/galactic/share/ament_index/resource_index
/opt/ros/galactic/share/ament_index/resource_index/packages
/opt/ros/galactic/share/ament_index/resource_index/packages/template_py_publisher
/opt/ros/galactic/share/template_py_publisher
/opt/ros/galactic/share/template_py_publisher/package.xml
/opt/ros/galactic/share/template_py_publisher/pyproject.toml
/usr
/usr/share
/usr/share/doc
/usr/share/doc/ros-galactic-template-py-publisher
/usr/share/doc/ros-galactic-template-py-publisher/changelog.Debian.gz
/usr/share/doc/ros-galactic-template-py-publisher/copyright

Running install over this I get:

$ python3 -m colcon_poetry_ros.dependencies.install --base-path /opt/ros/galactic/share

The lock file does not exist. Locking.
Updating dependencies
Resolving dependencies... (0.1s)

[Errno 13] Permission denied: '/opt/ros/galactic/share/template_py_publisher/poetry.lock'
Traceback (most recent call last):
  File "/home/ros/.local/lib/python3.8/site-packages/colcon_poetry_ros/package.py", line 99, in get_requirements_txt
    subprocess.run(
  File "/usr/lib/python3.8/subprocess.py", line 516, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['poetry', 'export', '--format', 'requirements.txt', '--output', '/tmp/tmp4nmmji81']' returned non-zero exit status 1.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/home/ros/.local/lib/python3.8/site-packages/colcon_poetry_ros/dependencies/install.py", line 179, in <module>
    main()
  File "/home/ros/.local/lib/python3.8/site-packages/colcon_poetry_ros/dependencies/install.py", line 22, in main
    _install_dependencies_via_pip(
  File "/home/ros/.local/lib/python3.8/site-packages/colcon_poetry_ros/dependencies/install.py", line 94, in _install_dependencies_via_pip
    requirements_data = project.get_requirements_txt([])
  File "/home/ros/.local/lib/python3.8/site-packages/colcon_poetry_ros/package.py", line 106, in get_requirements_txt
    raise RuntimeError(
RuntimeError: Failed to export Poetry dependencies in the requirements.txt format: Command '['poetry', 'export', '--format', 'requirements.txt', '--output', '/tmp/tmp4nmmji81']' returned non-zero exit status 1.

Even ignoring this permission issue - I imagine there will be problems. I could poetry shell && poetry install next to the pyproject.toml but I'm not sure how I'd tell launch which venv to use for which node.

I was wondering if anyone had any thoughts on how to get this working?

Exception when building a projct

This may be caused after adding python files to a package or adding a dependency. Exact replication instructions haven't been determined yet.

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/colcon_core/executor/__init__.py", line 91, in __call__
    rc = await self.task(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/colcon_core/task/__init__.py", line 93, in __call__
    return await task_method(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/colcon_poetry_ros/task/poetry/build.py", line 101, in build
    shutil.copy2(str(script), str(ros_script_dir))
  File "/usr/lib/python3.8/shutil.py", line 435, in copy2
    copyfile(src, dst, follow_symlinks=follow_symlinks)
  File "/usr/lib/python3.8/shutil.py", line 264, in copyfile
    with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
IsADirectoryError: [Errno 21] Is a directory: '/robot/install/vision/bin/__pycache__'

Use Poetry's bundle plugin instead of `poetry export`

We currently go through this awkward process of exporting Poetry dependencies to a requirements.txt and then installing those dependencies with Pip. We do this because Poetry didn't used to have a way of saving dependencies to a configurable location. Now, with the release of Poetry 1.2.0 and the bundle plugin, we can reconsider this solution.

identically named scripts from different package are clobbered in merged workspace [race condition?]

When multiple packages have a [tool.poetry.scripts] script and are installed with the parallel executor and merge flag (colcon build --merge), there could be potentially be multiple packages writing scripts to bin while one package is copying bin/*.

Additionally, any package that have previously written files to /bin would be damaged due to the use of globing here.

I'm testing some solutions to #20 and consistently see this occurring.

possible solutions:

  • if it wasn't the case that previous packages could have installed to bin, mutexing the install (there was similar race condition in the the core python that was fixed like so colcon/colcon-core#142)
  • assuming script names are unique across packages (should they be?), reading the list of scripts to copy from pyproject.toml
  • install into a staging area (eg. in build) before copying to install

Publish releases to PyPI

PyPI would be a good secondary home for this extension. The primary home should ideally be an APT repository or a PPA.

Install dependencies to the package's install location

Instead of installing Python dependencies globally, it would be neat to put it under Colcon's install/ directory for that package. This would provide the kind of dependency isolation that users expect when using Poetry. The main sticking point here is that it would require creating and laying out the install/ directory before Colcon does, since dependency installation should come before building. That might cause problems.

The dependency installation command should support Colcon's --install-base and --merge-install arguments.

Test dependencies are never installed

When dependency installation was moved out of build and test commands, we lost the ability to install test dependencies. The solution here is probably to make colcon_poetry_ros.dependencies.install optionally install test dependencies.

Dependency to other colcon packages in the ws

Summary

Hey there, I found really interesting this tool and I wanted to give it a shot
In order to try this out I created a colcon ws and I created a couple of poetry packages.
However, I found an issue when trying to identify dependencies among the pacakges via colcon graph or even the order of "building" when doing packages-up-to

I might probably be missing some configuration, I am not really poetry savvy

Replicating the issue

Basically I created a couple of packages in my ws:

  1. ros2 pkg create --build-type ament_python my_py_pkg
  2. ros2 pkg create --build-type ament_python my_py_pkg_2
  3. In the package xml of the second package I added the first one as a dependency.

So far (no poetry-ros so far) when doing colcon graph the dependencies are correctly identified:

my_py_pkg     +*
my_py_pkg_2    +
  1. Then, via poetry init I initalized the pyproject.toml for each package. (Also removed the setup.py file as it is no longer needed)

From here I proceeded to colcon build (previously installing colcon-poetry-ros extension) things are "ok"(things are built and installed).

However, when checking the dependencies via colcon graph the dependencies aren't well identified.

my_py_pkg     + 
my_py_pkg_2    +

Consequently, the ordering of the colcon build executing isn't expected.

Clarify effects on test task

Right now, the test task defined in this extension is a thin wrapper around the Python test task defined by colcon-core, but with PyTest forced on. However, looking at the code, there's no reason why the oddly named setup.py testing mode wouldn't work. It just appears to run tests using unittest.

The only thing that will definitely not work is colcon-core's automatic testing mode detection. It uses dependencies specified in the user's setup.py to figure out whether to use PyTest or unittest automatically. It looks like the code is written with fallbacks in case that information is not available, but it's worth investigating if we can do some auto-detection of our own.

simultaneous script install for multiple packages in --merge build results in unpredictable files copied to lib/package_name

When multiple packages have a [tool.poetry.scripts] script and are installed with the parallel executor and merge flag (colcon build --merge), there could be potentially be multiple packages writing scripts to bin while one package is copying bin/*. I believe this is a race condition between build tasks.

Additionally, any package that have previously written files to /bin would be damaged due to the use of globing here.

I'm testing some solutions to #20 and consistently see this occurring.

possible solutions:

  • if it wasn't the case that previous packages could have installed to bin, mutexing the install (there was similar race condition in the the core python that was fixed like so colcon/colcon-core#142)
  • assuming script names are unique across packages (should they be?), reading the list of scripts to copy from pyproject.toml
  • install into a staging area (eg. in build) before copying to install

"Destination path already exists" when running the same build twice

This happens when running a successful build twice in a row.

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/colcon_core/executor/__init__.py", line 91, in __call__
    rc = await self.task(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/colcon_core/task/__init__.py", line 93, in __call__
    return await task_method(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/colcon_poetry_ros/task/poetry/build.py", line 60, in build
    shutil.move(
  File "/usr/lib/python3.8/shutil.py", line 789, in move
    raise Error("Destination path '%s' already exists" % real_dst)
shutil.Error: Destination path '/robot/build/hardware/poetry_dist/dist' already exists

Consider installing Python dependencies in a virtualenv

Doing this would be tricky, because we probably can't let Poetry manage the virtual environment for us since poetry install does not allow us to specify a target path. We would also need to augment the automatically generated entrypoint scripts for nodes so that they enter the virtual environment automatically.

remove dependency on package.xml

This extension currently requires a package.xml to be present. Similar to how colcon-cmake and colcon-ros work, I suggest that it would make a lot of sense to make this optional.

There could be a package colcon-poetry that extracts all information solely from the pyproject.toml and a colcon-poetry-ros that merges the information from the pyproject.toml and package.xml. This is useful in order to build "pure" python packages without a package.xml that only require python packages available on PyPI, and to have the option to define additional non-python dependencies in a package.xml.

Poetry `1.2.0` writes unrelated lines when running `poetry export`

Currently, colcon-poetry-ros runs poetry export and saves the stdout to a file, and then installs it.

This no longer works as-is with poetry 1.2.0 because it prints out Creating virtualenv XXXX-hash in /path/to/virtualenvs, and that's getting saved to the file and causes an error that looks like:

ERROR: Invalid requirement: 'Creating virtualenv XXXX-hash in /path/to/virtualenvs'

Warnings and issues during setup

When following the setup guide things didn't go too smoothly for me.

Issue 1 - setup.cfg

I was getting the following error:

WARNING:colcon.colcon_poetry_ros.task.poetry.build:Poetry did not install any scripts. Are you missing a [tool.poetry.scripts] section?

I was able to solve this by deleting the setup.cfg. If this is the correct solution it would be good to add a note in the README.md

Issue 2 - not finding install packages

Running a simple colcon build and then python3 -m colcon_poetry_ros.dependencies.install results in:

No packages were found in the following paths: <some_path_to_my_working_dir>

Specifying python3 -m colcon_poetry_ros.dependencies.install --base-path install got me closer to the solution but I was still getting

No packages were found in the following paths: install

Issue 3 - missing pyproject.tomls

pyproject.toml and package.xml missing from root of install dir.

As mentioned in issue 2, I was getting No packages were found in the following paths: install
I was able to resolve this by adding more data-files to the pyproject.toml

[tool.colcon-poetry-ros.data-files]
"share/ament_index/resource_index/packages" = ["resource/my_package_name"]
"share/my_package_name" = ["package.xml", "pyproject.toml"]

Does it also make sense to add the poetry.lock here?

I can get it working using
colcon build
and
python3 -m colcon_poetry_ros.dependencies.install --base-path /install/my_package_name/share/ but --base-path install won't find anything.
It seems globbing helps with this:
python3 -m colcon_poetry_ros.dependencies.install --base-path install/*/share

Issue 4 - merge install

I can make the above work with --merge-install using:
colcon build --merge-install
python3 -m colcon_poetry_ros.dependencies.install --merge-install --base-path install/share

This only works with --merge-install --base-path install/share.
If I add a different --base-path, eg --merge-install --base-path /opt/some_path_where_i_did_my_colcon_install_base, it will still output all the ./install/lib/etc/etc relative to the working dir, not the base-path

I've been rsyncing the files over to the base-path location as a quick hack...

python3 -m colcon_poetry_ros.dependencies.install --base-path /my_base_path/*/share
rsync -av install/ /my_base_path/
rm -rf install

Issue 5 - mode

I could not get --mode bundle to work without --merge-install.

With merge install: python3 -m colcon_poetry_ros.dependencies.install --method bundle --merge-install --base-path install/share it seems to work
Without merge install it would error:

  • Bundling some_package (0.0.0) into /home/ros/some_path/install/some_package: Installing dependencies

[Errno 2] No such file or directory
Traceback (most recent call last):
  File "/usr/lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/home/ros/some_path/colcon-poetry-ros/colcon_poetry_ros/dependencies/install.py", line 178, in <module>
    main()
  File "/home/ros/some_path/colcon-poetry-ros/colcon_poetry_ros/dependencies/install.py", line 25, in main
    _install_dependencies_via_poetry_bundle(
  File "/home/ros/some_path/colcon-poetry-ros/colcon_poetry_ros/dependencies/install.py", line 82, in _install_dependencies_via_poetry_bundle
    subprocess.run(
  File "/usr/lib/python3.8/subprocess.py", line 516, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['poetry', 'bundle', 'venv', '/home/ros/some_path/install/some_package']' returned non-zero exit status 1.

In summary, I seem to almost have it mostly working... I'm not sure if my setup is weird or if it is just a matter of improving the logs and how the packages are collected. The main issue I see is that python3 -m colcon_poetry_ros.dependencies.install --base-path /my_base_path/*/share does not install the deps into the base_path folder.

"file exists" error if folder is added to data-files

The README points out, that that copying entire directories is supported for data files.

If I use something like this:

[tool.colcon-poetry-ros.data-files]
"share/ament_index/resource_index/packages" = ["resource/{package_name}"]
"share/{package_name}" = ["package.xml", "secrets"]

The first build runs fine and secrets folder is copied to share folder correctly. But from the second build on, I do get the following error:

--- stderr: {package_name}                   
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/colcon_core/executor/__init__.py", line 91, in __call__
    rc = await self.task(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/colcon_core/task/__init__.py", line 93, in __call__
    return await task_method(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/colcon_poetry_ros/task/poetry/build.py", line 133, in build
    return_code = await self._add_data_files()
  File "/usr/local/lib/python3.8/dist-packages/colcon_poetry_ros/task/poetry/build.py", line 209, in _add_data_files
    shutil.copytree(str(source_path), str(dest_path / source_path.name))
  File "/usr/lib/python3.8/shutil.py", line 557, in copytree
    return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
  File "/usr/lib/python3.8/shutil.py", line 458, in _copytree
    os.makedirs(dst, exist_ok=dirs_exist_ok)
  File "/usr/lib/python3.8/os.py", line 223, in makedirs
    mkdir(name, mode)
FileExistsError: [Errno 17] File exists: '/path/to/my/ros2/ws/install/{package_name}/share/{package_name}/secrets'

Thanks in advance, regards, Nils

Usage with ament_cmake_python?

I tend to write / have a bunch of hybridized packages, C++ and python.
This might sound noob-ish, but I am not familiar with a better way to do this (combined); I've only ever used requirements.txt or poetry ❤️ . And for ros, all best practices go out the door, and everything is installed globally, the setup.cfg/py too complicated, so I've tried to avoid that. I just discovered this wonderful repo today, so I'm willing to convert!

My current solution has been adding python to cmake like the tutorial, then (as in doc) way at the bottom of the CMakeLists.txt, adding the following lines:

install(DIRECTORY scripts/ DESTINATION lib/${PROJECT_NAME})
ament_python_install_package(${PROJECT_NAME}_py)

For dependency installation, each package has a requirements.txt, and I can install / update all my packages either with a rosdep -yr (silencing failures), then a find . -name "requirements.txt" -exec pip install -r {} \;, and then... deal with whatever remaining problems manually.

What "build" steps can be moved into the CMakeLists, and how does using poetry with this change environments?
What marginal work needs to be done in the pyproject.toml that's not in package.xml/CMakeLists.txt, and what is required, but yes is redundant?

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.