Code Monkey home page Code Monkey logo

bazel-pypi-package's Introduction

Bazel PyPi Package

A Bazel macro for building Python packages and interacting with PyPi. The goal is to have the package configuration one would have in a setup.py file inside a Bazel BUILD file as a pypi_package rule. Interacting with PyPi is then done via Bazel commands, rather than the regualr commands, which are outside the build system.

Rationale

Bazel offers the py_library, py_test and py_binary rules. These are great for working inside a single application codebase. However, many Python projects are libraries, and are exported as packages in the Python Package Index - PyPi. Bazel does not offer anything for integrating with it, at the moment. As such, all the interaction is done through the regular mechanisms described in Packaging and Distributing Projects. This implies the existance of the setup.py, MANIFEST.in and .pypirc files, as well as the existance of build, dist, *.egg-info and other top-level directories which contain Python build artifacts. This state of affairs is quite messy. There are two separate build systems present, each with their configuration and each producing different forms of output clutter. Ideally we'd want only one - Bazel.

The goal of this project is to correct this state of affairs, by providing a small set of tools which encapsulate all the configuration and steps necessary for managing the interaction with the Python package index. At some point in the future, it should be integrated with regular Bazel.

Installation and Usage

Bazel doesn't yet allow importing macro libraries in the workspace. Therefore, one has to copy pypi_package.bzl in a location from which other BUILD files can load it.

The following usage example is borrowed from the tabletest package, which is a small utility library for writing neater unit-tests.

In a BUILD file, one has to first import the macro, like so:

load("/tools/pypi_package", "pypi_package")

We define a regular Python library, which will be included in the package. In general, we can have more than one such library.

py_library(
    name = "tabletest",
    srcs = ["tabletest/__init__.py"],
    visibility = ["//visibility:public"],
    srcs_version = "PY2"
)

In a manner similar to the configuration for the setup function, we then write the pypi_package rule as:

pypi_package(
    name = "tabletest_pkg",
    version = "1.0.2",
    description = "Unit testing module for table-like test, for Python 2.",
    long_description = "README.md",
    classifiers = [
        "Development Status :: 4 - Beta",
        "Environment :: Console",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: MIT License",
        "Operating System :: POSIX",
        "Programming Language :: Python :: 2",
        "Programming Language :: Python :: 2.6",
        "Programming Language :: Python :: 2.7",
        "Topic :: Software Development :: Testing",
        "Topic :: Software Development :: Libraries :: Python Modules"
    ],
    keywords = "unittest test table testing",
    url = "http://github.com/horia141/tabletest",
    author = "Horia Coman",
    author_email = "[email protected]",
    license = "MIT",
    packages = [":tabletest"],
    test_suite = "nose.collector",
    tests_require = ["nose"],
)

We must first register the package with PyPi. This is achieved by running the following binary:

bazel run //:tabletest_register -- --pypi_user=[your username] --pypi_pass=[your password]

After registering (which should be done only once, but is otherwise idempotent), we can upload the current version of the code (the result of building the py_library rule from above) to the package index via:

bazel run //:tabletest_upload -- --pypi_user=[your username] --pypi_pass=[your password]

The name of the pypi_package rule needs to end in _pkg and the prefix for it will be used to generate the _register and _upload binaries.

Each time a new version needs to be updated, the version field must be updated.

The rule tries to mimick the behavior of the setup.py file as described here, but with extra integration with Bazel, such as accepting labels for local libraries and the README.md file etc.

Interaction With Other Packages

In the install_requires and tests_require fields, one can specify the required dependencies for installing the package and for testing it. These operate at the PyPi level however, so they are specified as regular strings. However, if one depends on a repository for a package which also uses Bazel and this macro, then one can depend on that rule, rather than just specifying it as a string.

For example, the WORKSPACE file for the SDHash project, looks like this:

git_repository(
    name = "tabletest",
    remote = "https://github.com/horia141/tabletest.git",
    tag = "v1.0.3",
)

The pypi_package rule references the tabletest package like this:

pypi_package(
    name = "sdhash_pkg",
    version = "0.0.3",
    description = "Library for image hashing and deduplication.",
    long_description = "README.md",
    classifiers = [...],
    keywords = "photo image gif hash perceptual dedup deduplication fft",
    url = "http://github.com/horia141/sdhash",
    author = "Horia Coman",
    author_email = "[email protected]",
    license = "MIT",
    packages = [":sdhash"],
    install_requires = ["pillow", "numpy", "scipy"],
    test_suite = "nose.collector",
    tests_require = ["nose", "@tabletest//:tabletest_pkg"],
)

The tests_require line could also have looked like this:

...
    tests_require = ["nose", "tabletest"],
...

In both cases, the package must exist in PyPi.

Requirements

A working installation of Bazel and everything in Packaging and Distributing Projects.

bazel-pypi-package's People

Contributors

horia141 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

bazel-pypi-package's Issues

Generating package with nested packages

Hi, nice macro you have here for publishing :)

I am trying to package a dummy py_library with your macro but I am having problems with the first genrule:

    native.genrule(
        name = name,
        srcs = packages + [long_description],
        outs = ["setup.py", "MANIFEST.in"],
        cmd = 
            ("echo CREATING FILES!!!") +
            ("echo '%s' > $(location setup.py)" % setup_py) + 
            (" && echo '%s' > $(location MANIFEST.in)" % manifest_in) +
            (" && mkdir -p $(GENDIR)/%s" % short_name) +
            (" && cp $(SRCS) $(GENDIR)/%s" % short_name) +
            (" && mv $(GENDIR)/%s/%s $(GENDIR)" % (short_name, long_description)),
	    visibility = visibility,
    )

my package layout is as follows:

dummy
  __init__.py
  other
    __init__.py

The rule in BUILD.bazel is:

py_library(
    name = "dummy_py_library",
    srcs = [
        "dummy/__init__.py",
        "dummy/other/__init__.py"
    ],
    srcs_version = "PY3"
)

When I run the pypi_package with packages = [":dummy_py_library"] I get the following error:

cp: will not overwrite just-created 'bazel-out/k8-fastbuild/bin/lluvia/__init__.py' with 'python/dummy/other/__init__.py'

What would the macro need to support nested packages?

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.