Skip to main content

Declare your python dependencies inside your scripts

Project description

envless: a python utility for running scripts with dependencies declared inline

Python scripts are great and useful, but for simple tasks that require a dependency or two, it can be annoying to manage virtualenvs. This is especially annoying if you want to write the scripts to manage your dev environment in python.

envless provides a self-contained way for python scripts to declare and load their dependencies. To make the idea clearer, here's an example script that fetches and prints the python.org site:

import envless

envless.script_dependencies({"requests": "==2.28.2"}, __file__)

import requests

response = requests.get("https://python.org")
print(response.text)

In short, this will run the script, installing requests if needed, so that you don't need to have it preinstalled or set up a virtualenv or anything first. If this script is called show_python.py, then you just run python show_python.py, and it works!

This is heavily inspired by how deno and go automatically determine dependencies based on the source code rather than declaring them manually in a separate file.

Installation

The only requirement is that you need to be able to import envless when you're running the python you want to use for the script. This usually means that you should pip install --user envless.

If you have multiple versions of python on your system, this means you should install with the corresponding pip. So if your system default python is 3.8, but you also have 3.11 installed, and you want to run with 3.11, you might need to pip3.11 install --user envless and then python3.11 <script> to run your script.

envless should always support all currently supported python versions, except python3.7, which is about to go end-of-life at the time of writing this package.

How it works

The script_dependencies function turns the requirements dict into a requirements.txt tempfile. It then hashes that tempfile and the running python version to get a version ID, creates a virtualenv with that ID if needed, and installs the dependencies into that virtualenv. Then it execs the current interpreter with that virtualenv active so that the dependencies are available to the script.

Note that this implies that the dependencies do not contaminate your global environment, and also that virtualenvs can be shared among scripts with the same dependency declarations (so don't go messing with them manually).

If you want to clear out old envs, they live in your platform's equivalent of ~/.local/share/envless/virtualenvs. It should always be safe to delete this directory if there isn't a script actively running; envs will be recreated as needed.

API

envless.script_dependencies: the only function in the package you should need to use from your code.

Args:

  • requirements: a dict where keys are package names that can be installed via pip and values are version specifiers for those packages (again, any version specifier that pip can handle). If you don't care about the version you get, just pass "" as the version specifier.
  • source_file: the path of the file that is calling this function. You should always just pass the python builtin variable __file__ for this argument.

Examples

See the tests dir, which contains scripts that use envless.

Limitations

Your call to envless.script_dependencies must come before you import any code outside the standard library.

envless only works well when used in the script that you're using as an entrypoint. Importing another script that uses envless will end up executing that other script as the entrypoint, which is probably not what you want. If you think you might need to import a script that uses envless, you can put the call to envless.script_dependencies inside an if __name__ == "__main__": block (which still must occur prior to any imports outside the standard library). For example:

if __name__ == "__main__":
    import envless
    envless.script_dependencies({"requests": "==2.28.2"}, __file__)

import requests

response = requests.get("https://python.org")
print(response.text)

Note, however, that this means that the script doing the importing is responsible for providing all the dependencies; in this example, requests will not be installed automatically if the script is not the entrypoint.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

envless-0.2.0.tar.gz (5.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

envless-0.2.0-py3-none-any.whl (4.7 kB view details)

Uploaded Python 3

File details

Details for the file envless-0.2.0.tar.gz.

File metadata

  • Download URL: envless-0.2.0.tar.gz
  • Upload date:
  • Size: 5.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.15 CPython/3.8.16 Darwin/22.3.0

File hashes

Hashes for envless-0.2.0.tar.gz
Algorithm Hash digest
SHA256 574fd93b7b2af72592f99ba300be48a17a619dccec358b0addc346668229bd57
MD5 d0f3a1668b4d95479cf45a21acd738d4
BLAKE2b-256 a925d3363087f47dfb19831ca7f68f56032c793cc3c36ff2b61afdfb33f058a4

See more details on using hashes here.

File details

Details for the file envless-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: envless-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 4.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.15 CPython/3.8.16 Darwin/22.3.0

File hashes

Hashes for envless-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 048544e9e8a61faab08ed6c4dfc25e3b0aec01afef515eb6baa99b89ef0c1e59
MD5 e99eb248d281151af4061f0db25128aa
BLAKE2b-256 185eb257cfdf9b3cb86b1edf8b6be8e24e3366d00a36e9019459922dea2eff6f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page