├── .Brewfile.travis ├── .bazelrc ├── .gitignore ├── .travis.yml ├── BUILD ├── README.md ├── WORKSPACE ├── python.bzl ├── rules ├── BUILD ├── compile.bzl ├── dependencies.bzl └── repository.bzl ├── runtime ├── BUILD └── dynamic.sh ├── src ├── bin │ ├── BUILD │ ├── compile_pip_requirements.py │ ├── create_pip_repository.py │ └── replace_shebang.py ├── piprules │ ├── BUILD │ ├── __init__.py │ ├── bazel.py │ ├── util.py │ └── wheels.py └── templates │ ├── BUILD │ └── compile_pip_requirements_wrapper_template.sh ├── test ├── BUILD ├── data_test.py ├── dependency_deduplication_test.py ├── ietf-yang-metadata.yin ├── mock_test.py ├── pathlib_test.py └── pyyaml_test.py ├── thirdparty └── pip │ ├── 2 │ ├── BUILD │ ├── requirements-linux.txt │ └── requirements-osx.txt │ ├── 3 │ ├── BUILD │ ├── requirements-linux.txt │ └── requirements-osx.txt │ ├── BUILD │ └── requirements.in └── tools ├── BUILD ├── compile_pip_requirements.par ├── create_pip_repository.par ├── pytest ├── BUILD ├── main_template.py └── rules.bzl └── update.sh /.Brewfile.travis: -------------------------------------------------------------------------------- 1 | tap "homebrew/cask-versions" 2 | cask "java8" 3 | tap "bazelbuild/tap", pin:true 4 | brew "bazel" 5 | -------------------------------------------------------------------------------- /.bazelrc: -------------------------------------------------------------------------------- 1 | run --python_top=//runtime:dynamic 2 | test --python_top=//runtime:dynamic --build_tests_only 3 | 4 | # Control progress output when invoked by Travis 5 | build:travis --noshow_progress --show_task_finish --action_env=PATH --action_env=PYENV_VERSION=3.6.3:2.7.14 --nodistinct_host_configuration 6 | 7 | try-import %workspace%/user.bazelrc 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bazel-* 2 | user.bazelrc 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - osx 3 | - linux 4 | 5 | dist: trusty 6 | 7 | language: 8 | - generic 9 | 10 | addons: 11 | homebrew: 12 | brewfile: .Brewfile.travis 13 | apt: 14 | sources: 15 | - sourceline: 'deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8' 16 | key_url: 'https://storage.googleapis.com/bazel-apt/doc/apt-key.pub.gpg' 17 | packages: 18 | - openjdk-8-jdk 19 | - bazel 20 | 21 | install: 22 | - pyenv install --skip-existing 2.7.14 23 | - pyenv install --skip-existing 3.6.3 24 | 25 | script: 26 | - bazel test --config=travis ... 27 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | load("@com_github_bazelbuild_buildtools//buildifier:def.bzl", "buildifier") 2 | 3 | # Run this target to auto-format all Bazel files 4 | buildifier(name = "format") 5 | 6 | config_setting( 7 | name = "linux", 8 | constraint_values = ["@bazel_tools//platforms:linux"], 9 | visibility = ["//visibility:public"], 10 | ) 11 | 12 | config_setting( 13 | name = "osx", 14 | constraint_values = ["@bazel_tools//platforms:osx"], 15 | visibility = ["//visibility:public"], 16 | ) 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bazel rules for pip requirements 2 | 3 | [![Build Status](https://travis-ci.org/apt-itude/rules_pip.svg?branch=master)](https://travis-ci.org/apt-itude/rules_pip) 4 | 5 | ## Overview 6 | This repository provides rules for the [Bazel build tool](https://www.bazel.build/) that allow your Python code to depend on pip packages using a standard [requirements file](https://pip.pypa.io/en/stable/user_guide/#requirements-files). It is built in pure Python and uses the `pip` and `wheel` libraries to ensure that the resulting dependency set is the same as it would be by using those tools. 7 | 8 | This repository is designed to be compatible with both Python 2 and 3 in a single repo, as well as support multiple platforms. 9 | 10 | ## Setup 11 | Add the following to your `WORKSPACE` file: 12 | ``` 13 | git_repository( 14 | name = "com_apt_itude_rules_pip", 15 | commit = "e5ed5e72bf5a7521244e1d2119821628bbf17263", 16 | remote = "https://github.com/apt-itude/rules_pip.git", 17 | ) 18 | 19 | load("@com_apt_itude_rules_pip//rules:dependencies.bzl", "pip_rules_dependencies") 20 | 21 | pip_rules_dependencies() 22 | ``` 23 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "com_apt_itude_rules_pip") 2 | 3 | # Dependencies for this repository 4 | 5 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 6 | load("//rules:dependencies.bzl", "pip_rules_dependencies") 7 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 8 | 9 | pip_rules_dependencies() 10 | 11 | # Buildifier repositories 12 | 13 | http_archive( 14 | name = "io_bazel_rules_go", 15 | sha256 = "7be7dc01f1e0afdba6c8eb2b43d2fa01c743be1b9273ab1eaf6c233df078d705", 16 | url = "https://github.com/bazelbuild/rules_go/releases/download/0.16.5/rules_go-0.16.5.tar.gz", 17 | ) 18 | 19 | http_archive( 20 | name = "com_github_bazelbuild_buildtools", 21 | strip_prefix = "buildtools-0.15.0", 22 | url = "https://github.com/bazelbuild/buildtools/archive/0.15.0.zip", 23 | ) 24 | 25 | load( 26 | "@io_bazel_rules_go//go:def.bzl", 27 | "go_register_toolchains", 28 | "go_rules_dependencies", 29 | ) 30 | 31 | go_rules_dependencies() 32 | 33 | go_register_toolchains() 34 | 35 | load( 36 | "@com_github_bazelbuild_buildtools//buildifier:deps.bzl", 37 | "buildifier_dependencies", 38 | ) 39 | 40 | buildifier_dependencies() 41 | 42 | # PIP repositories 43 | 44 | load("//rules:repository.bzl", "pip_repository") 45 | load("//:python.bzl", "PYTHON2", "PYTHON3") 46 | 47 | pip_repository( 48 | name = "pip2", 49 | python_interpreter = PYTHON2, 50 | requirements_per_platform = { 51 | "//thirdparty/pip/2:requirements-linux.txt": "linux", 52 | "//thirdparty/pip/2:requirements-osx.txt": "osx", 53 | }, 54 | ) 55 | 56 | pip_repository( 57 | name = "pip3", 58 | python_interpreter = PYTHON3, 59 | requirements_per_platform = { 60 | "//thirdparty/pip/3:requirements-linux.txt": "linux", 61 | "//thirdparty/pip/3:requirements-osx.txt": "osx", 62 | }, 63 | ) 64 | -------------------------------------------------------------------------------- /python.bzl: -------------------------------------------------------------------------------- 1 | PYTHON2 = "python2.7" 2 | PYTHON3 = "python3.6" 3 | -------------------------------------------------------------------------------- /rules/BUILD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apt-itude/rules_pip/aafdefd2bf1a9f6995669c1d744da493de9a7b75/rules/BUILD -------------------------------------------------------------------------------- /rules/compile.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//lib:paths.bzl", "paths") 2 | 3 | def _get_path_relative_to_workspace(path, ctx): 4 | if paths.is_absolute(path): 5 | return paths.relativize(path, "/") 6 | else: 7 | return paths.join(ctx.label.package, path) 8 | 9 | def _compile_pip_requirements_impl(ctx): 10 | out_file = ctx.actions.declare_file(ctx.label.name + ".sh") 11 | 12 | requirements_txt_path = _get_path_relative_to_workspace( 13 | ctx.attr.requirements_txt, 14 | ctx, 15 | ) 16 | 17 | substitutions = { 18 | "@@REQUIREMENTS_IN_PATH@@": ctx.file.requirements_in.short_path, 19 | "@@REQUIREMENTS_TXT_PATH@@": requirements_txt_path, 20 | "@@PYTHON_INTERPRETER_PATH@@": ctx.attr.python_interpreter, 21 | "@@PIP_COMPILE_BINARY@@": ctx.executable._pip_compile.short_path, 22 | "@@HEADER@@": ctx.attr.header, 23 | } 24 | 25 | ctx.actions.expand_template( 26 | template = ctx.file._template, 27 | output = out_file, 28 | substitutions = substitutions, 29 | is_executable = True, 30 | ) 31 | 32 | runfiles = ctx.runfiles( 33 | files = ( 34 | ctx.files.requirements_in + 35 | ctx.files.data + 36 | ctx.files._pip_compile 37 | ), 38 | ) 39 | 40 | return [DefaultInfo( 41 | files = depset([out_file]), 42 | runfiles = runfiles, 43 | executable = out_file, 44 | )] 45 | 46 | compile_pip_requirements = rule( 47 | implementation = _compile_pip_requirements_impl, 48 | attrs = { 49 | "requirements_in": attr.label( 50 | allow_single_file = [".in"], 51 | mandatory = True, 52 | ), 53 | "data": attr.label_list(allow_files = True), 54 | "requirements_txt": attr.string(default = "requirements.txt"), 55 | "python_interpreter": attr.string(default = "python"), 56 | "header": attr.string(default = "# This file is generated code. DO NOT EDIT."), 57 | "_pip_compile": attr.label( 58 | default = "//tools:compile_pip_requirements.par", 59 | allow_single_file = True, 60 | cfg = "host", 61 | executable = True, 62 | ), 63 | "_template": attr.label( 64 | default = "//src/templates:compile_pip_requirements_wrapper_template.sh", 65 | allow_single_file = True, 66 | ), 67 | }, 68 | executable = True, 69 | ) 70 | -------------------------------------------------------------------------------- /rules/dependencies.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 2 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 3 | 4 | _WHEEL_BUILD_FILE_CONTENT = """ 5 | py_library( 6 | name = "lib", 7 | srcs = glob(["**/*.py"]), 8 | data = glob( 9 | ["**/*"], 10 | exclude = [ 11 | "**/*.py", 12 | "**/* *", # Bazel runfiles cannot have spaces in the name 13 | "BUILD", 14 | "WORKSPACE", 15 | "*.whl.zip", 16 | ], 17 | ), 18 | imports = ["."], 19 | visibility = ["//visibility:public"], 20 | ) 21 | """ 22 | 23 | def pip_rules_dependencies(): 24 | _remote_wheel( 25 | name = "pip", 26 | url = "https://files.pythonhosted.org/packages/c2/d7/90f34cb0d83a6c5631cf71dfe64cc1054598c843a92b400e55675cc2ac37/pip-18.1-py2.py3-none-any.whl", 27 | sha256 = "7909d0a0932e88ea53a7014dfd14522ffef91a464daaaf5c573343852ef98550", 28 | ) 29 | 30 | _remote_wheel( 31 | name = "setuptools", 32 | url = "https://files.pythonhosted.org/packages/96/06/c8ee69628191285ddddffb277bd5abdf769166e7a14b867c2a172f0175b1/setuptools-40.4.3-py2.py3-none-any.whl", 33 | sha256 = "ce4137d58b444bac11a31d4e0c1805c69d89e8ed4e91fde1999674ecc2f6f9ff", 34 | ) 35 | 36 | _remote_wheel( 37 | name = "wheel", 38 | url = "https://files.pythonhosted.org/packages/fc/e9/05316a1eec70c2bfc1c823a259546475bd7636ba6d27ec80575da523bc34/wheel-0.32.1-py2.py3-none-any.whl", 39 | sha256 = "9fa1f772f1a2df2bd00ddb4fa57e1cc349301e1facb98fbe62329803a9ff1196", 40 | ) 41 | 42 | _remote_wheel( 43 | name = "pip_tools", 44 | url = "https://files.pythonhosted.org/packages/f7/58/7a3c61ff7ea45cf0f13f3c58c5261c598a1923efa3327494f70c2d532cba/pip_tools-3.1.0-py2.py3-none-any.whl", 45 | sha256 = "31b43e5f8d605fc84f7506199025460abcb98a29d12cc99db268f73e39cf55e5", 46 | ) 47 | 48 | _remote_wheel( 49 | name = "click", 50 | url = "https://files.pythonhosted.org/packages/fa/37/45185cb5abbc30d7257104c434fe0b07e5a195a6847506c074527aa599ec/Click-7.0-py2.py3-none-any.whl", 51 | sha256 = "2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", 52 | ) 53 | 54 | _remote_wheel( 55 | name = "six", 56 | url = "https://files.pythonhosted.org/packages/67/4b/141a581104b1f6397bfa78ac9d43d8ad29a7ca43ea90a2d863fe3056e86a/six-1.11.0-py2.py3-none-any.whl", 57 | sha256 = "832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb", 58 | ) 59 | 60 | _ensure_rule_exists( 61 | git_repository, 62 | name = "bazel_skylib", 63 | remote = "https://github.com/bazelbuild/bazel-skylib.git", 64 | tag = "0.5.0", 65 | ) 66 | 67 | _ensure_rule_exists( 68 | git_repository, 69 | name = "subpar", 70 | remote = "https://github.com/google/subpar", 71 | tag = "2.0.0", 72 | ) 73 | 74 | def _remote_wheel(name, url, sha256): 75 | _ensure_rule_exists( 76 | http_archive, 77 | name = "pip_%s" % name, 78 | url = url, 79 | sha256 = sha256, 80 | build_file_content = _WHEEL_BUILD_FILE_CONTENT, 81 | type = "zip", 82 | ) 83 | 84 | def _ensure_rule_exists(rule_type, name, **kwargs): 85 | if name not in native.existing_rules(): 86 | rule_type(name = name, **kwargs) 87 | -------------------------------------------------------------------------------- /rules/repository.bzl: -------------------------------------------------------------------------------- 1 | def _get_platform(repo_ctx): 2 | if "mac" in repo_ctx.os.name: 3 | return "osx" 4 | 5 | return repo_ctx.os.name 6 | 7 | def _select_requirements_for_platform(repo_ctx): 8 | current_platform = _get_platform(repo_ctx) 9 | 10 | for label, intended_platform in repo_ctx.attr.requirements_per_platform.items(): 11 | if intended_platform == current_platform: 12 | return repo_ctx.path(label) 13 | 14 | fail( 15 | "None of the given requirements files match the current environment", 16 | attr = "pip_repository", 17 | ) 18 | 19 | def _pip_repository_impl(repo_ctx): 20 | repo_ctx.file("BUILD", "") 21 | 22 | create_repo_exe_path = repo_ctx.path(repo_ctx.attr._create_repo_exe) 23 | repo_directory = repo_ctx.path("") 24 | 25 | if repo_ctx.attr.requirements: 26 | requirements_path = repo_ctx.path(repo_ctx.attr.requirements) 27 | elif repo_ctx.attr.requirements_per_platform: 28 | requirements_path = _select_requirements_for_platform(repo_ctx) 29 | else: 30 | fail( 31 | "Either 'requirements' or 'requirements_per_platform' is required", 32 | attr = "pip_repository", 33 | ) 34 | 35 | r = repo_ctx.execute([ 36 | repo_ctx.attr.python_interpreter, 37 | create_repo_exe_path, 38 | repo_directory, 39 | requirements_path, 40 | ] + repo_ctx.attr.wheel_args) 41 | if r.return_code: 42 | fail(r.stderr) 43 | 44 | pip_repository = repository_rule( 45 | implementation = _pip_repository_impl, 46 | attrs = { 47 | "requirements": attr.label( 48 | allow_files = True, 49 | ), 50 | "requirements_per_platform": attr.label_keyed_string_dict( 51 | allow_files = True, 52 | allow_empty = False, 53 | ), 54 | "python_interpreter": attr.string(default = "python"), 55 | "wheel_args": attr.string_list(), 56 | "_create_repo_exe": attr.label( 57 | default = "//tools:create_pip_repository.par", 58 | executable = True, 59 | cfg = "host", 60 | ), 61 | }, 62 | ) 63 | -------------------------------------------------------------------------------- /runtime/BUILD: -------------------------------------------------------------------------------- 1 | py_runtime( 2 | name = "dynamic", 3 | files = [], 4 | interpreter = "dynamic.sh", 5 | visibility = ["//visibility:public"], 6 | ) 7 | -------------------------------------------------------------------------------- /runtime/dynamic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # dynamic entrypoint 3 | # in a posix-compatible way attempt to resolve interpreter path. 4 | # checks: 5 | # - shebang line (requires expr) 6 | # - path to python3 7 | # - path to python 8 | read -r firstline < "$1" 9 | exprpath=$(command -v expr) 10 | if test -n "${exprpath}"; then 11 | e=$(expr "$firstline" : '#!\(.*python.*\)') 12 | if test -n "${e}"; then 13 | exec $e "$@" 14 | fi 15 | fi 16 | py=$(command -v python3) 17 | if test -n "${py}"; then 18 | exec $py "$@" 19 | else 20 | exec $(command -v python) "$@" 21 | fi 22 | -------------------------------------------------------------------------------- /src/bin/BUILD: -------------------------------------------------------------------------------- 1 | load("@subpar//:subpar.bzl", "par_binary") 2 | 3 | par_binary( 4 | name = "compile_pip_requirements", 5 | srcs = ["compile_pip_requirements.py"], 6 | visibility = ["//visibility:public"], 7 | deps = [ 8 | "@pip_click//:lib", 9 | "@pip_pip//:lib", 10 | "@pip_pip_tools//:lib", 11 | "@pip_six//:lib", 12 | ], 13 | ) 14 | 15 | par_binary( 16 | name = "create_pip_repository", 17 | srcs = ["create_pip_repository.py"], 18 | visibility = ["//visibility:public"], 19 | zip_safe = False, 20 | deps = [ 21 | "//src/piprules", 22 | ], 23 | ) 24 | 25 | py_binary( 26 | name = "replace_shebang", 27 | srcs = ["replace_shebang.py"], 28 | visibility = ["//:__subpackages__"], 29 | ) 30 | -------------------------------------------------------------------------------- /src/bin/compile_pip_requirements.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Wrapper for the pip-tools compile entry point""" 3 | 4 | from piptools.scripts import compile as pip_compile 5 | 6 | 7 | if __name__ == '__main__': 8 | pip_compile.cli() 9 | -------------------------------------------------------------------------------- /src/bin/create_pip_repository.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from piprules import bazel, wheels 4 | 5 | 6 | def main(): 7 | args, extra_args = parse_args() 8 | wheels.download(args.repository_directory, args.requirements, *extra_args) 9 | unpack_wheels_into_bazel_packages(args.repository_directory) 10 | 11 | 12 | def parse_args(): 13 | parser = argparse.ArgumentParser() 14 | 15 | parser.add_argument("repository_directory") 16 | parser.add_argument("requirements") 17 | 18 | return parser.parse_known_args() 19 | 20 | 21 | def unpack_wheels_into_bazel_packages(repository_directory): 22 | for wheel_path in wheels.find_all(repository_directory): 23 | distribution = wheels.unpack(wheel_path, repository_directory) 24 | bazel.generate_package_for_python_distribution(distribution) 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /src/bin/replace_shebang.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.6 2 | 3 | import argparse 4 | import pathlib 5 | import re 6 | import sys 7 | 8 | 9 | SHEBANG_REGEX = re.compile(r"^#!.*") 10 | 11 | 12 | def main(): 13 | args = parse_args() 14 | 15 | args.output_path.parent.mkdir(parents=True, exist_ok=True) 16 | 17 | replace_shebang(args.input_path, args.output_path, args.interpreter) 18 | 19 | 20 | def parse_args(): 21 | parser = argparse.ArgumentParser() 22 | 23 | parser.add_argument("input_path", type=pathlib.Path) 24 | parser.add_argument("output_path", type=pathlib.Path) 25 | parser.add_argument("interpreter") 26 | 27 | return parser.parse_args() 28 | 29 | 30 | def replace_shebang(input_path, output_path, interpreter): 31 | input_contents = input_path.read_text() 32 | 33 | output_contents = SHEBANG_REGEX.sub( 34 | make_shebang(interpreter), 35 | input_contents, 36 | ) 37 | 38 | output_path.write_text(output_contents) 39 | 40 | 41 | def make_shebang(interpreter): 42 | return f"#!/usr/bin/env {interpreter}" 43 | 44 | 45 | if __name__ == "__main__": 46 | main() 47 | -------------------------------------------------------------------------------- /src/piprules/BUILD: -------------------------------------------------------------------------------- 1 | py_library( 2 | name = "piprules", 3 | srcs = glob(["*.py"]), 4 | imports = [".."], 5 | visibility = ["//visibility:public"], 6 | deps = [ 7 | "@pip_pip//:lib", 8 | "@pip_setuptools//:lib", 9 | "@pip_wheel//:lib", 10 | ], 11 | ) 12 | -------------------------------------------------------------------------------- /src/piprules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apt-itude/rules_pip/aafdefd2bf1a9f6995669c1d744da493de9a7b75/src/piprules/__init__.py -------------------------------------------------------------------------------- /src/piprules/bazel.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import os 3 | import shutil 4 | import textwrap 5 | 6 | from piprules import util 7 | 8 | 9 | def generate_package_for_python_distribution(distribution): 10 | _PyDistPackageGenerator(distribution).generate() 11 | 12 | 13 | class _PyDistPackageGenerator(object): 14 | 15 | def __init__(self, distribution): 16 | self.distribution = distribution 17 | 18 | @property 19 | def base_package_path(self): 20 | return self.distribution.location 21 | 22 | @property 23 | def base_package_build_file_path(self): 24 | return os.path.join(self.base_package_path, "BUILD") 25 | 26 | @property 27 | def base_package_name(self): 28 | return util.normalize_distribution_name(self.distribution.project_name) 29 | 30 | @property 31 | def data_source_pattern(self): 32 | return os.path.join(self.base_package_path, "*.data", "*") 33 | 34 | @property 35 | def library_name(self): 36 | return self.base_package_name 37 | 38 | @property 39 | def library_dependencies(self): 40 | return set( 41 | _LibraryDependency.from_distribution_requirement(req) 42 | for req in self.distribution.requires() 43 | ) 44 | 45 | def generate(self): 46 | self._create_base_package_build_file() 47 | 48 | for data_directory in self._find_data_directories(): 49 | _DataPackageGenerator(self.base_package_path, data_directory).generate() 50 | 51 | def _create_base_package_build_file(self): 52 | # Files with spaces in the name must be excluded 53 | # https://github.com/bazelbuild/bazel/issues/374 54 | contents = textwrap.dedent(""" 55 | py_library( 56 | name = "{name}", 57 | srcs = glob(["**/*.py"]), 58 | data = glob( 59 | ["**/*"], 60 | exclude = [ 61 | "**/*.py", 62 | "**/* *", # Bazel runfiles cannot have spaces in the name 63 | "**/BUILD", 64 | ], 65 | ), 66 | deps = [{deps}], 67 | imports = ["."], 68 | visibility = ["//visibility:public"], 69 | ) 70 | """).lstrip().format( 71 | name=self.library_name, 72 | deps=_create_string_list(sorted(dep.label for dep in self.library_dependencies)), 73 | ) 74 | 75 | with open(self.base_package_build_file_path, mode="w") as build_file: 76 | build_file.write(contents) 77 | 78 | def _find_data_directories(self): 79 | return glob.glob(self.data_source_pattern) 80 | 81 | 82 | class _LibraryDependency(object): 83 | 84 | def __init__(self, name): 85 | self.name = name 86 | 87 | def __eq__(self, other): 88 | return self.name == other.name 89 | 90 | def __hash__(self): 91 | return hash(self.name) 92 | 93 | @classmethod 94 | def from_distribution_requirement(cls, requirement): 95 | return cls(util.normalize_distribution_name(requirement.project_name)) 96 | 97 | @property 98 | def label(self): 99 | return "//{}".format(self.name) 100 | 101 | 102 | class _DataPackageGenerator(object): 103 | 104 | def __init__(self, base_package_path, data_directory): 105 | self.base_package_path = base_package_path 106 | self.data_directory = data_directory 107 | 108 | @property 109 | def package_name(self): 110 | return os.path.basename(self.data_directory) 111 | 112 | @property 113 | def package_path(self): 114 | return os.path.join(self.base_package_path, self.package_name) 115 | 116 | @property 117 | def symlink_target(self): 118 | return os.path.relpath(self.data_directory, start=self.base_package_path) 119 | 120 | def generate(self): 121 | os.symlink(self.symlink_target, self.package_path) 122 | self._create_build_files() 123 | 124 | def _create_build_files(self): 125 | for dirpath, dirnames, filenames in os.walk(self.package_path): 126 | _DataPackageBuildFileGenerator(dirpath, filenames).generate() 127 | 128 | 129 | class _DataPackageBuildFileGenerator(object): 130 | 131 | def __init__(self, package_path, filenames): 132 | self.package_path = package_path 133 | self.filenames = filenames 134 | 135 | @property 136 | def package_name(self): 137 | return os.path.basename(self.package_path) 138 | 139 | @property 140 | def build_file_path(self): 141 | return os.path.join(self.package_path, "BUILD") 142 | 143 | def generate(self): 144 | contents = self._get_contents() 145 | 146 | with open(self.build_file_path, mode="w") as build_file: 147 | build_file.write(contents) 148 | 149 | def _get_contents(self): 150 | if not self.filenames: 151 | return "" 152 | 153 | return textwrap.dedent(""" 154 | filegroup( 155 | name = "{package_name}", 156 | srcs = glob(["*"]), 157 | ) 158 | 159 | exports_files([{data_files}]) 160 | """).lstrip().format( 161 | package_name=self.package_name, 162 | data_files=_create_string_list(self.filenames), 163 | ) 164 | 165 | 166 | def _create_string_list(values): 167 | return ", ".join(_quote(value) for value in values) 168 | 169 | 170 | def _quote(value): 171 | return '"{}"'.format(value) 172 | -------------------------------------------------------------------------------- /src/piprules/util.py: -------------------------------------------------------------------------------- 1 | import errno 2 | import contextlib 3 | import os 4 | 5 | 6 | def normalize_distribution_name(name): 7 | return name.lower().replace("-", "_") 8 | 9 | 10 | def get_path_stem(path): 11 | return os.path.splitext(os.path.basename(path))[0] 12 | 13 | 14 | def ensure_directory_exists(path): 15 | try: 16 | os.makedirs(path) 17 | except OSError as err: 18 | if err.errno != errno.EEXIST: 19 | raise err 20 | 21 | 22 | def get_import_path_of_module(module): 23 | return os.path.abspath(os.path.dirname(os.path.dirname(module.__file__))) 24 | 25 | 26 | @contextlib.contextmanager 27 | def prepend_to_pythonpath(paths): 28 | original_pythonpath = os.environ.get("PYTHONPATH") 29 | original_parts = original_pythonpath.split(":") if original_pythonpath else [] 30 | os.environ["PYTHONPATH"] = ":".join(paths + original_parts) 31 | 32 | try: 33 | yield 34 | finally: 35 | if original_pythonpath is None: 36 | del os.environ["PYTHONPATH"] 37 | else: 38 | os.environ["PYTHONPATH"] = original_pythonpath 39 | -------------------------------------------------------------------------------- /src/piprules/wheels.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import glob 3 | import os 4 | import pkg_resources 5 | 6 | from pip._internal import main as pip_main 7 | from wheel import wheelfile 8 | 9 | from piprules import util 10 | 11 | 12 | class Error(Exception): 13 | 14 | """Base exception for the wheels module""" 15 | 16 | 17 | def download(dest_directory, requirements_file_path, *extra_args): 18 | with _add_pip_import_paths_to_pythonpath(): 19 | pip_main( 20 | args=[ 21 | "wheel", 22 | "-w", dest_directory, 23 | "-r", requirements_file_path, 24 | ] + list(extra_args) 25 | ) 26 | 27 | 28 | @contextlib.contextmanager 29 | def _add_pip_import_paths_to_pythonpath(): 30 | import pip 31 | import setuptools 32 | import wheel 33 | 34 | import_paths = [util.get_import_path_of_module(m) for m in [pip, setuptools, wheel]] 35 | with util.prepend_to_pythonpath(import_paths): 36 | yield 37 | 38 | 39 | def find_all(directory): 40 | for matching_path in glob.glob("{}/*.whl".format(directory)): 41 | yield matching_path 42 | 43 | 44 | def unpack(wheel_path, dest_directory): 45 | # TODO(): don't use unsupported wheel library 46 | with wheelfile.WheelFile(wheel_path) as wheel_file: 47 | distribution_name = wheel_file.parsed_filename.group("name") 48 | library_name = util.normalize_distribution_name(distribution_name) 49 | package_directory = os.path.join(dest_directory, library_name) 50 | wheel_file.extractall(package_directory) 51 | 52 | try: 53 | return next(pkg_resources.find_distributions(package_directory)) 54 | except StopIteration: 55 | raise DistributionNotFoundError(package_directory) 56 | 57 | 58 | class DistributionNotFoundError(Error): 59 | def __init__(self, package_directory): 60 | super(DistributionNotFoundError, self).__init__() 61 | self.package_directory = package_directory 62 | 63 | def __str__(self): 64 | return "Could not find in Python distribution in directory {}".format( 65 | self.package_directory 66 | ) 67 | -------------------------------------------------------------------------------- /src/templates/BUILD: -------------------------------------------------------------------------------- 1 | exports_files(["compile_pip_requirements_wrapper_template.sh"]) 2 | -------------------------------------------------------------------------------- /src/templates/compile_pip_requirements_wrapper_template.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -z ${BUILD_WORKSPACE_DIRECTORY+x} ]; then 3 | echo "This script must be executed with Bazel" 4 | exit 1 5 | fi 6 | 7 | REQUIREMENTS_IN_PATH="@@REQUIREMENTS_IN_PATH@@" 8 | REQUIREMENTS_TXT_PATH="$BUILD_WORKSPACE_DIRECTORY/@@REQUIREMENTS_TXT_PATH@@" 9 | PYTHON_INTERPRETER_PATH="@@PYTHON_INTERPRETER_PATH@@" 10 | PIP_COMPILE_BINARY="@@PIP_COMPILE_BINARY@@" 11 | 12 | echo "Compiling $REQUIREMENTS_TXT_PATH" 13 | $PYTHON_INTERPRETER_PATH $PIP_COMPILE_BINARY \ 14 | --output-file $REQUIREMENTS_TXT_PATH \ 15 | --no-header \ 16 | --no-index \ 17 | --generate-hashes \ 18 | --allow-unsafe \ 19 | "$@" \ 20 | $REQUIREMENTS_IN_PATH 21 | set -x 22 | echo "@@HEADER@@" > requirements.tmp 23 | cat $REQUIREMENTS_TXT_PATH >> requirements.tmp 24 | cp requirements.tmp $REQUIREMENTS_TXT_PATH 25 | -------------------------------------------------------------------------------- /test/BUILD: -------------------------------------------------------------------------------- 1 | load("//:python.bzl", "PYTHON2", "PYTHON3") 2 | load("//tools/pytest:rules.bzl", "pytest_test") 3 | 4 | pytest_test( 5 | name = "dependency_deduplication_test_2", 6 | src = "dependency_deduplication_test.py", 7 | deps = ["@pip2//isort"], 8 | python_version = 2, 9 | ) 10 | 11 | pytest_test( 12 | name = "dependency_deduplication_test_3", 13 | src = "dependency_deduplication_test.py", 14 | deps = ["@pip3//isort"], 15 | python_version = 3, 16 | ) 17 | 18 | pytest_test( 19 | name = "mock_test_2", 20 | src = "mock_test.py", 21 | deps = ["@pip2//pytest_mock"], 22 | python_version = 2, 23 | ) 24 | 25 | pytest_test( 26 | name = "mock_test_3", 27 | src = "mock_test.py", 28 | deps = ["@pip3//pytest_mock"], 29 | python_version = 3, 30 | ) 31 | 32 | pytest_test( 33 | name = "pathlib_test_2", 34 | src = "pathlib_test.py", 35 | deps = ["@pip2//pathlib2"], 36 | python_version = 2, 37 | ) 38 | 39 | pytest_test( 40 | name = "pathlib_test_3", 41 | src = "pathlib_test.py", 42 | python_version = 3, 43 | ) 44 | 45 | pytest_test( 46 | name = "pyyaml_test_2", 47 | src = "pyyaml_test.py", 48 | deps = ["@pip2//pyyaml"], 49 | python_version = 2, 50 | ) 51 | 52 | pytest_test( 53 | name = "pyyaml_test_3", 54 | src = "pyyaml_test.py", 55 | deps = ["@pip3//pyyaml"], 56 | python_version = 3, 57 | ) 58 | 59 | genrule( 60 | name = "pyang2_script", 61 | srcs = ["@pip2//pyang/scripts:pyang"], 62 | outs = ["pyang2.py"], 63 | tools = ["//src/bin:replace_shebang"], 64 | cmd = "$(location //src/bin:replace_shebang) $< $@ %s" % PYTHON2, 65 | ) 66 | 67 | py_binary( 68 | name = "pyang2", 69 | srcs = [":pyang2_script"], 70 | deps = ["@pip2//pyang"], 71 | ) 72 | 73 | genrule( 74 | name = "test-yin-2", 75 | srcs = ["@pip2//pyang/data/share/yang/modules/ietf:ietf-yang-metadata.yang"], 76 | outs = ["ietf-yang-metadata-2.yin"], 77 | tools = [":pyang2"], 78 | cmd = "$(location :pyang2) -f yin -o $@ $<", 79 | ) 80 | 81 | genrule( 82 | name = "pyang3_script", 83 | srcs = ["@pip3//pyang/scripts:pyang"], 84 | outs = ["pyang3.py"], 85 | tools = ["//src/bin:replace_shebang"], 86 | cmd = "$(location //src/bin:replace_shebang) $< $@ %s" % PYTHON3, 87 | ) 88 | 89 | py_binary( 90 | name = "pyang3", 91 | srcs = [":pyang3_script"], 92 | deps = ["@pip3//pyang"], 93 | ) 94 | 95 | genrule( 96 | name = "test-yin-3", 97 | srcs = ["@pip3//pyang/data/share/yang/modules/ietf:ietf-yang-metadata.yang"], 98 | outs = ["ietf-yang-metadata-3.yin"], 99 | tools = [":pyang3"], 100 | cmd = "$(location :pyang3) -f yin -o $@ $<", 101 | ) 102 | 103 | pytest_test( 104 | name = "data_test", 105 | src = "data_test.py", 106 | data = [ 107 | "ietf-yang-metadata.yin", 108 | ":test-yin-2", 109 | ":test-yin-3", 110 | ], 111 | python_version = 3, 112 | ) 113 | -------------------------------------------------------------------------------- /test/data_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.mark.parametrize("python_version", [2, 3]) 5 | def test_output(python_version): 6 | path = "test/ietf-yang-metadata-{}.yin".format(python_version) 7 | 8 | with open(path) as yin_file: 9 | contents = yin_file.read() 10 | 11 | with open("test/ietf-yang-metadata.yin") as expected_yin_file: 12 | expected_contents = expected_yin_file.read() 13 | 14 | assert contents == expected_contents 15 | -------------------------------------------------------------------------------- /test/dependency_deduplication_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | In Python 2, isort requires futures, but pkg_resources produces 2 different requirement 3 | instances for that library. This ensures that the duplicate requirements don't cause 4 | duplicate dependencies to be added to the build rule, which is an error. 5 | """ 6 | def test_isort(): 7 | import isort 8 | -------------------------------------------------------------------------------- /test/ietf-yang-metadata.yin: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | IETF NETMOD (NETCONF Data Modeling Language) Working Group 9 | 10 | 11 | WG Web: <https://datatracker.ietf.org/wg/netmod/> 12 | 13 | WG List: <mailto:netmod@ietf.org> 14 | 15 | WG Chair: Lou Berger 16 | <mailto:lberger@labn.net> 17 | 18 | WG Chair: Kent Watsen 19 | <mailto:kwatsen@juniper.net> 20 | 21 | Editor: Ladislav Lhotka 22 | <mailto:lhotka@nic.cz> 23 | 24 | 25 | This YANG module defines an 'extension' statement that allows 26 | for defining metadata annotations. 27 | 28 | Copyright (c) 2016 IETF Trust and the persons identified as 29 | authors of the code. All rights reserved. 30 | 31 | Redistribution and use in source and binary forms, with or 32 | without modification, is permitted pursuant to, and subject to 33 | the license terms contained in, the Simplified BSD License set 34 | forth in Section 4.c of the IETF Trust's Legal Provisions 35 | Relating to IETF Documents 36 | (http://trustee.ietf.org/license-info). 37 | 38 | This version of this YANG module is part of RFC 7952 39 | (http://www.rfc-editor.org/info/rfc7952); see the RFC itself 40 | for full legal notices. 41 | 42 | 43 | 44 | Initial revision. 45 | 46 | 47 | RFC 7952: Defining and Using Metadata with YANG 48 | 49 | 50 | 51 | 52 | 53 | This extension allows for defining metadata annotations in 54 | YANG modules. The 'md:annotation' statement can appear only 55 | at the top level of a YANG module or submodule, i.e., it 56 | becomes a new alternative in the ABNF production rule for 57 | 'body-stmts' (Section 14 in RFC 7950). 58 | 59 | The argument of the 'md:annotation' statement defines the name 60 | of the annotation. Syntactically, it is a YANG identifier as 61 | defined in Section 6.2 of RFC 7950. 62 | 63 | An annotation defined with this 'extension' statement inherits 64 | the namespace and other context from the YANG module in which 65 | it is defined. 66 | 67 | The data type of the annotation value is specified in the same 68 | way as for a leaf data node using the 'type' statement. 69 | 70 | The semantics of the annotation and other documentation can be 71 | specified using the following standard YANG substatements (all 72 | are optional): 'description', 'if-feature', 'reference', 73 | 'status', and 'units'. 74 | 75 | A server announces support for a particular annotation by 76 | including the module in which the annotation is defined among 77 | the advertised YANG modules, e.g., in a NETCONF <hello> 78 | message or in the YANG library (RFC 7950). The annotation can 79 | then be attached to any instance of a data node defined in any 80 | YANG module that is advertised by the server. 81 | 82 | XML encoding and JSON encoding of annotations are defined in 83 | RFC 7952. 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /test/mock_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | This tests that setuptools entry points work correctly since pytest plugins 3 | like pytest-mock rely on that functionality 4 | """ 5 | 6 | import sys 7 | 8 | import pytest 9 | 10 | 11 | @pytest.fixture 12 | def mock_argv(mocker): 13 | return mocker.patch.object(sys, "argv", ["fake", "args"]) 14 | 15 | 16 | def test_mock_args(mock_argv): 17 | assert sys.argv == ["fake", "args"] 18 | -------------------------------------------------------------------------------- /test/pathlib_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | This tests conditional dependencies based on Python runtime. The pathlib2 3 | module is only included if running Python 2. 4 | """ 5 | 6 | import sys 7 | 8 | if sys.version_info.major == 2: 9 | import pathlib2 as pathlib 10 | else: 11 | import pathlib 12 | 13 | 14 | def test_pathlib(): 15 | assert pathlib.Path("some/test/file.txt").stem == "file" 16 | -------------------------------------------------------------------------------- /test/pyyaml_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | This test ensures that Python distributions not published as wheels, like 3 | pyyaml, will be imported correctly. 4 | """ 5 | 6 | import yaml 7 | 8 | 9 | DATA = { 10 | "ghosts": [ 11 | "inky", 12 | "pinky", 13 | "blinky", 14 | "sue", 15 | ] 16 | } 17 | 18 | 19 | def test_yaml(): 20 | yaml_str = yaml.dump(DATA) 21 | assert yaml.load(yaml_str) == DATA 22 | -------------------------------------------------------------------------------- /thirdparty/pip/2/BUILD: -------------------------------------------------------------------------------- 1 | load("//rules:compile.bzl", "compile_pip_requirements") 2 | load("//:python.bzl", "PYTHON2") 3 | 4 | compile_pip_requirements( 5 | name = "compile", 6 | python_interpreter = PYTHON2, 7 | requirements_in = "//thirdparty/pip:requirements.in", 8 | requirements_txt = select({ 9 | "//:linux": "requirements-linux.txt", 10 | "//:osx": "requirements-osx.txt", 11 | }), 12 | ) 13 | 14 | exports_files(glob(["requirements*"])) 15 | -------------------------------------------------------------------------------- /thirdparty/pip/2/requirements-linux.txt: -------------------------------------------------------------------------------- 1 | atomicwrites==1.2.1 \ 2 | --hash=sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0 \ 3 | --hash=sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee \ 4 | # via pytest 5 | attrs==18.2.0 \ 6 | --hash=sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69 \ 7 | --hash=sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb \ 8 | # via pytest 9 | funcsigs==1.0.2 \ 10 | --hash=sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca \ 11 | --hash=sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50 \ 12 | # via mock, pytest 13 | futures==3.2.0 \ 14 | --hash=sha256:9ec02aa7d674acb8618afb127e27fde7fc68994c0437ad759fa094a574adb265 \ 15 | --hash=sha256:ec0a6cb848cc212002b9828c3e34c675e0c9ff6741dc445cab6fdd4e1085d1f1 \ 16 | # via isort 17 | isort==4.3.4 \ 18 | --hash=sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af \ 19 | --hash=sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8 \ 20 | --hash=sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497 21 | lxml==4.2.5 \ 22 | --hash=sha256:02bc220d61f46e9b9d5a53c361ef95e9f5e1d27171cd461dddb17677ae2289a5 \ 23 | --hash=sha256:22f253b542a342755f6cfc047fe4d3a296515cf9b542bc6e261af45a80b8caf6 \ 24 | --hash=sha256:2f31145c7ff665b330919bfa44aacd3a0211a76ca7e7b441039d2a0b0451e415 \ 25 | --hash=sha256:36720698c29e7a9626a0dc802ef8885f8f0239bfd1689628ecd459a061f2807f \ 26 | --hash=sha256:438a1b0203545521f6616132bfe0f4bca86f8a401364008b30e2b26ec408ce85 \ 27 | --hash=sha256:4815892904c336bbaf73dafd54f45f69f4021c22b5bad7332176bbf4fb830568 \ 28 | --hash=sha256:5be031b0f15ad63910d8e5038b489d95a79929513b3634ad4babf77100602588 \ 29 | --hash=sha256:5c93ae37c3c588e829b037fdfbd64a6e40c901d3f93f7beed6d724c44829a3ad \ 30 | --hash=sha256:60842230678674cdac4a1cf0f707ef12d75b9a4fc4a565add4f710b5fcf185d5 \ 31 | --hash=sha256:62939a8bb6758d1bf923aa1c13f0bcfa9bf5b2fc0f5fa917a6e25db5fe0cfa4e \ 32 | --hash=sha256:75830c06a62fe7b8fe3bbb5f269f0b308f19f3949ac81cfd40062f47c1455faf \ 33 | --hash=sha256:81992565b74332c7c1aff6a913a3e906771aa81c9d0c68c68113cffcae45bc53 \ 34 | --hash=sha256:8c892fb0ee52c594d9a7751c7d7356056a9682674b92cc1c4dc968ff0f30c52f \ 35 | --hash=sha256:9d862e3cf4fc1f2837dedce9c42269c8c76d027e49820a548ac89fdcee1e361f \ 36 | --hash=sha256:a623965c086a6e91bb703d4da62dabe59fe88888e82c4117d544e11fd74835d6 \ 37 | --hash=sha256:a7783ab7f6a508b0510490cef9f857b763d796ba7476d9703f89722928d1e113 \ 38 | --hash=sha256:aab09fbe8abfa3b9ce62aaf45aca2d28726b1b9ee44871dbe644050a2fff4940 \ 39 | --hash=sha256:abf181934ac3ef193832fb973fd7f6149b5c531903c2ec0f1220941d73eee601 \ 40 | --hash=sha256:ae07fa0c115733fce1e9da96a3ac3fa24801742ca17e917e0c79d63a01eeb843 \ 41 | --hash=sha256:b9c78242219f674ab645ec571c9a95d70f381319a23911941cd2358a8e0521cf \ 42 | --hash=sha256:bccb267678b870d9782c3b44d0cefe3ba0e329f9af8c946d32bf3778e7a4f271 \ 43 | --hash=sha256:c4df4d27f4c93b2cef74579f00b1d3a31a929c7d8023f870c4b476f03a274db4 \ 44 | --hash=sha256:caf0e50b546bb60dfa99bb18dfa6748458a83131ecdceaf5c071d74907e7e78a \ 45 | --hash=sha256:d3266bd3ac59ac4edcd5fa75165dee80b94a3e5c91049df5f7c057ccf097551c \ 46 | --hash=sha256:db0d213987bcd4e6d41710fb4532b22315b0d8fb439ff901782234456556aed1 \ 47 | --hash=sha256:dbbd5cf7690a40a9f0a9325ab480d0fccf46d16b378eefc08e195d84299bfae1 \ 48 | --hash=sha256:e16e07a0ec3a75b5ee61f2b1003c35696738f937dc8148fbda9fe2147ccb6e61 \ 49 | --hash=sha256:e175a006725c7faadbe69e791877d09936c0ef2cf49d01b60a6c1efcb0e8be6f \ 50 | --hash=sha256:edd9c13a97f6550f9da2236126bb51c092b3b1ce6187f2bd966533ad794bbb5e \ 51 | --hash=sha256:fa39ea60d527fbdd94215b5e5552f1c6a912624521093f1384a491a8ad89ad8b \ 52 | # via pyang 53 | mock==2.0.0 \ 54 | --hash=sha256:5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1 \ 55 | --hash=sha256:b158b6df76edd239b8208d481dc46b6afd45a846b7812ff0ce58971cf5bc8bba \ 56 | # via pytest-mock 57 | more-itertools==4.3.0 \ 58 | --hash=sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092 \ 59 | --hash=sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e \ 60 | --hash=sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d \ 61 | # via pytest 62 | pathlib2==2.3.2 ; python_version < "3.0" \ 63 | --hash=sha256:8eb170f8d0d61825e09a95b38be068299ddeda82f35e96c3301a8a5e7604cb83 \ 64 | --hash=sha256:d1aa2a11ba7b8f7b21ab852b1fb5afb277e1bb99d5dfc663380b5015c0d80c5a 65 | pbr==4.3.0 \ 66 | --hash=sha256:1be135151a0da949af8c5d0ee9013d9eafada71237eb80b3ba8896b4f12ec5dc \ 67 | --hash=sha256:cf36765bf2218654ae824ec8e14257259ba44e43b117fd573c8d07a9895adbdd \ 68 | # via mock 69 | pluggy==0.7.1 \ 70 | --hash=sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1 \ 71 | --hash=sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1 \ 72 | # via pytest 73 | py==1.6.0 \ 74 | --hash=sha256:06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1 \ 75 | --hash=sha256:50402e9d1c9005d759426988a492e0edaadb7f4e68bcddfea586bc7432d009c6 \ 76 | # via pytest 77 | pyang==1.7.5 \ 78 | --hash=sha256:56b236ba77c69d461fce910cd3130be960e76fa0ef6e3f95a7ee0eb908cd9581 \ 79 | --hash=sha256:8c628ac71fdbe51175add094b441f3db8e431d56f4571f750e125a3144df8c6c 80 | pytest-mock==1.10.0 \ 81 | --hash=sha256:53801e621223d34724926a5c98bd90e8e417ce35264365d39d6c896388dcc928 \ 82 | --hash=sha256:d89a8209d722b8307b5e351496830d5cc5e192336003a485443ae9adeb7dd4c0 83 | pytest==3.8.2 \ 84 | --hash=sha256:7e258ee50338f4e46957f9e09a0f10fb1c2d05493fa901d113a8dafd0790de4e \ 85 | --hash=sha256:9332147e9af2dcf46cd7ceb14d5acadb6564744ddff1fe8c17f0ce60ece7d9a2 86 | pyyaml==3.13 \ 87 | --hash=sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b \ 88 | --hash=sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf \ 89 | --hash=sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a \ 90 | --hash=sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3 \ 91 | --hash=sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1 \ 92 | --hash=sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1 \ 93 | --hash=sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613 \ 94 | --hash=sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04 \ 95 | --hash=sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f \ 96 | --hash=sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537 \ 97 | --hash=sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531 98 | scandir==1.9.0 \ 99 | --hash=sha256:04b8adb105f2ed313a7c2ef0f1cf7aff4871aa7a1883fa4d8c44b5551ab052d6 \ 100 | --hash=sha256:1444134990356c81d12f30e4b311379acfbbcd03e0bab591de2696a3b126d58e \ 101 | --hash=sha256:1b5c314e39f596875e5a95dd81af03730b338c277c54a454226978d5ba95dbb6 \ 102 | --hash=sha256:346619f72eb0ddc4cf355ceffd225fa52506c92a2ff05318cfabd02a144e7c4e \ 103 | --hash=sha256:44975e209c4827fc18a3486f257154d34ec6eaec0f90fef0cca1caa482db7064 \ 104 | --hash=sha256:61859fd7e40b8c71e609c202db5b0c1dbec0d5c7f1449dec2245575bdc866792 \ 105 | --hash=sha256:a5e232a0bf188362fa00123cc0bb842d363a292de7126126df5527b6a369586a \ 106 | --hash=sha256:c14701409f311e7a9b7ec8e337f0815baf7ac95776cc78b419a1e6d49889a383 \ 107 | --hash=sha256:c7708f29d843fc2764310732e41f0ce27feadde453261859ec0fca7865dfc41b \ 108 | --hash=sha256:c9009c527929f6e25604aec39b0a43c3f831d2947d89d6caaab22f057b7055c8 \ 109 | --hash=sha256:f5c71e29b4e2af7ccdc03a020c626ede51da471173b4a6ad1e904f2b2e04b4bd \ 110 | # via pathlib2 111 | six==1.11.0 \ 112 | --hash=sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9 \ 113 | --hash=sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb \ 114 | # via mock, more-itertools, pathlib2, pytest 115 | 116 | # The following packages are considered to be unsafe in a requirements file: 117 | setuptools==40.4.3 \ 118 | --hash=sha256:acbc5740dd63f243f46c2b4b8e2c7fd92259c2ddb55a4115b16418a2ed371b15 \ 119 | --hash=sha256:ce4137d58b444bac11a31d4e0c1805c69d89e8ed4e91fde1999674ecc2f6f9ff \ 120 | # via pytest 121 | -------------------------------------------------------------------------------- /thirdparty/pip/2/requirements-osx.txt: -------------------------------------------------------------------------------- 1 | atomicwrites==1.2.1 \ 2 | --hash=sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0 \ 3 | --hash=sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee \ 4 | # via pytest 5 | attrs==18.2.0 \ 6 | --hash=sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69 \ 7 | --hash=sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb \ 8 | # via pytest 9 | funcsigs==1.0.2 \ 10 | --hash=sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca \ 11 | --hash=sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50 \ 12 | # via mock, pytest 13 | futures==3.2.0 \ 14 | --hash=sha256:9ec02aa7d674acb8618afb127e27fde7fc68994c0437ad759fa094a574adb265 \ 15 | --hash=sha256:ec0a6cb848cc212002b9828c3e34c675e0c9ff6741dc445cab6fdd4e1085d1f1 \ 16 | # via isort 17 | isort==4.3.4 \ 18 | --hash=sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af \ 19 | --hash=sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8 \ 20 | --hash=sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497 21 | lxml==4.2.5 \ 22 | --hash=sha256:02bc220d61f46e9b9d5a53c361ef95e9f5e1d27171cd461dddb17677ae2289a5 \ 23 | --hash=sha256:22f253b542a342755f6cfc047fe4d3a296515cf9b542bc6e261af45a80b8caf6 \ 24 | --hash=sha256:2f31145c7ff665b330919bfa44aacd3a0211a76ca7e7b441039d2a0b0451e415 \ 25 | --hash=sha256:36720698c29e7a9626a0dc802ef8885f8f0239bfd1689628ecd459a061f2807f \ 26 | --hash=sha256:438a1b0203545521f6616132bfe0f4bca86f8a401364008b30e2b26ec408ce85 \ 27 | --hash=sha256:4815892904c336bbaf73dafd54f45f69f4021c22b5bad7332176bbf4fb830568 \ 28 | --hash=sha256:5be031b0f15ad63910d8e5038b489d95a79929513b3634ad4babf77100602588 \ 29 | --hash=sha256:5c93ae37c3c588e829b037fdfbd64a6e40c901d3f93f7beed6d724c44829a3ad \ 30 | --hash=sha256:60842230678674cdac4a1cf0f707ef12d75b9a4fc4a565add4f710b5fcf185d5 \ 31 | --hash=sha256:62939a8bb6758d1bf923aa1c13f0bcfa9bf5b2fc0f5fa917a6e25db5fe0cfa4e \ 32 | --hash=sha256:75830c06a62fe7b8fe3bbb5f269f0b308f19f3949ac81cfd40062f47c1455faf \ 33 | --hash=sha256:81992565b74332c7c1aff6a913a3e906771aa81c9d0c68c68113cffcae45bc53 \ 34 | --hash=sha256:8c892fb0ee52c594d9a7751c7d7356056a9682674b92cc1c4dc968ff0f30c52f \ 35 | --hash=sha256:9d862e3cf4fc1f2837dedce9c42269c8c76d027e49820a548ac89fdcee1e361f \ 36 | --hash=sha256:a623965c086a6e91bb703d4da62dabe59fe88888e82c4117d544e11fd74835d6 \ 37 | --hash=sha256:a7783ab7f6a508b0510490cef9f857b763d796ba7476d9703f89722928d1e113 \ 38 | --hash=sha256:aab09fbe8abfa3b9ce62aaf45aca2d28726b1b9ee44871dbe644050a2fff4940 \ 39 | --hash=sha256:abf181934ac3ef193832fb973fd7f6149b5c531903c2ec0f1220941d73eee601 \ 40 | --hash=sha256:ae07fa0c115733fce1e9da96a3ac3fa24801742ca17e917e0c79d63a01eeb843 \ 41 | --hash=sha256:b9c78242219f674ab645ec571c9a95d70f381319a23911941cd2358a8e0521cf \ 42 | --hash=sha256:bccb267678b870d9782c3b44d0cefe3ba0e329f9af8c946d32bf3778e7a4f271 \ 43 | --hash=sha256:c4df4d27f4c93b2cef74579f00b1d3a31a929c7d8023f870c4b476f03a274db4 \ 44 | --hash=sha256:caf0e50b546bb60dfa99bb18dfa6748458a83131ecdceaf5c071d74907e7e78a \ 45 | --hash=sha256:d3266bd3ac59ac4edcd5fa75165dee80b94a3e5c91049df5f7c057ccf097551c \ 46 | --hash=sha256:db0d213987bcd4e6d41710fb4532b22315b0d8fb439ff901782234456556aed1 \ 47 | --hash=sha256:dbbd5cf7690a40a9f0a9325ab480d0fccf46d16b378eefc08e195d84299bfae1 \ 48 | --hash=sha256:e16e07a0ec3a75b5ee61f2b1003c35696738f937dc8148fbda9fe2147ccb6e61 \ 49 | --hash=sha256:e175a006725c7faadbe69e791877d09936c0ef2cf49d01b60a6c1efcb0e8be6f \ 50 | --hash=sha256:edd9c13a97f6550f9da2236126bb51c092b3b1ce6187f2bd966533ad794bbb5e \ 51 | --hash=sha256:fa39ea60d527fbdd94215b5e5552f1c6a912624521093f1384a491a8ad89ad8b \ 52 | # via pyang 53 | mock==2.0.0 \ 54 | --hash=sha256:5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1 \ 55 | --hash=sha256:b158b6df76edd239b8208d481dc46b6afd45a846b7812ff0ce58971cf5bc8bba \ 56 | # via pytest-mock 57 | more-itertools==4.3.0 \ 58 | --hash=sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092 \ 59 | --hash=sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e \ 60 | --hash=sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d \ 61 | # via pytest 62 | pathlib2==2.3.2 ; python_version < "3.0" \ 63 | --hash=sha256:8eb170f8d0d61825e09a95b38be068299ddeda82f35e96c3301a8a5e7604cb83 \ 64 | --hash=sha256:d1aa2a11ba7b8f7b21ab852b1fb5afb277e1bb99d5dfc663380b5015c0d80c5a 65 | pbr==4.3.0 \ 66 | --hash=sha256:1be135151a0da949af8c5d0ee9013d9eafada71237eb80b3ba8896b4f12ec5dc \ 67 | --hash=sha256:cf36765bf2218654ae824ec8e14257259ba44e43b117fd573c8d07a9895adbdd \ 68 | # via mock 69 | pluggy==0.7.1 \ 70 | --hash=sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1 \ 71 | --hash=sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1 \ 72 | # via pytest 73 | py==1.6.0 \ 74 | --hash=sha256:06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1 \ 75 | --hash=sha256:50402e9d1c9005d759426988a492e0edaadb7f4e68bcddfea586bc7432d009c6 \ 76 | # via pytest 77 | pyang==1.7.5 \ 78 | --hash=sha256:56b236ba77c69d461fce910cd3130be960e76fa0ef6e3f95a7ee0eb908cd9581 \ 79 | --hash=sha256:8c628ac71fdbe51175add094b441f3db8e431d56f4571f750e125a3144df8c6c 80 | pytest-mock==1.10.0 \ 81 | --hash=sha256:53801e621223d34724926a5c98bd90e8e417ce35264365d39d6c896388dcc928 \ 82 | --hash=sha256:d89a8209d722b8307b5e351496830d5cc5e192336003a485443ae9adeb7dd4c0 83 | pytest==3.8.2 \ 84 | --hash=sha256:7e258ee50338f4e46957f9e09a0f10fb1c2d05493fa901d113a8dafd0790de4e \ 85 | --hash=sha256:9332147e9af2dcf46cd7ceb14d5acadb6564744ddff1fe8c17f0ce60ece7d9a2 86 | pyyaml==3.13 \ 87 | --hash=sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b \ 88 | --hash=sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf \ 89 | --hash=sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a \ 90 | --hash=sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3 \ 91 | --hash=sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1 \ 92 | --hash=sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1 \ 93 | --hash=sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613 \ 94 | --hash=sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04 \ 95 | --hash=sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f \ 96 | --hash=sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537 \ 97 | --hash=sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531 98 | scandir==1.9.0 \ 99 | --hash=sha256:04b8adb105f2ed313a7c2ef0f1cf7aff4871aa7a1883fa4d8c44b5551ab052d6 \ 100 | --hash=sha256:1444134990356c81d12f30e4b311379acfbbcd03e0bab591de2696a3b126d58e \ 101 | --hash=sha256:1b5c314e39f596875e5a95dd81af03730b338c277c54a454226978d5ba95dbb6 \ 102 | --hash=sha256:346619f72eb0ddc4cf355ceffd225fa52506c92a2ff05318cfabd02a144e7c4e \ 103 | --hash=sha256:44975e209c4827fc18a3486f257154d34ec6eaec0f90fef0cca1caa482db7064 \ 104 | --hash=sha256:61859fd7e40b8c71e609c202db5b0c1dbec0d5c7f1449dec2245575bdc866792 \ 105 | --hash=sha256:a5e232a0bf188362fa00123cc0bb842d363a292de7126126df5527b6a369586a \ 106 | --hash=sha256:c14701409f311e7a9b7ec8e337f0815baf7ac95776cc78b419a1e6d49889a383 \ 107 | --hash=sha256:c7708f29d843fc2764310732e41f0ce27feadde453261859ec0fca7865dfc41b \ 108 | --hash=sha256:c9009c527929f6e25604aec39b0a43c3f831d2947d89d6caaab22f057b7055c8 \ 109 | --hash=sha256:f5c71e29b4e2af7ccdc03a020c626ede51da471173b4a6ad1e904f2b2e04b4bd \ 110 | # via pathlib2 111 | six==1.11.0 \ 112 | --hash=sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9 \ 113 | --hash=sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb \ 114 | # via mock, more-itertools, pathlib2, pytest 115 | 116 | # The following packages are considered to be unsafe in a requirements file: 117 | setuptools==40.4.3 \ 118 | --hash=sha256:acbc5740dd63f243f46c2b4b8e2c7fd92259c2ddb55a4115b16418a2ed371b15 \ 119 | --hash=sha256:ce4137d58b444bac11a31d4e0c1805c69d89e8ed4e91fde1999674ecc2f6f9ff \ 120 | # via pytest 121 | -------------------------------------------------------------------------------- /thirdparty/pip/3/BUILD: -------------------------------------------------------------------------------- 1 | load("//rules:compile.bzl", "compile_pip_requirements") 2 | load("//:python.bzl", "PYTHON3") 3 | 4 | compile_pip_requirements( 5 | name = "compile", 6 | python_interpreter = PYTHON3, 7 | requirements_in = "//thirdparty/pip:requirements.in", 8 | requirements_txt = select({ 9 | "//:linux": "requirements-linux.txt", 10 | "//:osx": "requirements-osx.txt", 11 | }), 12 | ) 13 | 14 | exports_files(glob(["requirements*"])) 15 | -------------------------------------------------------------------------------- /thirdparty/pip/3/requirements-linux.txt: -------------------------------------------------------------------------------- 1 | atomicwrites==1.2.1 \ 2 | --hash=sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0 \ 3 | --hash=sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee \ 4 | # via pytest 5 | attrs==18.2.0 \ 6 | --hash=sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69 \ 7 | --hash=sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb \ 8 | # via pytest 9 | isort==4.3.4 \ 10 | --hash=sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af \ 11 | --hash=sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8 \ 12 | --hash=sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497 13 | lxml==4.2.5 \ 14 | --hash=sha256:02bc220d61f46e9b9d5a53c361ef95e9f5e1d27171cd461dddb17677ae2289a5 \ 15 | --hash=sha256:22f253b542a342755f6cfc047fe4d3a296515cf9b542bc6e261af45a80b8caf6 \ 16 | --hash=sha256:2f31145c7ff665b330919bfa44aacd3a0211a76ca7e7b441039d2a0b0451e415 \ 17 | --hash=sha256:36720698c29e7a9626a0dc802ef8885f8f0239bfd1689628ecd459a061f2807f \ 18 | --hash=sha256:438a1b0203545521f6616132bfe0f4bca86f8a401364008b30e2b26ec408ce85 \ 19 | --hash=sha256:4815892904c336bbaf73dafd54f45f69f4021c22b5bad7332176bbf4fb830568 \ 20 | --hash=sha256:5be031b0f15ad63910d8e5038b489d95a79929513b3634ad4babf77100602588 \ 21 | --hash=sha256:5c93ae37c3c588e829b037fdfbd64a6e40c901d3f93f7beed6d724c44829a3ad \ 22 | --hash=sha256:60842230678674cdac4a1cf0f707ef12d75b9a4fc4a565add4f710b5fcf185d5 \ 23 | --hash=sha256:62939a8bb6758d1bf923aa1c13f0bcfa9bf5b2fc0f5fa917a6e25db5fe0cfa4e \ 24 | --hash=sha256:75830c06a62fe7b8fe3bbb5f269f0b308f19f3949ac81cfd40062f47c1455faf \ 25 | --hash=sha256:81992565b74332c7c1aff6a913a3e906771aa81c9d0c68c68113cffcae45bc53 \ 26 | --hash=sha256:8c892fb0ee52c594d9a7751c7d7356056a9682674b92cc1c4dc968ff0f30c52f \ 27 | --hash=sha256:9d862e3cf4fc1f2837dedce9c42269c8c76d027e49820a548ac89fdcee1e361f \ 28 | --hash=sha256:a623965c086a6e91bb703d4da62dabe59fe88888e82c4117d544e11fd74835d6 \ 29 | --hash=sha256:a7783ab7f6a508b0510490cef9f857b763d796ba7476d9703f89722928d1e113 \ 30 | --hash=sha256:aab09fbe8abfa3b9ce62aaf45aca2d28726b1b9ee44871dbe644050a2fff4940 \ 31 | --hash=sha256:abf181934ac3ef193832fb973fd7f6149b5c531903c2ec0f1220941d73eee601 \ 32 | --hash=sha256:ae07fa0c115733fce1e9da96a3ac3fa24801742ca17e917e0c79d63a01eeb843 \ 33 | --hash=sha256:b9c78242219f674ab645ec571c9a95d70f381319a23911941cd2358a8e0521cf \ 34 | --hash=sha256:bccb267678b870d9782c3b44d0cefe3ba0e329f9af8c946d32bf3778e7a4f271 \ 35 | --hash=sha256:c4df4d27f4c93b2cef74579f00b1d3a31a929c7d8023f870c4b476f03a274db4 \ 36 | --hash=sha256:caf0e50b546bb60dfa99bb18dfa6748458a83131ecdceaf5c071d74907e7e78a \ 37 | --hash=sha256:d3266bd3ac59ac4edcd5fa75165dee80b94a3e5c91049df5f7c057ccf097551c \ 38 | --hash=sha256:db0d213987bcd4e6d41710fb4532b22315b0d8fb439ff901782234456556aed1 \ 39 | --hash=sha256:dbbd5cf7690a40a9f0a9325ab480d0fccf46d16b378eefc08e195d84299bfae1 \ 40 | --hash=sha256:e16e07a0ec3a75b5ee61f2b1003c35696738f937dc8148fbda9fe2147ccb6e61 \ 41 | --hash=sha256:e175a006725c7faadbe69e791877d09936c0ef2cf49d01b60a6c1efcb0e8be6f \ 42 | --hash=sha256:edd9c13a97f6550f9da2236126bb51c092b3b1ce6187f2bd966533ad794bbb5e \ 43 | --hash=sha256:fa39ea60d527fbdd94215b5e5552f1c6a912624521093f1384a491a8ad89ad8b \ 44 | # via pyang 45 | more-itertools==4.3.0 \ 46 | --hash=sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092 \ 47 | --hash=sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e \ 48 | --hash=sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d \ 49 | # via pytest 50 | pluggy==0.7.1 \ 51 | --hash=sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1 \ 52 | --hash=sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1 \ 53 | # via pytest 54 | py==1.6.0 \ 55 | --hash=sha256:06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1 \ 56 | --hash=sha256:50402e9d1c9005d759426988a492e0edaadb7f4e68bcddfea586bc7432d009c6 \ 57 | # via pytest 58 | pyang==1.7.5 ; python_version >= "3.0" \ 59 | --hash=sha256:56b236ba77c69d461fce910cd3130be960e76fa0ef6e3f95a7ee0eb908cd9581 \ 60 | --hash=sha256:8c628ac71fdbe51175add094b441f3db8e431d56f4571f750e125a3144df8c6c 61 | pytest-mock==1.10.0 \ 62 | --hash=sha256:53801e621223d34724926a5c98bd90e8e417ce35264365d39d6c896388dcc928 \ 63 | --hash=sha256:d89a8209d722b8307b5e351496830d5cc5e192336003a485443ae9adeb7dd4c0 64 | pytest==3.8.2 \ 65 | --hash=sha256:7e258ee50338f4e46957f9e09a0f10fb1c2d05493fa901d113a8dafd0790de4e \ 66 | --hash=sha256:9332147e9af2dcf46cd7ceb14d5acadb6564744ddff1fe8c17f0ce60ece7d9a2 67 | pyyaml==3.13 \ 68 | --hash=sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b \ 69 | --hash=sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf \ 70 | --hash=sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a \ 71 | --hash=sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3 \ 72 | --hash=sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1 \ 73 | --hash=sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1 \ 74 | --hash=sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613 \ 75 | --hash=sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04 \ 76 | --hash=sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f \ 77 | --hash=sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537 \ 78 | --hash=sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531 79 | six==1.11.0 \ 80 | --hash=sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9 \ 81 | --hash=sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb \ 82 | # via more-itertools, pytest 83 | 84 | # The following packages are considered to be unsafe in a requirements file: 85 | setuptools==40.4.3 \ 86 | --hash=sha256:acbc5740dd63f243f46c2b4b8e2c7fd92259c2ddb55a4115b16418a2ed371b15 \ 87 | --hash=sha256:ce4137d58b444bac11a31d4e0c1805c69d89e8ed4e91fde1999674ecc2f6f9ff \ 88 | # via pytest 89 | -------------------------------------------------------------------------------- /thirdparty/pip/3/requirements-osx.txt: -------------------------------------------------------------------------------- 1 | atomicwrites==1.2.1 \ 2 | --hash=sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0 \ 3 | --hash=sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee \ 4 | # via pytest 5 | attrs==18.2.0 \ 6 | --hash=sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69 \ 7 | --hash=sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb \ 8 | # via pytest 9 | isort==4.3.4 \ 10 | --hash=sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af \ 11 | --hash=sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8 \ 12 | --hash=sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497 13 | lxml==4.2.5 \ 14 | --hash=sha256:02bc220d61f46e9b9d5a53c361ef95e9f5e1d27171cd461dddb17677ae2289a5 \ 15 | --hash=sha256:22f253b542a342755f6cfc047fe4d3a296515cf9b542bc6e261af45a80b8caf6 \ 16 | --hash=sha256:2f31145c7ff665b330919bfa44aacd3a0211a76ca7e7b441039d2a0b0451e415 \ 17 | --hash=sha256:36720698c29e7a9626a0dc802ef8885f8f0239bfd1689628ecd459a061f2807f \ 18 | --hash=sha256:438a1b0203545521f6616132bfe0f4bca86f8a401364008b30e2b26ec408ce85 \ 19 | --hash=sha256:4815892904c336bbaf73dafd54f45f69f4021c22b5bad7332176bbf4fb830568 \ 20 | --hash=sha256:5be031b0f15ad63910d8e5038b489d95a79929513b3634ad4babf77100602588 \ 21 | --hash=sha256:5c93ae37c3c588e829b037fdfbd64a6e40c901d3f93f7beed6d724c44829a3ad \ 22 | --hash=sha256:60842230678674cdac4a1cf0f707ef12d75b9a4fc4a565add4f710b5fcf185d5 \ 23 | --hash=sha256:62939a8bb6758d1bf923aa1c13f0bcfa9bf5b2fc0f5fa917a6e25db5fe0cfa4e \ 24 | --hash=sha256:75830c06a62fe7b8fe3bbb5f269f0b308f19f3949ac81cfd40062f47c1455faf \ 25 | --hash=sha256:81992565b74332c7c1aff6a913a3e906771aa81c9d0c68c68113cffcae45bc53 \ 26 | --hash=sha256:8c892fb0ee52c594d9a7751c7d7356056a9682674b92cc1c4dc968ff0f30c52f \ 27 | --hash=sha256:9d862e3cf4fc1f2837dedce9c42269c8c76d027e49820a548ac89fdcee1e361f \ 28 | --hash=sha256:a623965c086a6e91bb703d4da62dabe59fe88888e82c4117d544e11fd74835d6 \ 29 | --hash=sha256:a7783ab7f6a508b0510490cef9f857b763d796ba7476d9703f89722928d1e113 \ 30 | --hash=sha256:aab09fbe8abfa3b9ce62aaf45aca2d28726b1b9ee44871dbe644050a2fff4940 \ 31 | --hash=sha256:abf181934ac3ef193832fb973fd7f6149b5c531903c2ec0f1220941d73eee601 \ 32 | --hash=sha256:ae07fa0c115733fce1e9da96a3ac3fa24801742ca17e917e0c79d63a01eeb843 \ 33 | --hash=sha256:b9c78242219f674ab645ec571c9a95d70f381319a23911941cd2358a8e0521cf \ 34 | --hash=sha256:bccb267678b870d9782c3b44d0cefe3ba0e329f9af8c946d32bf3778e7a4f271 \ 35 | --hash=sha256:c4df4d27f4c93b2cef74579f00b1d3a31a929c7d8023f870c4b476f03a274db4 \ 36 | --hash=sha256:caf0e50b546bb60dfa99bb18dfa6748458a83131ecdceaf5c071d74907e7e78a \ 37 | --hash=sha256:d3266bd3ac59ac4edcd5fa75165dee80b94a3e5c91049df5f7c057ccf097551c \ 38 | --hash=sha256:db0d213987bcd4e6d41710fb4532b22315b0d8fb439ff901782234456556aed1 \ 39 | --hash=sha256:dbbd5cf7690a40a9f0a9325ab480d0fccf46d16b378eefc08e195d84299bfae1 \ 40 | --hash=sha256:e16e07a0ec3a75b5ee61f2b1003c35696738f937dc8148fbda9fe2147ccb6e61 \ 41 | --hash=sha256:e175a006725c7faadbe69e791877d09936c0ef2cf49d01b60a6c1efcb0e8be6f \ 42 | --hash=sha256:edd9c13a97f6550f9da2236126bb51c092b3b1ce6187f2bd966533ad794bbb5e \ 43 | --hash=sha256:fa39ea60d527fbdd94215b5e5552f1c6a912624521093f1384a491a8ad89ad8b \ 44 | # via pyang 45 | more-itertools==4.3.0 \ 46 | --hash=sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092 \ 47 | --hash=sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e \ 48 | --hash=sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d \ 49 | # via pytest 50 | pluggy==0.7.1 \ 51 | --hash=sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1 \ 52 | --hash=sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1 \ 53 | # via pytest 54 | py==1.6.0 \ 55 | --hash=sha256:06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1 \ 56 | --hash=sha256:50402e9d1c9005d759426988a492e0edaadb7f4e68bcddfea586bc7432d009c6 \ 57 | # via pytest 58 | pyang==1.7.5 \ 59 | --hash=sha256:56b236ba77c69d461fce910cd3130be960e76fa0ef6e3f95a7ee0eb908cd9581 \ 60 | --hash=sha256:8c628ac71fdbe51175add094b441f3db8e431d56f4571f750e125a3144df8c6c 61 | pytest-mock==1.10.0 \ 62 | --hash=sha256:53801e621223d34724926a5c98bd90e8e417ce35264365d39d6c896388dcc928 \ 63 | --hash=sha256:d89a8209d722b8307b5e351496830d5cc5e192336003a485443ae9adeb7dd4c0 64 | pytest==3.8.2 \ 65 | --hash=sha256:7e258ee50338f4e46957f9e09a0f10fb1c2d05493fa901d113a8dafd0790de4e \ 66 | --hash=sha256:9332147e9af2dcf46cd7ceb14d5acadb6564744ddff1fe8c17f0ce60ece7d9a2 67 | pyyaml==3.13 \ 68 | --hash=sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b \ 69 | --hash=sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf \ 70 | --hash=sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a \ 71 | --hash=sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3 \ 72 | --hash=sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1 \ 73 | --hash=sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1 \ 74 | --hash=sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613 \ 75 | --hash=sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04 \ 76 | --hash=sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f \ 77 | --hash=sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537 \ 78 | --hash=sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531 79 | six==1.11.0 \ 80 | --hash=sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9 \ 81 | --hash=sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb \ 82 | # via more-itertools, pytest 83 | 84 | # The following packages are considered to be unsafe in a requirements file: 85 | setuptools==40.4.3 \ 86 | --hash=sha256:acbc5740dd63f243f46c2b4b8e2c7fd92259c2ddb55a4115b16418a2ed371b15 \ 87 | --hash=sha256:ce4137d58b444bac11a31d4e0c1805c69d89e8ed4e91fde1999674ecc2f6f9ff \ 88 | # via pytest 89 | -------------------------------------------------------------------------------- /thirdparty/pip/BUILD: -------------------------------------------------------------------------------- 1 | exports_files(["requirements.in"]) 2 | -------------------------------------------------------------------------------- /thirdparty/pip/requirements.in: -------------------------------------------------------------------------------- 1 | isort 2 | pathlib2 ; python_version < "3.0" 3 | pyang 4 | pytest 5 | pytest-mock 6 | pyyaml 7 | -------------------------------------------------------------------------------- /tools/BUILD: -------------------------------------------------------------------------------- 1 | exports_files([ 2 | "compile_pip_requirements.par", 3 | "create_pip_repository.par", 4 | ]) 5 | -------------------------------------------------------------------------------- /tools/compile_pip_requirements.par: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apt-itude/rules_pip/aafdefd2bf1a9f6995669c1d744da493de9a7b75/tools/compile_pip_requirements.par -------------------------------------------------------------------------------- /tools/create_pip_repository.par: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apt-itude/rules_pip/aafdefd2bf1a9f6995669c1d744da493de9a7b75/tools/create_pip_repository.par -------------------------------------------------------------------------------- /tools/pytest/BUILD: -------------------------------------------------------------------------------- 1 | exports_files(["main_template.py"]) 2 | -------------------------------------------------------------------------------- /tools/pytest/main_template.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env @@INTERPRETER@@ 2 | 3 | import sys 4 | 5 | import pytest 6 | 7 | 8 | def main(): 9 | args = sys.argv[1:] 10 | args.append("@@TEST_PATH@@") 11 | 12 | sys.exit(pytest.main(args)) 13 | 14 | 15 | if __name__ == '__main__': 16 | main() 17 | -------------------------------------------------------------------------------- /tools/pytest/rules.bzl: -------------------------------------------------------------------------------- 1 | load("//:python.bzl", "PYTHON2", "PYTHON3") 2 | 3 | def _pytest_main_impl(ctx): 4 | substitutions = { 5 | "@@INTERPRETER@@": ctx.attr.interpreter, 6 | "@@TEST_PATH@@": ctx.file.src.short_path, 7 | } 8 | 9 | ctx.actions.expand_template( 10 | template = ctx.file._template, 11 | output = ctx.outputs.main, 12 | substitutions = substitutions, 13 | ) 14 | 15 | _pytest_main = rule( 16 | implementation = _pytest_main_impl, 17 | attrs = { 18 | "src": attr.label( 19 | mandatory = True, 20 | allow_single_file = [".py"], 21 | ), 22 | "interpreter": attr.string(mandatory = True), 23 | "_template": attr.label( 24 | default = "//tools/pytest:main_template.py", 25 | allow_single_file = True, 26 | ), 27 | }, 28 | outputs = { 29 | "main": "%{name}.py", 30 | }, 31 | ) 32 | 33 | def pytest_test(name, src, python_version = 3, **kwargs): 34 | if python_version == 2: 35 | interpreter = PYTHON2 36 | pytest_dep = "@pip2//pytest" 37 | elif python_version == 3: 38 | interpreter = PYTHON3 39 | pytest_dep = "@pip3//pytest" 40 | else: 41 | fail("Python version must be 2 or 3") 42 | 43 | main_name = "%s_main" % name 44 | main_output = ":%s.py" % main_name 45 | 46 | _pytest_main( 47 | name = main_name, 48 | src = src, 49 | interpreter = interpreter, 50 | ) 51 | 52 | deps = kwargs.pop("deps", []) + [pytest_dep] 53 | 54 | native.py_test( 55 | name = name, 56 | srcs = [main_output, src], 57 | main = main_output, 58 | deps = deps, 59 | **kwargs 60 | ) 61 | -------------------------------------------------------------------------------- /tools/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | bazel build //src/bin:compile_pip_requirements.par 4 | bazel build //src/bin:create_pip_repository.par 5 | 6 | WORKSPACE=$(bazel info workspace) 7 | cp $WORKSPACE/bazel-bin/src/bin/compile_pip_requirements.par $WORKSPACE/tools/compile_pip_requirements.par 8 | cp $WORKSPACE/bazel-bin/src/bin/create_pip_repository.par $WORKSPACE/tools/create_pip_repository.par 9 | --------------------------------------------------------------------------------