[
  {
    "path": ".github/workflows/build.yml",
    "content": "# Heavily based on the Poetry main Github Actions workflow\n# https://github.com/python-poetry/poetry/blob/1.2.0a1/.github/workflows/main.yml\n\nname: \"CI\"\non:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - '**'\n\njobs:\n  tests:\n    name: ${{ matrix.os }} / ${{ matrix.python-version }}\n    runs-on: ${{ matrix.os }}-latest\n    strategy:\n      matrix:\n        os: [Ubuntu, MacOS]\n        python-version: [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\", \"3.12\"]\n    defaults:\n      run:\n        shell: bash\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Set up Python ${{ matrix.python-version }}\n        uses: actions/setup-python@v4\n        id: setup-python\n        with:\n          python-version: ${{ matrix.python-version }}\n\n      - name: Install poetry\n        run: |\n          if [[ \"${{ matrix.python-version }}\" == \"3.7\" ]]; then\n            curl -sSL https://install.python-poetry.org | python - --version 1.5.1 -y\n          else\n            curl -sSL https://install.python-poetry.org | python - -y\n          fi\n\n      - name: Update PATH\n        run: echo \"$HOME/.local/bin\" >> $GITHUB_PATH\n\n      - name: Configure poetry\n        run: poetry config virtualenvs.in-project true\n\n      - name: Set up cache\n        uses: actions/cache@v3\n        id: cache\n        with:\n          path: .venv\n          key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}\n\n      - name: Ensure cache is healthy\n        if: steps.cache.outputs.cache-hit == 'true'\n        run: timeout 10s poetry run pip --version || rm -rf .venv\n\n      - name: Install dependencies\n        run: poetry install --no-root\n\n      - name: Install poetry-dotenv-plugin\n        run: poetry self add \"$GITHUB_WORKSPACE\"\n\n      - name: Run system tests\n        run: tests/test_system.sh\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "# Based on\n# https://github.com/python-poetry/poetry/blob/a0cc7d6b9ea9b59203ac01e4ac641643dc7c9c7a/.github/workflows/release.yml\n\nname: Release\n\non:\n  push:\n    tags:\n      - '*.*.*'\n\njobs:\n  release:\n    name: Release\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Set up Python 3.11\n        uses: actions/setup-python@v4\n        with:\n          python-version: \"3.11\"\n\n      - name: Install Poetry\n        run: curl -sSL https://install.python-poetry.org | python - -y\n\n      - name: Update PATH\n        run: echo \"$HOME/.local/bin\" >> $GITHUB_PATH\n\n      - name: Build project for distribution\n        run: poetry build\n\n      - name: Check Version\n        id: check-version\n        run: |\n          [[ \"$(poetry version --short)\" =~ ^[0-9]+\\.[0-9]+\\.[0-9]+$ ]] \\\n            || echo \"prerelease=true\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Create Release\n        uses: ncipollo/release-action@v1\n        with:\n          artifacts: \"dist/*\"\n          token: ${{ secrets.GITHUB_TOKEN }}\n          draft: false\n          prerelease: steps.check-version.outputs.prerelease == 'true'\n\n      - name: Publish to PyPI\n        env:\n          POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }}\n        run: poetry publish\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2021 Michael Peteuil\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Poetry Dotenv Plugin\n\n[![CI](https://github.com/mpeteuil/poetry-dotenv-plugin/actions/workflows/build.yml/badge.svg)](https://github.com/mpeteuil/poetry-dotenv-plugin/actions/workflows/build.yml)\n\nA [Poetry](https://python-poetry.org/) plugin that automatically loads environment variables from `.env` files into the environment before poetry commands are run.\n\nSupports Python 3.7+[^1]\n\n```sh\n$ cat .env\nMY_ENV_VAR='Hello World'\n\n$ poetry run python -c 'import os; print(os.environ.get(\"MY_ENV_VAR\"))'\nHello World\n```\n\nThis plugin depends on the [`python-dotenv` package](https://github.com/theskumar/python-dotenv) for its functionality and therefore also supports features that `python-dotenv` supports. Interpolating variables using POSIX variable expansion for example.\n\n### Origins\n\nInitial implementation based on the event handler application plugin example in the [Poetry docs](https://python-poetry.org/docs/plugins/#event-handler).\n\n## Install\n\n```sh\npoetry self add poetry-dotenv-plugin\n```\n\n### Coming from Pipenv\n\nIf you are transitioning from `pipenv` there shouldn't be much to change with regard to the `.env` loading. If you were a user of [`pipenv`'s environment variables](https://pipenv.pypa.io/en/latest/advanced/#automatic-loading-of-env) to control `.env` loading then you can use the analogous environment variables listed below.\n\nPipenv env var | Poetry env var\n-------------- | ----------------------\nPIPENV_DOTENV_LOCATION | POETRY_DOTENV_LOCATION\nPIPENV_DONT_LOAD_ENV | POETRY_DONT_LOAD_ENV\n\n### Overriding existing environment variables\n\nBy default, this plugin will override existing environment variables. This is because this plugin was built to make onboarding for users coming from `pipenv` as seamless as possible. If you want to prevent existing environment variables from being overridden, you can set the `POETRY_DOTENV_DONT_OVERRIDE` environment variable to `true`.[^2]\n\n[^1]: Python 3.7 is supported only when using Poetry < [1.6.0](https://python-poetry.org/history/#160---2023-08-20), which [dropped support for Python 3.7](https://github.com/python-poetry/poetry/pull/7674).\n[^2]: See [#16](https://github.com/mpeteuil/poetry-dotenv-plugin/pull/16) for background.\n"
  },
  {
    "path": "poetry_dotenv_plugin/__init__.py",
    "content": ""
  },
  {
    "path": "poetry_dotenv_plugin/dotenv_plugin.py",
    "content": "import os\n\nfrom cleo.events.console_events import COMMAND\nimport dotenv\nfrom poetry.console.application import Application\nfrom poetry.console.commands.env_command import EnvCommand\nfrom poetry.plugins.application_plugin import ApplicationPlugin\n\nclass DotenvPlugin(ApplicationPlugin):\n    def activate(self, application):\n        application.event_dispatcher.add_listener(COMMAND, self.load_dotenv)\n\n    def load_dotenv(\n        self,\n        event,\n        event_name,\n        dispatcher\n    ):\n        POETRY_DONT_LOAD_ENV = bool(os.environ.get(\"POETRY_DONT_LOAD_ENV\"))\n        command = event.command\n\n        if not isinstance(command, EnvCommand) or POETRY_DONT_LOAD_ENV:\n            return\n\n        POETRY_DOTENV_LOCATION = os.environ.get(\"POETRY_DOTENV_LOCATION\")\n        io = event.io\n\n        if io.is_debug():\n            io.write_line(\"<debug>Loading environment variables.</debug>\")\n\n        path = POETRY_DOTENV_LOCATION or dotenv.find_dotenv(usecwd=True)\n        POETRY_DOTENV_DONT_OVERRIDE = os.environ.get(\"POETRY_DOTENV_DONT_OVERRIDE\", \"\")\n        DOTENV_OVERRIDE = not POETRY_DOTENV_DONT_OVERRIDE.lower() in (\n            \"true\",\n            \"1\",\n        )\n        dotenv.load_dotenv(dotenv_path=path, override=DOTENV_OVERRIDE)\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[tool.poetry]\nname = \"poetry-dotenv-plugin\"\nversion = \"0.2.0\"\ndescription = \"A Poetry plugin to automatically load environment variables from .env files\"\nauthors = [\"Michael Peteuil <michael.peteuil@gmail.com>\"]\nlicense = \"MIT\"\nreadme = \"README.md\"\npackages = [{include = \"poetry_dotenv_plugin\"}]\nhomepage = \"https://github.com/mpeteuil/poetry-dotenv-plugin\"\nrepository = \"https://github.com/mpeteuil/poetry-dotenv-plugin\"\nkeywords = [\"poetry\", \"poetry-plugin\", \"plugin\", \"dotenv\"]\nclassifiers = [\n    \"Topic :: Software Development\",\n    \"Topic :: System :: Systems Administration\",\n    \"Topic :: Utilities\",\n]\n\n[tool.poetry.dependencies]\npython = \">=3.7,<4\"\npoetry = \">=1.2.0a1\"\npython-dotenv = \">=0.10.0\"\n\n[tool.poetry.group.dev.dependencies]\npytest = \"^6.2.3\"\n\n[build-system]\nrequires = [\"poetry-core\"]\nbuild-backend = \"poetry.core.masonry.api\"\n\n[tool.poetry.plugins.\"poetry.application.plugin\"]\npoetry-dotenv-plugin = \"poetry_dotenv_plugin.dotenv_plugin:DotenvPlugin\"\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_system.sh",
    "content": "#!/usr/bin/env bash\n\nfunction create_dotenv_file() {\n  # Setup .env file so the plugin can do its job\n  echo \"export MY_ENV_VAR='foo'\" > .env\n}\n\nfunction delete_dotenv_file() {\n  # Tear down .env file since we no longer need it\n  rm -f .env\n}\n\nfunction test_end_to_end_system_with_default_dotenv_file() {\n  # Setup\n  local expected\n  expected='foo'\n  create_dotenv_file\n\n  local output\n  output=$(poetry run python -c \"import os; print(os.environ['MY_ENV_VAR'])\")\n\n  # Cleanup\n  delete_dotenv_file\n\n  if [ \"$expected\" = \"$output\" ]; then\n    printf \"test_end_to_end_system_with_default_dotenv_file: PASSED\\n\"\n  else\n    printf \"Expected '$expected', but got '%s'.\\n\" \"$output\"\n    exit 1\n  fi\n}\n\nfunction test_end_to_end_system_with_dotenv_location_override() {\n  # Setup\n  local expected\n  expected='bar'\n  local new_dotenv_path\n  new_dotenv_path=\"$PWD/tests/tmp\"\n  create_dotenv_file\n\n  # Override the file that was just created\n  mkdir -p \"$new_dotenv_path\" && echo \"export MY_ENV_VAR='bar'\" > \"$new_dotenv_path/.env\"\n\n  local output\n  output=$(export POETRY_DOTENV_LOCATION=\"$new_dotenv_path/.env\" && poetry run python -c \"import os; print(os.environ['MY_ENV_VAR'])\")\n\n  # Cleanup\n  rm -rf \"$new_dotenv_path\"\n  delete_dotenv_file\n\n  if [ \"$expected\" = \"$output\" ]; then\n    printf \"test_end_to_end_system_with_dotenv_location_override: PASSED\\n\"\n  else\n    printf \"Expected '$expected', but got '%s'.\\n\" \"$output\"\n    exit 1\n  fi\n}\n\nfunction test_end_to_end_system_with_default_env_overrides() {\n  # Setup\n  local expected\n  expected='foo'\n  create_dotenv_file\n\n  local output\n  output=$(export MY_ENV_VAR='bar' && poetry run python -c \"import os; print(os.environ['MY_ENV_VAR'])\")\n\n  # Cleanup\n  delete_dotenv_file\n\n  if [ \"$expected\" = \"$output\" ]; then\n    printf \"test_end_to_end_system_with_default_env_overrides: PASSED\\n\"\n  else\n    printf \"Expected '$expected', but got '%s'.\\n\" \"$output\"\n    exit 1\n  fi\n}\n\nfunction test_end_to_end_system_without_env_overrides() {\n  # Setup\n  local expected\n  expected='bar'\n  create_dotenv_file\n\n  local output\n  output=$(export MY_ENV_VAR='bar' POETRY_DOTENV_DONT_OVERRIDE=true && poetry run python -c \"import os; print(os.environ['MY_ENV_VAR'])\")\n\n  # Cleanup\n  delete_dotenv_file\n\n  if [ \"$expected\" = \"$output\" ]; then\n    printf \"test_end_to_end_system_without_env_overrides: PASSED\\n\"\n  else\n    printf \"Expected '$expected', but got '%s'.\\n\" \"$output\"\n    exit 1\n  fi\n}\n\nfunction test_end_to_end_system_without_loading_dotenv_file() {\n  # Setup\n  local expected\n  expected='Nonexistent Variable'\n  create_dotenv_file\n\n  local output\n  output=$(export POETRY_DONT_LOAD_ENV=true && poetry run python -c \"import os; print(os.environ.get('MY_ENV_VAR', '$expected'))\")\n\n  # Cleanup\n  delete_dotenv_file\n\n  if [ \"$expected\" = \"$output\" ]; then\n    printf \"test_end_to_end_system_without_loading_dotenv_file: PASSED\\n\"\n  else\n    printf \"Expected '$expected', but got '%s'.\\n\" \"$output\"\n    exit 1\n  fi\n}\n\ntest_end_to_end_system_with_default_dotenv_file\ntest_end_to_end_system_with_dotenv_location_override\ntest_end_to_end_system_with_default_env_overrides\ntest_end_to_end_system_without_env_overrides\ntest_end_to_end_system_without_loading_dotenv_file\n"
  }
]