diff --git a/.flake8 b/.flake8 index 160c1b8..cf5d05d 100644 --- a/.flake8 +++ b/.flake8 @@ -1,5 +1,9 @@ [flake8] +# E203 -> whitespace before ':' (conflicts with Black) +# E231 -> Bad trailing comma (conflicts with Black) +# E501 -> line too long (conflicts with Black) + extend-ignore: - E203, # whitespace before ':' (conflicts with Black) - E231, # Bad trailing comma (conflicts with Black) - E501, # line too long (conflicts with Black) + E203, + E231, + E501, diff --git a/.github/workflows/pants.yaml b/.github/workflows/pants.yaml index 6c8efdd..ceb31af 100644 --- a/.github/workflows/pants.yaml +++ b/.github/workflows/pants.yaml @@ -1,31 +1,69 @@ +# Copyright 2020 Pants project contributors. +# Licensed under the Apache License, Version 2.0 (see LICENSE). + +# See https://www.pantsbuild.org/stable/docs/using-pants/using-pants-in-ci for tips on how to set up your CI with Pants. + name: Pants -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] +on: [push, pull_request] jobs: + org-check: + name: Check GitHub Organization + if: ${{ github.repository_owner == 'pantsbuild' }} + runs-on: ubuntu-24.04 + steps: + - name: Noop + run: "true" build: - env: - PANTS_CONFIG_FILES: pants.ci.toml - runs-on: ubuntu-latest + name: Perform CI Checks + needs: org-check + runs-on: ubuntu-24.04 strategy: matrix: - python-version: [3.7] + python-version: [3.12] steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - name: bootstrap + - uses: pantsbuild/actions/init-pants@v8 + # This action bootstraps pants and manages 2-3 GHA caches. + # See: github.com/pantsbuild/actions/tree/main/init-pants/ + with: + # v0 makes it easy to bust the cache if needed + # just increase the integer to start with a fresh cache + gha-cache-key: v0 + # The Python backend uses named_caches for Pip/PEX state, + # so it is appropriate to invalidate on lockfile changes. + named-caches-hash: ${{ hashFiles('python-default.lock') }} + # If you're not using a fine-grained remote caching service (see https://www.pantsbuild.org/docs/remote-caching), + # then you may also want to preserve the local Pants cache (lmdb_store). However this must invalidate for + # changes to any file that can affect the build, so may not be practical in larger repos. + # A remote cache service integrates with Pants's fine-grained invalidation and avoids these problems. + cache-lmdb-store: 'true' # defaults to 'false' + # Note that named_caches and lmdb_store falls back to partial restore keys which + # may give a useful partial result that will save time over completely clean state, + # but will cause the cache entry to grow without bound over time. + # See https://www.pantsbuild.org/stable/docs/using-pants/using-pants-in-ci for tips on how to periodically clean it up. + # Alternatively you change gha-cache-key to ignore old caches. + - name: Check BUILD files run: | - ./pants --version - - name: Lint - run: | - ./pants lint :: + pants tailor --check update-build-files --check :: + - name: Lint and typecheck + run: | + pants lint check :: - name: Test run: | - ./pants test :: + pants test :: + - name: Package / Run + run: | + # We also smoke test that our release process will work by running `package`. + pants package :: + pants run helloworld/:pex_binary + - name: Upload pants log + uses: actions/upload-artifact@v4 + with: + name: pants-log + path: .pants.d/workdir/pants.log + if: always() # We want the log even on failures. diff --git a/.gitignore b/.gitignore index f7a6370..08c35f4 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,8 @@ # Python files __pycache__/ *.pyc -/.venv/ +.venv/ # Editors .idea/ +*.iml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8c62824..0000000 --- a/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - -# See https://pants.readme.io/docs/using-pants-in-ci for tips on how to set up your CI with Pants. - -env: - global: - - PANTS_CONFIG_FILES=pants.ci.toml - -os: linux -dist: bionic -language: python -python: 3.7 - -cache: - directories: - - $HOME/.cache/pants/setup - - $HOME/.cache/pants/lmdb_store - -install: - - ./pants --version # This will bootstrap Pants - -script: - - ./pants --changed-since=origin/master lint - - ./pants --changed-since=origin/master --changed-include-dependees=transitive test diff --git a/BUILD b/BUILD index 5f81ec9..fca77e4 100644 --- a/BUILD +++ b/BUILD @@ -1,16 +1,7 @@ # Copyright 2020 Pants project contributors. # Licensed under the Apache License, Version 2.0 (see LICENSE). - -# A macro that turns every entry in this directory's requirements.txt into a target -# with the name of the corresponding dist. -# -# For example, `translate>=3.2.1` expands to: -# python_requirement_library( -# name='translate', -# requirements=[ -# python_requirement('translate>=3.2.1') -# ] -# ) - -python_requirements() +# A macro that turns every entry in this directory's requirements.txt into a +# `python_requirement_library` target. Refer to +# https://www.pantsbuild.org/docs/python-third-party-dependencies. +python_requirements(name="reqs") diff --git a/README.md b/README.md index 44cd996..3cc3c1d 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,24 @@ # example-python -An example repository to demonstrate Python support in Pants v2. +An example repository to demonstrate Python support in Pants. -See https://pants.readme.io/ for much more detailed documentation. +See [pantsbuild.org](https://www.pantsbuild.org/docs) for much more detailed documentation. + +This is only one possible way of laying out your project with Pants. See +[pantsbuild.org/docs/source-roots#examples](https://www.pantsbuild.org/docs/source-roots#examples) for some other +example layouts. # Running Pants -You run Pants goals using the `./pants` wrapper script, which will bootstrap the -configured version of Pants if necessary. +You run Pants goals using the `pants` launcher binary, which will bootstrap the +version of Pants configured for this repo if necessary. + +See [here](https://www.pantsbuild.org/docs/installation) for how to install the `pants` binary. -Use `./pants --version` to see the version of Pants configured for the repo (which you can also find +> :question: Running with Apple Silicon and/or macOS? You will want to make changes to the `search_path` and +`interpreter_constraints` values in `pants.toml` before running `pants` - there is guidance in `pants.toml` +for those settings. + +Use `pants --version` to see the version of Pants configured for the repo (which you can also find in `pants.toml`). # Goals @@ -16,16 +26,16 @@ in `pants.toml`). Pants commands are called _goals_. You can get a list of goals with ``` -./pants goals +pants help goals ``` # Targets -Targets are sets of source files with some attached metadata. Targets are provided in `BUILD` files. -Targets have types, such as `python_library`, `resources`, `python_binary`. Examples of metadata include -dependencies on other targets, Python version compatibility, entry points for binaries, and so on. +Targets are a way of setting metadata for some part of your code, such as timeouts for tests and +entry points for binaries. Targets have types like `python_source`, `resources`, and +`pex_binary`. They are defined in `BUILD` files. -Pants goals can be invoked on targets or directly on source files/directories (which is often more intuitive and convenient). +Pants goals can be invoked on targets or directly on source files (which is often more intuitive and convenient). In the latter case, Pants locates target metadata for the source files as needed. ## File specifications @@ -33,46 +43,52 @@ In the latter case, Pants locates target metadata for the source files as needed Invoking goals on files is straightforward, e.g., ``` -./pants test helloworld/util/lang_test.py +pants test helloworld/greet/greeting_test.py ``` You can use globs: ``` -./pants lint helloworld/util/*.py +pants lint helloworld/greet/*.py ``` But note that these will be expanded by your shell, so this is equivalent to having used ``` -./pants lint helloworld/util/lang.py helloworld/util/lang_test.py helloworld/util/resources.py helloworld/util/resources_test.py +pants lint helloworld/greet/__init__.py helloworld/greet/greeting.py helloworld/greet/greeting_test.py ``` If you want Pants itself to expand the globs (which is sometimes necessary), you must quote them in the shell: ``` -./pants lint 'helloworld/util/*.py' +pants lint 'helloworld/greet/*.py' ``` -## Target specifications +You can run on all changed files: -Targets are referenced on the command line using their address, of the form `path/to/dir:name`, e.g., +``` +pants --changed-since=HEAD lint +``` + +You can run on all changed files, and any of their "dependents": ``` -./pants lint helloworld/util:util +pants --changed-since=HEAD --changed-dependents=transitive test ``` -You can omit the target name if it is the same as the immediately enclosing directory name, e.g., +## Target specifications + +Targets are referenced on the command line using their address, of the form `path/to/dir:name`, e.g., ``` -./pants lint helloworld/util +pants lint helloworld/greet:lib ``` You can glob over all targets in a directory with a single trailing `:`, or over all targets in a directory and all its subdirectories with a double trailing `::`, e.g., ``` -./pants lint helloworld:: +pants lint helloworld:: ``` ## Globbing semantics @@ -82,16 +98,11 @@ For example, if you run the `test` goal over a set of files that includes non-te those, rather than error. So you can safely do things like ``` -./pants test :: +pants test :: ``` To run all tests. -In some cases trying to run a goal on multiple files or targets will fail due to conflicts. For example, you cannot -`./pants repl helloworld::` because that globs over both Python 2 and Python 3 code, so there is -no way to select an interpreter compatible with both both to run the REPL on. - - # Example Goals Try these out in this repo! @@ -99,60 +110,79 @@ Try these out in this repo! ## List targets ``` -./pants list helloworld:: # All targets. - -./pants list 'helloworld/**/*.py' # Just targets containing Python code. +pants list :: # All targets. +pants list 'helloworld/**/*.py' # Just targets containing Python code. ``` ## Run linters and formatters ``` -./pants lint helloworld:: -./pants fmt 'helloworld/**/*.py' +pants lint :: +pants fmt helloworld/greet:: +``` + +## Run MyPy + +``` +pants check :: ``` ## Run tests ``` -./pants test :: # Run all tests in the repo. -./pants test helloworld/util:test # Run all the tests in this target. -./pants test helloworld/util/lang_test.py # Run just the tests in this file. -./pants test helloworld/util/lang_test.py --pytest-args='-k test_language_translator' # Run just this one test. +pants test :: # Run all tests in the repo. +pants test --output=all :: # Run all tests in the repo and view pytest output even for tests that passed (you can set this permanently in pants.toml). +pants test helloworld/translator:tests # Run all the tests in this target. +pants test helloworld/translator/translator_test.py # Run just the tests in this file. +pants test helloworld/translator/translator_test.py -- -k test_unknown_phrase # Run just this one test by passing through pytest args. ``` -## Create a runnable binary +## Create a PEX binary + +The `package` goal requires specifying a target which can be packaged. In this case, the there is a `pex_binary` target with the name `pex_binary` in the `helloworld/BUILD` file. ``` -./pants binary helloworld/main.py helloworld/main_py2.py +pants package helloworld:pex_binary ``` -## Run a binary +The pex file is output to `dist/helloworld/pex_binary.pex` and can be executed directly. + +## Run a binary directly ``` -./pants run helloworld/main.py +pants run helloworld/main.py ``` ## Open a REPL ``` -./pants repl helloworld/greet # The REPL will have all relevant code and dependencies on its sys.path. -./pants repl --shell=ipython helloworld/greet +pants repl helloworld/greet:lib # The REPL will have all relevant code and dependencies on its sys.path. +pants repl --shell=ipython helloworld/greet:lib --no-pantsd # To use IPython, you must disable Pantsd for now. +``` + +## Build a wheel / generate `setup.py` + +This will build both a `.whl` bdist and a `.tar.gz` sdist. + +``` +pants package helloworld/translator:dist ``` -## Run `setup.py` commands +## Count lines of code ``` -./pants setup-py --args="bdist_wheel" helloworld/util # Build a wheel. +pants count-loc '**/*' ``` -## Build an AWS Lambda +## Generate or update a lockfile containing the dependencies ``` -./pants awslambda helloworld:helloworld-awslambda # Has sdist requirements, so must be built on Linux. +pants generate-lockfiles --resolve=python-default ``` -## Count lines of code + +## Create virtualenv for IDE integration ``` -./pants cloc '**/*' +pants export --resolve=python-default ``` diff --git a/constraints.txt b/constraints.txt deleted file mode 100644 index 443d4e7..0000000 --- a/constraints.txt +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - -# Generated by first creating a virtual environment with `python3.7 -m venv .venv`, then running -# `.venv/bin/pip install -r requirements.txt` and `.venv/bin/pip freeze`. - -ansicolors==1.1.8 -appdirs==1.4.3 -certifi==2020.4.5.1 -cfgv==3.1.0 -chardet==3.0.4 -click==7.1.2 -distlib==0.3.0 -filelock==3.0.12 -identify==1.4.15 -idna==2.9 -importlib-metadata==1.6.0 -lxml==4.5.0 -nodeenv==1.3.5 -packaging==20.3 -pluggy==0.13.1 -pre-commit==2.3.0 -protobuf==3.11.3 -py==1.8.1 -pyparsing==2.4.7 -PyYAML==5.3.1 -requests==2.23.0 -six==1.14.0 -toml==0.10.0 -tox==3.15.0 -translate==3.5.0 -urllib3==1.25.9 -virtualenv==20.0.20 -zipp==3.1.0 diff --git a/get-pants.sh b/get-pants.sh new file mode 100755 index 0000000..cae178e --- /dev/null +++ b/get-pants.sh @@ -0,0 +1,221 @@ +#!/usr/bin/env bash +# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md). +# Licensed under the Apache License, Version 2.0 (see LICENSE). + +set -euo pipefail + +COLOR_RED="\x1b[31m" +COLOR_GREEN="\x1b[32m" +COLOR_YELLOW="\x1b[33m" +COLOR_RESET="\x1b[0m" + +function log() { + echo -e "$@" 1>&2 +} + +function die() { + (($# > 0)) && log "${COLOR_RED}$*${COLOR_RESET}" + exit 1 +} + +function green() { + (($# > 0)) && log "${COLOR_GREEN}$*${COLOR_RESET}" +} + +function warn() { + (($# > 0)) && log "${COLOR_YELLOW}$*${COLOR_RESET}" +} + +function check_cmd() { + local cmd="$1" + command -v "$cmd" > /dev/null || die "This script requires the ${cmd} binary to be on the PATH." +} + +help_url="https://www.pantsbuild.org/docs/getting-help" + +_GC=() + +function gc() { + if (($# > 0)); then + check_cmd rm + _GC+=("$@") + else + rm -rf "${_GC[@]}" + fi +} + +trap gc EXIT + +check_cmd uname + +function calculate_os() { + local os + + os="$(uname -s)" + if [[ "${os}" =~ [Ll]inux ]]; then + echo linux + elif [[ "${os}" =~ [Dd]arwin ]]; then + echo macos + elif [[ "${os}" =~ [Ww]in|[Mm][Ii][Nn][Gg] ]]; then + # Powershell reports something like: Windows_NT + # Git bash reports something like: MINGW64_NT-10.0-22621 + echo windows + else + die "Pants is not supported on this operating system (${os}). Please reach out to us at ${help_url} for help." + fi +} + +OS="$(calculate_os)" + +check_cmd basename +if [[ "${OS}" == "windows" ]]; then + check_cmd pwsh +else + check_cmd curl +fi + +function fetch() { + local url="$1" + local dest_dir="$2" + + local dest + dest="${dest_dir}/$(basename "${url}")" + + if [[ "${OS}" == "windows" ]]; then + pwsh -c "Invoke-WebRequest -OutFile $dest -Uri $url" + else + curl --proto '=https' --tlsv1.2 -sSfL -o "${dest}" "${url}" + fi +} + +if [[ "${OS}" == "macos" ]]; then + check_cmd shasum +else + check_cmd sha256sum +fi + +function sha256() { + if [[ "${OS}" == "macos" ]]; then + shasum --algorithm 256 "$@" + else + sha256sum "$@" + fi +} + +check_cmd mktemp + +function install_from_url() { + local url="$1" + local dest="$2" + + local workdir + workdir="$(mktemp -d)" + gc "${workdir}" + + fetch "${url}.sha256" "${workdir}" + fetch "${url}" "${workdir}" + ( + cd "${workdir}" + sha256 -c --status ./*.sha256 || + die "Download from ${url} did not match the fingerprint at ${url}.sha256" + ) + rm "${workdir}/"*.sha256 + if [[ "${OS}" == "macos" ]]; then + mkdir -p "$(dirname "${dest}")" + install -m 755 "${workdir}/"* "${dest}" + else + install -D -m 755 "${workdir}/"* "${dest}" + fi +} + +function calculate_arch() { + local arch + + arch="$(uname -m)" + if [[ "${arch}" =~ x86[_-]64 ]]; then + echo x86_64 + elif [[ "${arch}" =~ arm64|aarch64 ]]; then + echo aarch64 + else + die "Pants is not supported for this chip architecture (${arch}). Please reach out to us at ${help_url} for help." + fi +} + +check_cmd cat + +function usage() { + cat << EOF +Usage: $0 + +Installs the pants launcher binary. + +You only need to run this once on a machine when you do not have "pants" +available to run yet. + +The pants binary takes care of managing and running the underlying +Pants version configured in "pants.toml" in the surrounding Pants-using +project. + +Once installed, if you want to update your "pants" launcher binary, use +"SCIE_BOOT=update pants" to get the latest release or +"SCIE_BOOT=update pants --help" to learn more options. + +-h | --help: Print this help message. + +-d | --bin-dir: + The directory to install the scie-pants binary in, "~/.local/bin" by default. + +-b | --base-name: + The name to use for the scie-pants binary, "pants" by default. + +-V | --version: + The version of the scie-pants binary to install, the latest version by default. + The available versions can be seen at: + https://github.com/pantsbuild/scie-pants/releases + +EOF +} + +bin_dir="${HOME}/.local/bin" +base_name="pants" +version="latest/download" +while (($# > 0)); do + case "$1" in + --help | -h) + usage + exit 0 + ;; + --bin-dir | -d) + bin_dir="$2" + shift + ;; + --base-name | -b) + base_name="$2" + shift + ;; + --version | -V) + version="download/v$2" + shift + ;; + *) + usage + die "Unexpected argument $1\n" + ;; + esac + shift +done + +ARCH="$(calculate_arch)" +URL="https://github.com/pantsbuild/scie-pants/releases/${version}/scie-pants-${OS}-${ARCH}" +dest="${bin_dir}/${base_name}" + +log "Downloading and installing the pants launcher ..." +install_from_url "${URL}" "${dest}" +green "Installed the pants launcher from ${URL} to ${dest}" +if ! command -v "${base_name}" > /dev/null; then + warn "${dest} is not on the PATH." + log "You'll either need to invoke ${dest} explicitly or else add ${bin_dir} to your shell's PATH." +fi + +green "\nRunning \`pants\` in a Pants-enabled repo will use the version of Pants configured for that repo." +green "In a repo not yet Pants-enabled, it will prompt you to set up Pants for that repo." diff --git a/helloworld/BUILD b/helloworld/BUILD index bf588a4..5e55812 100644 --- a/helloworld/BUILD +++ b/helloworld/BUILD @@ -1,51 +1,16 @@ # Copyright 2020 Pants project contributors. # Licensed under the Apache License, Version 2.0 (see LICENSE). -python_binary( - # name defaults to the name of this directory, i.e., `helloworld`. - sources = ["main.py"], - entry_point = "helloworld.main", - dependencies = [ - ":config", - "//:ansicolors", - "helloworld/greet", - ], +# This target sets the metadata for all the Python non-test files in this directory. +python_sources( + name="lib", ) -# Note: Has sdist dependencies, so must be built on Linux. -python_awslambda( - name='helloworld-awslambda', - sources = ["awslambda.py"], - dependencies=[ - ":config", - "helloworld/greet", - ], - handler='helloworld.awslambda:handler', - runtime='python3.7', -) - -python_binary( - name = "helloworld_py2", - sources = ["main_py2.py"], - entry_point = "helloworld.main_py2", - compatibility = ">=2.7,<3", - dependencies = [ - "//:ansicolors", - "helloworld/greet_py2", - ], -) - -python_library( - name = "config", - sources = ["config.py"], - dependencies = [ - ":config_file", - "helloworld/protos", - "helloworld/util", - ], -) - -resources( - name = "config_file", - sources = ["config.json"], +# This target allows us to bundle our app into a PEX binary file via +# `pants package`. We can also run it with `pants run`. See +# https://www.pantsbuild.org/docs/python-package-goal and +# https://www.pantsbuild.org/docs/python-run-goal. +pex_binary( + name="pex_binary", + entry_point="main.py", ) diff --git a/helloworld/__init__.py b/helloworld/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/helloworld/awslambda.py b/helloworld/awslambda.py deleted file mode 100644 index 161db44..0000000 --- a/helloworld/awslambda.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - -from helloworld.config import load_config -from helloworld.greet.greeting import Greeter - - -def handler(event, context): - config = load_config() - greeter = Greeter(languages=config.languages, greetings=config.greetings) - print(greeter.greet("world")) diff --git a/helloworld/config.json b/helloworld/config.json deleted file mode 100644 index 6069fa0..0000000 --- a/helloworld/config.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "languages": [ - "en", - "de", - "fr", - "es" - ], - "greetings": [ - "hello", - "good morning", - "good afternoon", - "good evening", - "salutations" - ] -} diff --git a/helloworld/config.py b/helloworld/config.py deleted file mode 100644 index d3cdc96..0000000 --- a/helloworld/config.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - -from helloworld.protos.config_pb2 import Config -from helloworld.util.config_loader import load_config_from_json - - -def load_config() -> Config: - return load_config_from_json(__name__, "config.json") diff --git a/helloworld/greet/BUILD b/helloworld/greet/BUILD index 75366c7..6dcc65e 100644 --- a/helloworld/greet/BUILD +++ b/helloworld/greet/BUILD @@ -1,19 +1,22 @@ # Copyright 2020 Pants project contributors. # Licensed under the Apache License, Version 2.0 (see LICENSE). -python_library( - # `name` defaults to the name of this directory, i.e., `greet`. - # `sources` defaults to ['*.py', '!*_test.py', '!test_*.py', '!conftest.py']. - dependencies = [ - "//:translate", - "helloworld/util", - ], +# This target sets the metadata for all the Python non-test files in this directory. +# +# * Pants cannot yet infer dependencies on `resource` / `resources` targets, so we explicitly add +# the dep. +python_sources( + name="lib", + dependencies=[":translations"], ) +# This target sets the metadata for all the Python test files in this directory. python_tests( - name = 'tests', - # `sources` defaults to ['*_test.py', 'test_*.py', 'conftest.py']. - dependencies = [ - ":greet", - ] + name="tests", +) + +# This target teaches Pants about our JSON file, which allows other targets to depend on it. +resource( + name="translations", + source="translations.json", ) diff --git a/helloworld/greet/__init__.py b/helloworld/greet/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/helloworld/greet/greeting.py b/helloworld/greet/greeting.py index 3338652..70c7675 100644 --- a/helloworld/greet/greeting.py +++ b/helloworld/greet/greeting.py @@ -1,21 +1,29 @@ # Copyright 2020 Pants project contributors. # Licensed under the Apache License, Version 2.0 (see LICENSE). +from __future__ import annotations + +import importlib.resources +import json import random -from typing import List -from helloworld.util.lang import LanguageTranslator +from helloworld.translator.translator import LanguageTranslator class Greeter: - def __init__(self, greetings: List[str], languages: List[str]) -> None: - self._greetings = greetings - self._language_translator = LanguageTranslator(languages=languages) - - def translated_greeting(self) -> str: - random_greeting = random.choice(self._greetings) - return self._language_translator.translate_to_random_language(random_greeting) + def __init__( + self, *, translations: dict[str, dict[str, str]] | None = None + ) -> None: + self._translations = ( + translations + if translations is not None + else json.loads( + importlib.resources.read_text(__name__, "translations.json") + ) + ) + self._translator = LanguageTranslator(self._translations) def greet(self, name: str) -> str: - greeting = self.translated_greeting() + random_greeting = random.choice(list(self._translations.keys())) + greeting = self._translator.translate_to_random_language(random_greeting) return f"{greeting}, {name}!".capitalize() diff --git a/helloworld/greet/greeting_test.py b/helloworld/greet/greeting_test.py index 4faa9e8..8d43373 100644 --- a/helloworld/greet/greeting_test.py +++ b/helloworld/greet/greeting_test.py @@ -5,5 +5,5 @@ def test_greeter() -> None: - greeter = Greeter(languages=["es"], greetings=["good morning"]) - assert greeter.greet("world") == "Buenos días, world!" + greeter = Greeter(translations={"hello": {"es": "hola"}}) + assert greeter.greet("test") == "Hola, test!" diff --git a/helloworld/greet/translations.json b/helloworld/greet/translations.json new file mode 100644 index 0000000..a9eddda --- /dev/null +++ b/helloworld/greet/translations.json @@ -0,0 +1,18 @@ +{ + "hello": { + "es": "hola", + "fr": "bonjour", + "af": "hallo", + "ch": "你好", + "ru": "Привет", + "cs": "ahoj" + }, + "good night": { + "es": "buenas noches", + "fr": "bonne nuit", + "af": "Goeie nag", + "ch": "晚安", + "ru": "спокойной ночи", + "cs": "dobrou noc" + } +} diff --git a/helloworld/greet_py2/BUILD b/helloworld/greet_py2/BUILD deleted file mode 100644 index de883c7..0000000 --- a/helloworld/greet_py2/BUILD +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - - -python_library( - # name defaults to the name of this directory, i.e., `greet_py2`. - # sources defaults to ['*.py', '!*_test.py', '!test_*.py', '!conftest.py']. - compatibility = ">=2.7,<3" -) diff --git a/helloworld/greet_py2/greeting_py2.py b/helloworld/greet_py2/greeting_py2.py deleted file mode 100644 index f030eb4..0000000 --- a/helloworld/greet_py2/greeting_py2.py +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - - -def greet_py2(name): - exec "x = 'hello, {}'.format(name)" - return x # noqa diff --git a/helloworld/main.py b/helloworld/main.py index 42164cc..125d189 100644 --- a/helloworld/main.py +++ b/helloworld/main.py @@ -3,15 +3,12 @@ from colors import green -from helloworld.config import load_config from helloworld.greet.greeting import Greeter def say_hello() -> None: - config = load_config() - greeter = Greeter(languages=config.languages, greetings=config.greetings) - sentence = greeter.greet("world") - print(green(sentence)) + greeting = Greeter().greet("Pantsbuild") + print(green(greeting)) if __name__ == "__main__": diff --git a/helloworld/main_py2.py b/helloworld/main_py2.py deleted file mode 100644 index 588a2b4..0000000 --- a/helloworld/main_py2.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - -from colors import green - -from helloworld.greet_py2.greeting_py2 import greet_py2 - - -def say_hello_py2(): - print green(greet_py2("Python 2")) - - -if __name__ == "__main__": - say_hello_py2() diff --git a/helloworld/protos/BUILD b/helloworld/protos/BUILD deleted file mode 100644 index 317138f..0000000 --- a/helloworld/protos/BUILD +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - -protobuf_library( - # `name` defaults to the name of this directory, i.e., `protos`. - # `sources` defaults to ["*.proto"]. - dependencies=[ - "//:protobuf", - ], -) diff --git a/helloworld/protos/config.proto b/helloworld/protos/config.proto deleted file mode 100644 index 8fd242c..0000000 --- a/helloworld/protos/config.proto +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2020 Pants project contributors. -// Licensed under the Apache License, Version 2.0 (see LICENSE). - -syntax = "proto3"; - -package helloworld.protos; - -message Config { - repeated string languages = 1; - repeated string greetings = 2; -} diff --git a/helloworld/translator/BUILD b/helloworld/translator/BUILD new file mode 100644 index 0000000..7086f94 --- /dev/null +++ b/helloworld/translator/BUILD @@ -0,0 +1,30 @@ +# Copyright 2020 Pants project contributors. +# Licensed under the Apache License, Version 2.0 (see LICENSE). + +# This target sets the metadata for all the Python non-test files in this directory. +python_sources( + name="lib", +) + +# This target sets the metadata for all the Python test files in this directory. +python_tests( + name="tests", +) + +# This target allows us to build a `.whl` bdist and a `.tar.gz` sdist by auto-generating +# `setup.py`. See https://www.pantsbuild.org/docs/python-distributions. +# +# Because this target has no source code, Pants cannot infer dependencies. We depend on `:lib`, +# which means we'll include all the non-test Python files in this directory, and any of +# their dependencies. +python_distribution( + name="dist", + dependencies=[":lib"], + wheel=True, + sdist=True, + provides=setup_py( + name="helloworld.translator", + version="0.0.1", + description="A language translator.", + ), +) diff --git a/helloworld/translator/__init__.py b/helloworld/translator/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/helloworld/translator/translator.py b/helloworld/translator/translator.py new file mode 100644 index 0000000..d9fb1b3 --- /dev/null +++ b/helloworld/translator/translator.py @@ -0,0 +1,46 @@ +# Copyright 2020 Pants project contributors. +# Licensed under the Apache License, Version 2.0 (see LICENSE). + +from __future__ import annotations + +import random +from dataclasses import dataclass + + +class UnknownLanguage(Exception): + pass + + +class UnknownPhrase(Exception): + pass + + +@dataclass +class LanguageTranslator: + """A mapping of phrases (in English) to ISO 639 language codes (like `es`, + `fr`) and their translation. + + Assumes that every phrase is translated into the same languages. + """ + + phrases_to_translations: dict[str, dict[str, str]] + + @property + def all_languages(self) -> set[str]: + return { + lang + for translations in self.phrases_to_translations.values() + for lang in translations.keys() + } + + def translate(self, lang: str, phrase: str) -> str: + if phrase not in self.phrases_to_translations: + raise UnknownPhrase(phrase) + translations = self.phrases_to_translations[phrase] + if lang not in translations: + raise UnknownLanguage(lang) + return translations[lang] + + def translate_to_random_language(self, phrase: str) -> str: + lang = random.choice(sorted(self.all_languages)) + return self.translate(lang, phrase) diff --git a/helloworld/translator/translator_test.py b/helloworld/translator/translator_test.py new file mode 100644 index 0000000..1f838ff --- /dev/null +++ b/helloworld/translator/translator_test.py @@ -0,0 +1,34 @@ +# Copyright 2020 Pants project contributors. +# Licensed under the Apache License, Version 2.0 (see LICENSE). + +import pytest + +from helloworld.translator.translator import ( + LanguageTranslator, + UnknownLanguage, + UnknownPhrase, +) + + +def test_language_translator() -> None: + translator = LanguageTranslator( + { + "hello": {"es": "hola", "ar": "مرحبًا"}, + "computer": {"es": "computadora", "ar": "حاسوب"}, + } + ) + assert translator.translate("es", "hello") == "hola" + assert translator.translate("ar", "hello") == "مرحبًا" + assert translator.translate("es", "computer") == "computadora" + + +def test_unknown_phrase() -> None: + translator = LanguageTranslator({"hello": {"es": "hola"}}) + with pytest.raises(UnknownPhrase): + translator.translate("es", "good morning") + + +def test_unknown_language() -> None: + translator = LanguageTranslator({"hello": {"es": "hola"}}) + with pytest.raises(UnknownLanguage): + translator.translate("ch", "hello") diff --git a/helloworld/util/BUILD b/helloworld/util/BUILD deleted file mode 100644 index ceed705..0000000 --- a/helloworld/util/BUILD +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - -python_library( - # `name` defaults to the name of this directory, i.e., `util`. - # `sources` defaults to ['*.py', '!*_test.py', '!test_*.py', '!conftest.py']. - dependencies = [ - "//:setuptools", - "//:translate", - "helloworld/protos", - ], - # See https://pants.readme.io/docs/python-setup-py-goal. - provides = setup_py( - name='helloworld.util', - version='0.0.1', - description='Greeting library utilities', - ), -) - -python_tests( - name = 'tests', - # `sources` defaults to ['*_test.py', 'test_*.py', 'conftest.py']. - dependencies = [ - ":config_loader_test_data", - ":util", - ], -) - -resources( - name = 'config_loader_test_data', - sources = ['config_loader_test_data.json'], -) diff --git a/helloworld/util/config_loader.py b/helloworld/util/config_loader.py deleted file mode 100644 index ce2f9de..0000000 --- a/helloworld/util/config_loader.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - -import pkg_resources -from google.protobuf.json_format import Parse as parse_json - -from helloworld.protos.config_pb2 import Config - - -def load_config_from_json(pkg_name: str, resource_name: str) -> Config: - resource_content = pkg_resources.resource_string(pkg_name, resource_name).decode() - return parse_json(resource_content, Config()) diff --git a/helloworld/util/config_loader_test.py b/helloworld/util/config_loader_test.py deleted file mode 100644 index 2059a06..0000000 --- a/helloworld/util/config_loader_test.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - -from helloworld.util.config_loader import load_config_from_json - - -def test_load_config_from_json() -> None: - config = load_config_from_json(__name__, "config_loader_test_data.json") - assert config.languages == ["af", "zh"] - assert config.greetings == ["hi", "hey"] diff --git a/helloworld/util/config_loader_test_data.json b/helloworld/util/config_loader_test_data.json deleted file mode 100644 index deeb560..0000000 --- a/helloworld/util/config_loader_test_data.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "languages": [ - "af", - "zh" - ], - "greetings": [ - "hi", - "hey" - ] -} diff --git a/helloworld/util/lang.py b/helloworld/util/lang.py deleted file mode 100644 index 3a75cab..0000000 --- a/helloworld/util/lang.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - -import random -from typing import List - -from translate import Translator - - -class LanguageTranslator: - class UnknownLanguage(Exception): - pass - - def __init__(self, languages: List[str]) -> None: - self._langs = languages - - def translate(self, lang: str, phrase: str) -> str: - if lang not in self._langs: - raise self.UnknownLanguage(lang) - translator = Translator(lang) - return translator.translate(phrase) - - def translate_to_random_language(self, phrase: str) -> str: - return self.translate(self._pick_random_language(), phrase) - - def _pick_random_language(self) -> str: - return random.choice(self._langs) diff --git a/helloworld/util/lang_test.py b/helloworld/util/lang_test.py deleted file mode 100644 index 190a96a..0000000 --- a/helloworld/util/lang_test.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - -import pytest - -from helloworld.util.lang import LanguageTranslator - - -def test_language_translator() -> None: - language_translator = LanguageTranslator(languages=["es"]) - assert "hola" == language_translator.translate("es", "hello") - - -def test_unknown_language() -> None: - language_translator = LanguageTranslator(languages=[]) - with pytest.raises(LanguageTranslator.UnknownLanguage): - language_translator.translate("xx", "hello") diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..77ca553 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,31 @@ +[mypy] +# Optionals +no_implicit_optional = True + +# Strictness +allow_untyped_globals = False +allow_redefinition = False +implicit_reexport = False +strict_equality = True + +# Warnings +warn_unused_ignores = True +warn_no_return = True +warn_return_any = True +warn_redundant_casts = True +warn_unreachable = True + +# Error output +show_column_numbers = True +show_error_context = True +show_error_codes = True +show_traceback = True +pretty = True +color_output = True +error_summary = True + +[mypy-colors] +ignore_missing_imports = True + +[mypy-pytest] +ignore_missing_imports = True diff --git a/pants b/pants deleted file mode 100755 index 2e265e6..0000000 --- a/pants +++ /dev/null @@ -1,194 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - -# =============================== NOTE =============================== -# This ./pants bootstrap script comes from the pantsbuild/setup -# project and is intended to be checked into your code repository so -# that any developer can check out your code and be building it with -# Pants with no prior setup needed. -# -# You can learn more here: https://www.pantsbuild.org/install.html -# ==================================================================== - -set -eou pipefail - -PYTHON_BIN_NAME="${PYTHON:-unspecified}" - -PANTS_HOME="${PANTS_HOME:-${XDG_CACHE_HOME:-$HOME/.cache}/pants/setup}" -PANTS_BOOTSTRAP="${PANTS_HOME}/bootstrap-$(uname -s)-$(uname -m)" - -VENV_VERSION=${VENV_VERSION:-16.4.3} - -VENV_PACKAGE=virtualenv-${VENV_VERSION} -VENV_TARBALL=${VENV_PACKAGE}.tar.gz - -COLOR_RED="\x1b[31m" -COLOR_GREEN="\x1b[32m" -COLOR_RESET="\x1b[0m" - -function log() { - echo -e "$@" 1>&2 -} - -function die() { - (($# > 0)) && log "${COLOR_RED}$*${COLOR_RESET}" - exit 1 -} - -function green() { - (($# > 0)) && log "${COLOR_GREEN}$*${COLOR_RESET}" -} - -function tempdir { - mktemp -d "$1"/pants.XXXXXX -} - -function get_exe_path_or_die { - exe="$1" - if ! command -v "${exe}"; then - die "Could not find ${exe}. Please ensure ${exe} is on your PATH." - fi -} - -function get_pants_config_value { - config_key="$1" - optional_space="[[:space:]]*" - if [[ -f 'pants.ini' ]]; then - valid_delimiters="[:=]" - prefix="^${config_key}${optional_space}${valid_delimiters}${optional_space}" - sed -ne "/${prefix}/ s#${prefix}##p" pants.ini && return 0 - fi - if [[ -f 'pants.toml' ]]; then - prefix="^${config_key}${optional_space}=${optional_space}" - raw_value="$(sed -ne "/${prefix}/ s#${prefix}##p" pants.toml)" - echo "${raw_value}" | tr -d \"\' && return 0 - fi - return 0 -} - -function get_python_major_minor_version { - python_exe="$1" - "$python_exe" <&1 > /dev/null)" == "pyenv: python${version}"* ]]; then - continue - fi - echo "${interpreter_path}" && return 0 - done -} - -function determine_python_exe { - if [[ "${PYTHON_BIN_NAME}" != 'unspecified' ]]; then - python_bin_name="${PYTHON_BIN_NAME}" - else - python_bin_name="$(determine_default_python_exe)" - if [[ -z "${python_bin_name}" ]]; then - die "No valid Python interpreter found. Pants requires Python 3.6+ to run." - fi - fi - python_exe="$(get_exe_path_or_die "${python_bin_name}")" - major_minor_version="$(get_python_major_minor_version "${python_exe}")" - for valid_version in '36' '37' '38' '39'; do - if [[ "${major_minor_version}" == "${valid_version}" ]]; then - echo "${python_exe}" && return 0 - fi - done - die "Invalid Python interpreter version for ${python_exe}. Pants requires Python 3.6+ to run." -} - -# TODO(John Sirois): GC race loser tmp dirs leftover from bootstrap_XXX -# functions. Any tmp dir w/o a symlink pointing to it can go. - -function bootstrap_venv { - if [[ ! -d "${PANTS_BOOTSTRAP}/${VENV_PACKAGE}" ]]; then - ( - mkdir -p "${PANTS_BOOTSTRAP}" - staging_dir=$(tempdir "${PANTS_BOOTSTRAP}") - cd "${staging_dir}" - curl -LO "https://pypi.io/packages/source/v/virtualenv/${VENV_TARBALL}" - tar -xzf "${VENV_TARBALL}" - ln -s "${staging_dir}/${VENV_PACKAGE}" "${staging_dir}/latest" - mv "${staging_dir}/latest" "${PANTS_BOOTSTRAP}/${VENV_PACKAGE}" - ) 1>&2 - fi - echo "${PANTS_BOOTSTRAP}/${VENV_PACKAGE}" -} - -function bootstrap_pants { - pants_version="$1" - python="$2" - - pants_requirement="pantsbuild.pants==${pants_version}" - python_major_minor_version="$(get_python_major_minor_version "${python}")" - target_folder_name="${pants_version}_py${python_major_minor_version}" - - if [[ ! -d "${PANTS_BOOTSTRAP}/${target_folder_name}" ]]; then - ( - venv_path="$(bootstrap_venv)" - staging_dir=$(tempdir "${PANTS_BOOTSTRAP}") - "${python}" "${venv_path}/virtualenv.py" --no-download "${staging_dir}/install" - "${staging_dir}/install/bin/pip" install -U pip - "${staging_dir}/install/bin/pip" install "${pants_requirement}" - ln -s "${staging_dir}/install" "${staging_dir}/${target_folder_name}" - mv "${staging_dir}/${target_folder_name}" "${PANTS_BOOTSTRAP}/${target_folder_name}" - green "New virtual environment successfully created at ${PANTS_BOOTSTRAP}/${target_folder_name}." - ) 1>&2 - fi - echo "${PANTS_BOOTSTRAP}/${target_folder_name}" -} - -# Ensure we operate from the context of the ./pants buildroot. -cd "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" -pants_version="$(determine_pants_version)" -python="$(determine_python_exe)" -pants_dir="$(bootstrap_pants "${pants_version}" "${python}")" - - -# We set the env var no_proxy to '*', to work around an issue with urllib using non -# async-signal-safe syscalls after we fork a process that has already spawned threads. -# -# See https://blog.phusion.nl/2017/10/13/why-ruby-app-servers-break-on-macos-high-sierra-and-what-can-be-done-about-it/ -export no_proxy='*' - -exec "${pants_dir}/bin/python" "${pants_dir}/bin/pants" "$@" diff --git a/pants.ci.toml b/pants.ci.toml index 9050246..bcf7a2e 100644 --- a/pants.ci.toml +++ b/pants.ci.toml @@ -1,16 +1,15 @@ -# See https://pants.readme.io/docs/using-pants-in-ci. +# Copyright 2020 Pants project contributors. +# Licensed under the Apache License, Version 2.0 (see LICENSE). + +# See https://www.pantsbuild.org/docs/using-pants-in-ci. [GLOBAL] -# Turn off the interactive UI. -v2_ui = false +dynamic_ui = false +colors = true -# Limit the maximum number of concurrent processes. Change this -# to a number that makes sense for your CI setup, based on -# the number of cores/threads. -process_execution_local_parallelism = 4 +# Set to `true` if you have a Pants remote cache provider available for CI builds +remote_cache_read = false +remote_cache_write = false -[python-setup] -# Limit the maximum number of concurrent jobs used to resolve third -# party dependencies. The total level of parallelism will be -# `process_execution_local_parallelism x resolver_jobs`. -resolver_jobs = 1 +[pytest] +args = ["-vv", "--no-header"] diff --git a/pants.toml b/pants.toml index ca4dbae..9c62618 100644 --- a/pants.toml +++ b/pants.toml @@ -2,48 +2,45 @@ # Licensed under the Apache License, Version 2.0 (see LICENSE). [GLOBAL] -pants_version = "1.28.0" -v1 = false # Turn off the v1 execution engine. -v2 = true # Enable the v2 execution engine. -v2_ui = true # Enable the v2 execution engine's terminal-based UI. - -backend_packages = [] # Deregister all v1 backends. - -# List v2 backends here. -backend_packages2.add = [ - 'pants.backend.awslambda.python', - 'pants.backend.codegen.protobuf.python', - 'pants.backend.python', - 'pants.backend.python.lint.docformatter', - 'pants.backend.python.lint.black', - 'pants.backend.python.lint.flake8', - 'pants.backend.python.lint.isort', +pants_version = "2.29.0" +backend_packages.add = [ + "pants.backend.build_files.fmt.black", + "pants.backend.python", + "pants.backend.python.lint.docformatter", + "pants.backend.python.lint.black", + "pants.backend.python.lint.flake8", + "pants.backend.python.lint.isort", + "pants.backend.python.typecheck.mypy", ] -# List v2 plugins here. -plugins2 = [] +[anonymous-telemetry] +enabled = true +repo_id = "3B1D361B-E9F1-49A8-B761-03DCC41FD58E" [source] -# The Python source root is the repo root. See https://pants.readme.io/docs/source-roots. +# The Python source root is the repo root. See https://www.pantsbuild.org/docs/source-roots. root_patterns = ["/"] -[python-setup] -# The default interpreter compatibility for code in this repo. Individual targets can ovverride -# this with the `compatibility` field. See -# https://pants.readme.io/docs/python-interpreter-compatibility. -interpreter_constraints = [">=3.7"] -# Use a lockfile. See https://pants.readme.io/docs/python-third-party-dependencies. -requirement_constraints = "constraints.txt" - -[lint] -# We use `per_target_caching` because we have some Python 2-only targets and some Python 3-only -# targets, so we need to run each target as a separate process to avoid interpreter compatibility -# conflicts. If you only have one Python version in your repository, do not use this setting. See -# https://pants.readme.io/docs/python-lint-goal. -per_target_caching = true - -[flake8] -config = ".flake8" - -[isort] -config = [".isort.cfg"] +[python] +# The default interpreter constraints for code in this repo. Individual targets can override +# this with the `interpreter_constraints` field. See +# https://www.pantsbuild.org/docs/python-interpreter-compatibility. +# +# Modify this if you don't have Python 3.13 on your machine. +# This can be a range, such as [">=3.8,<3.11"], but it's usually recommended to restrict +# to a single minor version. +interpreter_constraints = ["==3.12.*"] + +# Enable the "resolves" mechanism, which turns on lockfiles for user code. See +# https://www.pantsbuild.org/docs/python-third-party-dependencies. This also adds the +# `generate-lockfiles` goal for Pants to generate the lockfile for you. +enable_resolves = true + +resolves = { python-default = "python-default.lock"} + +[python-bootstrap] +# We search for interpreters both on the $PATH and in the `$(pyenv root)/versions` folder. +# If you're using macOS, you may want to leave off the entry to avoid using the +# problematic system Pythons. See +# https://www.pantsbuild.org/docs/python-interpreter-compatibility#changing-the-interpreter-search-path. +search_path = ["", ""] diff --git a/pants_from_sources b/pants_from_sources deleted file mode 100755 index 08de322..0000000 --- a/pants_from_sources +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2020 Pants project contributors. -# Licensed under the Apache License, Version 2.0 (see LICENSE). - -# Runs pants from sources. Useful for debugging. -# Assumes you have the pantsbuild/pants repo checked out in a sibling dir of this dir, -# named 'pants' but overridable using PANTS_SOURCE. - -set -euo pipefail - -cd "$(git rev-parse --show-toplevel)" - -PANTS_SOURCE="${PANTS_SOURCE:-../pants}" - -# When running pants from sources you are likely to be modifying those sources, so -# you won't want pantsd running. You can override this by setting ENABLE_PANTSD=true. -ENABLE_PANTSD="${ENABLE_PANTSD:-false}" - -backend_packages=( -) - -pythonpath=( -) - -plugins=( -) - -function string_list() { - eval local -r list_variable="\${$1[@]}" - - echo -n "[" - for item in ${list_variable}; do - echo -n "\"${item}\"," - done - echo -n "]" -} - -export PANTS_VERSION="$(cat "${PANTS_SOURCE}/src/python/pants/VERSION")" -export PANTS_PLUGINS2="$(string_list plugins)" -export PANTS_PYTHONPATH="+$(string_list pythonpath)" -export PANTS_BACKEND_PACKAGES2="+$(string_list backend_packages)" -export PANTS_ENABLE_PANTSD="${ENABLE_PANTSD}" -export no_proxy="*" - -exec "${PANTS_SOURCE}/pants" "--no-verify-config" "$@" diff --git a/python-default.lock b/python-default.lock new file mode 100644 index 0000000..4f755f2 --- /dev/null +++ b/python-default.lock @@ -0,0 +1,375 @@ +// This lockfile was autogenerated by Pants. To regenerate, run: +// +// pants generate-lockfiles --resolve=python-default +// +// --- BEGIN PANTS LOCKFILE METADATA: DO NOT EDIT OR REMOVE --- +// { +// "version": 4, +// "valid_for_interpreter_constraints": [ +// "CPython==3.12.*" +// ], +// "generated_with_requirements": [ +// "ansicolors==1.1.8", +// "pytest==7.1.3", +// "setuptools<57,>=56.2.0", +// "types-setuptools<58,>=56.2.0" +// ], +// "manylinux": "manylinux2014", +// "requirement_constraints": [], +// "only_binary": [], +// "no_binary": [], +// "excludes": [], +// "overrides": [] +// } +// --- END PANTS LOCKFILE METADATA --- + +{ + "allow_builds": true, + "allow_prereleases": false, + "allow_wheels": true, + "build_isolation": true, + "constraints": [], + "elide_unused_requires_dist": false, + "excluded": [], + "locked_resolves": [ + { + "locked_requirements": [ + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "00d2dde5a675579325902536738dd27e4fac1fd68f773fe36c21044eb559e187", + "url": "https://files.pythonhosted.org/packages/53/18/a56e2fe47b259bb52201093a3a9d4a32014f9d85071ad07e9d60600890ca/ansicolors-1.1.8-py2.py3-none-any.whl" + }, + { + "algorithm": "sha256", + "hash": "99f94f5e3348a0bcd43c82e5fc4414013ccc19d70bd939ad71e0133ce9c372e0", + "url": "https://files.pythonhosted.org/packages/76/31/7faed52088732704523c259e24c26ce6f2f33fbeff2ff59274560c27628e/ansicolors-1.1.8.zip" + } + ], + "project_name": "ansicolors", + "requires_dists": [], + "requires_python": null, + "version": "1.1.8" + }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", + "url": "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl" + }, + { + "algorithm": "sha256", + "hash": "75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", + "url": "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz" + } + ], + "project_name": "attrs", + "requires_dists": [ + "cloudpickle; platform_python_implementation == \"CPython\" and extra == \"benchmark\"", + "cloudpickle; platform_python_implementation == \"CPython\" and extra == \"cov\"", + "cloudpickle; platform_python_implementation == \"CPython\" and extra == \"dev\"", + "cloudpickle; platform_python_implementation == \"CPython\" and extra == \"tests\"", + "cogapp; extra == \"docs\"", + "coverage[toml]>=5.3; extra == \"cov\"", + "furo; extra == \"docs\"", + "hypothesis; extra == \"benchmark\"", + "hypothesis; extra == \"cov\"", + "hypothesis; extra == \"dev\"", + "hypothesis; extra == \"tests\"", + "mypy>=1.11.1; (platform_python_implementation == \"CPython\" and python_version >= \"3.10\") and extra == \"benchmark\"", + "mypy>=1.11.1; (platform_python_implementation == \"CPython\" and python_version >= \"3.10\") and extra == \"cov\"", + "mypy>=1.11.1; (platform_python_implementation == \"CPython\" and python_version >= \"3.10\") and extra == \"dev\"", + "mypy>=1.11.1; (platform_python_implementation == \"CPython\" and python_version >= \"3.10\") and extra == \"tests\"", + "mypy>=1.11.1; (platform_python_implementation == \"CPython\" and python_version >= \"3.10\") and extra == \"tests-mypy\"", + "myst-parser; extra == \"docs\"", + "pre-commit-uv; extra == \"dev\"", + "pympler; extra == \"benchmark\"", + "pympler; extra == \"cov\"", + "pympler; extra == \"dev\"", + "pympler; extra == \"tests\"", + "pytest-codspeed; extra == \"benchmark\"", + "pytest-mypy-plugins; (platform_python_implementation == \"CPython\" and python_version >= \"3.10\") and extra == \"benchmark\"", + "pytest-mypy-plugins; (platform_python_implementation == \"CPython\" and python_version >= \"3.10\") and extra == \"cov\"", + "pytest-mypy-plugins; (platform_python_implementation == \"CPython\" and python_version >= \"3.10\") and extra == \"dev\"", + "pytest-mypy-plugins; (platform_python_implementation == \"CPython\" and python_version >= \"3.10\") and extra == \"tests\"", + "pytest-mypy-plugins; (platform_python_implementation == \"CPython\" and python_version >= \"3.10\") and extra == \"tests-mypy\"", + "pytest-xdist[psutil]; extra == \"benchmark\"", + "pytest-xdist[psutil]; extra == \"cov\"", + "pytest-xdist[psutil]; extra == \"dev\"", + "pytest-xdist[psutil]; extra == \"tests\"", + "pytest>=4.3.0; extra == \"benchmark\"", + "pytest>=4.3.0; extra == \"cov\"", + "pytest>=4.3.0; extra == \"dev\"", + "pytest>=4.3.0; extra == \"tests\"", + "sphinx-notfound-page; extra == \"docs\"", + "sphinx; extra == \"docs\"", + "sphinxcontrib-towncrier; extra == \"docs\"", + "towncrier; extra == \"docs\"" + ], + "requires_python": ">=3.8", + "version": "25.3.0" + }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", + "url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl" + }, + { + "algorithm": "sha256", + "hash": "3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", + "url": "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz" + } + ], + "project_name": "iniconfig", + "requires_dists": [], + "requires_python": ">=3.8", + "version": "2.1.0" + }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", + "url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl" + }, + { + "algorithm": "sha256", + "hash": "d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", + "url": "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz" + } + ], + "project_name": "packaging", + "requires_dists": [], + "requires_python": ">=3.8", + "version": "25.0" + }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", + "url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl" + }, + { + "algorithm": "sha256", + "hash": "7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", + "url": "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz" + } + ], + "project_name": "pluggy", + "requires_dists": [ + "coverage; extra == \"testing\"", + "pre-commit; extra == \"dev\"", + "pytest-benchmark; extra == \"testing\"", + "pytest; extra == \"testing\"", + "tox; extra == \"dev\"" + ], + "requires_python": ">=3.9", + "version": "1.6.0" + }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378", + "url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl" + }, + { + "algorithm": "sha256", + "hash": "51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", + "url": "https://files.pythonhosted.org/packages/98/ff/fec109ceb715d2a6b4c4a85a61af3b40c723a961e8828319fbcb15b868dc/py-1.11.0.tar.gz" + } + ], + "project_name": "py", + "requires_dists": [], + "requires_python": "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7", + "version": "1.11.0" + }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7", + "url": "https://files.pythonhosted.org/packages/e3/b9/3541bbcb412a9fd56593005ff32183825634ef795a1c01ceb6dee86e7259/pytest-7.1.3-py3-none-any.whl" + }, + { + "algorithm": "sha256", + "hash": "4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39", + "url": "https://files.pythonhosted.org/packages/a4/a7/8c63a4966935b0d0b039fd67ebf2e1ae00f1af02ceb912d838814d772a9a/pytest-7.1.3.tar.gz" + } + ], + "project_name": "pytest", + "requires_dists": [ + "argcomplete; extra == \"testing\"", + "attrs>=19.2.0", + "colorama; sys_platform == \"win32\"", + "hypothesis>=3.56; extra == \"testing\"", + "importlib-metadata>=0.12; python_version < \"3.8\"", + "iniconfig", + "mock; extra == \"testing\"", + "nose; extra == \"testing\"", + "packaging", + "pluggy<2.0,>=0.12", + "py>=1.8.2", + "pygments>=2.7.2; extra == \"testing\"", + "requests; extra == \"testing\"", + "tomli>=1.0.0", + "xmlschema; extra == \"testing\"" + ], + "requires_python": ">=3.7", + "version": "7.1.3" + }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "bc30153eec47d82f20c6f5e1a13d4ee725c6deb7013a67557f89bfe5d25235c4", + "url": "https://files.pythonhosted.org/packages/d0/15/5041473f5d142ee93bf1593deb8f932e27a078f6f04e2020cf44044f72c5/setuptools-56.2.0-py3-none-any.whl" + }, + { + "algorithm": "sha256", + "hash": "7bb5652625e94e73b9358b7ed8c6431b732e80cf31f4e0972294c64f0e5b849e", + "url": "https://files.pythonhosted.org/packages/fc/0a/b486efab52f8ad03c3eca0c998dd3deafba0c39b29e0c49c68a7152c8b2d/setuptools-56.2.0.tar.gz" + } + ], + "project_name": "setuptools", + "requires_dists": [ + "certifi==2016.9.26; extra == \"certs\"", + "flake8-2020; extra == \"testing\"", + "jaraco.envs; extra == \"testing\"", + "jaraco.packaging>=8.2; extra == \"docs\"", + "jaraco.path>=3.2.0; extra == \"testing\"", + "mock; extra == \"testing\"", + "paver; extra == \"testing\"", + "pip>=19.1; extra == \"testing\"", + "pygments-github-lexers==0.0.5; extra == \"docs\"", + "pytest-black>=0.3.7; (platform_python_implementation != \"PyPy\" and python_version < \"3.10\") and extra == \"testing\"", + "pytest-checkdocs>=2.4; extra == \"testing\"", + "pytest-cov; extra == \"testing\"", + "pytest-enabler>=1.0.1; extra == \"testing\"", + "pytest-flake8; extra == \"testing\"", + "pytest-mypy; (platform_python_implementation != \"PyPy\" and python_version < \"3.10\") and extra == \"testing\"", + "pytest-virtualenv>=1.2.7; extra == \"testing\"", + "pytest-xdist; extra == \"testing\"", + "pytest>=4.6; extra == \"testing\"", + "rst.linker>=1.9; extra == \"docs\"", + "sphinx-inline-tabs; extra == \"docs\"", + "sphinx; extra == \"docs\"", + "sphinx; extra == \"testing\"", + "virtualenv>=13.0.0; extra == \"testing\"", + "wheel; extra == \"testing\"", + "wincertstore==0.2; sys_platform == \"win32\" and extra == \"ssl\"" + ], + "requires_python": ">=3.6", + "version": "56.2.0" + }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", + "url": "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl" + }, + { + "algorithm": "sha256", + "hash": "8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", + "url": "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl" + }, + { + "algorithm": "sha256", + "hash": "cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", + "url": "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz" + }, + { + "algorithm": "sha256", + "hash": "4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", + "url": "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", + "url": "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", + "url": "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl" + }, + { + "algorithm": "sha256", + "hash": "400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", + "url": "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl" + }, + { + "algorithm": "sha256", + "hash": "40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", + "url": "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl" + }, + { + "algorithm": "sha256", + "hash": "02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", + "url": "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl" + }, + { + "algorithm": "sha256", + "hash": "4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", + "url": "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl" + } + ], + "project_name": "tomli", + "requires_dists": [], + "requires_python": ">=3.8", + "version": "2.2.1" + }, + { + "artifacts": [ + { + "algorithm": "sha256", + "hash": "9660b8774b12cd61b448e2fd87a667c02e7ec13ce9f15171f1d49a4654c4df6a", + "url": "https://files.pythonhosted.org/packages/14/45/b8368a8c2d1dc4fa47eb4db980966e23edecbda16fab7a38186b076bbd4d/types_setuptools-57.4.18-py3-none-any.whl" + }, + { + "algorithm": "sha256", + "hash": "8ee03d823fe7fda0bd35faeae33d35cb5c25b497263e6a58b34c4cfd05f40bcf", + "url": "https://files.pythonhosted.org/packages/13/5e/3d46cd143913bd51dde973cd23b1d412de9662b08a3b8c213f26b265e6f1/types-setuptools-57.4.18.tar.gz" + } + ], + "project_name": "types-setuptools", + "requires_dists": [], + "requires_python": null, + "version": "57.4.18" + } + ], + "platform_tag": null + } + ], + "only_builds": [], + "only_wheels": [], + "overridden": [], + "path_mappings": {}, + "pex_version": "2.55.2", + "pip_version": "24.2", + "prefer_older_binary": false, + "requirements": [ + "ansicolors==1.1.8", + "pytest==7.1.3", + "setuptools<57,>=56.2.0", + "types-setuptools<58,>=56.2.0" + ], + "requires_python": [ + "CPython==3.12.*" + ], + "resolver_version": "pip-2020-resolver", + "style": "universal", + "target_systems": [ + "linux", + "mac" + ], + "transitive": true, + "use_pep517": null, + "use_system_time": false +} diff --git a/requirements.txt b/requirements.txt index 2fbc86c..979167d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # Copyright 2020 Pants project contributors. # Licensed under the Apache License, Version 2.0 (see LICENSE). -ansicolors>=1.0.2 -setuptools>=42.0.0 -translate>=3.2.1 -protobuf>=3.11.3 +ansicolors==1.1.8 +setuptools>=56.2.0,<57 +types-setuptools>=56.2.0,<58 +pytest==7.1.3 \ No newline at end of file