requires¶
Install: pip install requires
Decorate that lets you Require/Import dependencies at runtime.
Python dependency management can be mind bottlingly complex. Optional dependencies are pretty common. Why not require the dependency at run time if a function requires said dependency?
This package has come in handy in lambda-land where you only get 250mb (on aws)!
Usage:¶
In [1]:
Copied!
# This will fail
def uno():
return json.dumps({"a": 1, "b": 2})
try:
uno()
except NameError as ne:
print("Error:", ne)
# This will fail
def uno():
return json.dumps({"a": 1, "b": 2})
try:
uno()
except NameError as ne:
print("Error:", ne)
Error: name 'json' is not defined
In [2]:
Copied!
# This will not fail
import requires # Module is callable! (checkout funkify for more info -- `pip install funkify`)
@requires("json")
def uno():
return json.dumps({"a": 1, "b": 2})
uno()
# This will not fail
import requires # Module is callable! (checkout funkify for more info -- `pip install funkify`)
@requires("json")
def uno():
return json.dumps({"a": 1, "b": 2})
uno()
Out[2]:
'{"a": 1, "b": 2}'
In [3]:
Copied!
import requires
@requires("from json import dumps")
def uno():
return dumps({"a": 1, "b": 2})
uno()
import requires
@requires("from json import dumps")
def uno():
return dumps({"a": 1, "b": 2})
uno()
Out[3]:
'{"a": 1, "b": 2}'
In [4]:
Copied!
def dos():
return dumps({"a": 1, "b": 2})
dos()
def dos():
return dumps({"a": 1, "b": 2})
dos()
Out[4]:
'{"a": 1, "b": 2}'
In [5]:
Copied!
import requires
@requires(_from="json", _import="dumps")
def dos():
return dumps({"a": 1, "b": 2})
dos()
import requires
@requires(_from="json", _import="dumps")
def dos():
return dumps({"a": 1, "b": 2})
dos()
Out[5]:
'{"a": 1, "b": 2}'
In [6]:
Copied!
import requires
@requires(_import="rapidjson", pip="python-rapidjson", conda_forge="python-rapidjson")
def tres():
return rapidjson.dumps({"a": 1, "b": 2})
tres() # Will err if not install with where to install instructions
import requires
@requires(_import="rapidjson", pip="python-rapidjson", conda_forge="python-rapidjson")
def tres():
return rapidjson.dumps({"a": 1, "b": 2})
tres() # Will err if not install with where to install instructions
Out[6]:
'{"a":1,"b":2}'
In [7]:
Copied!
# should error
def quatro():
return path.join("a", "b")
try:
quatro()
except NameError as ne:
print("ERROR:", ne)
# should error
def quatro():
return path.join("a", "b")
try:
quatro()
except NameError as ne:
print("ERROR:", ne)
ERROR: name 'path' is not defined
In [10]:
Copied!
from requires import Requirement
os_path_req = Requirement(_import="path", _from="os")
@os_path_req
def quatro():
return path.join("a", "b")
assert isinstance(quatro(), str)
from requires import Requirement
os_path_req = Requirement(_import="path", _from="os")
@os_path_req
def quatro():
return path.join("a", "b")
assert isinstance(quatro(), str)
Enforcing requirements¶
In [18]:
Copied!
import requires
try:
import alibrary
except ModuleNotFoundError:
requirement = requires.Requirement(
_import="alibrary",
pip=True,
conda_forge="alibrary-conda-listing",
details="Install details",
)
try:
requirement.raise_error()
except requires.RequirementError as err:
print("ERROR:")
print(err)
import requires
try:
import alibrary
except ModuleNotFoundError:
requirement = requires.Requirement(
_import="alibrary",
pip=True,
conda_forge="alibrary-conda-listing",
details="Install details",
)
try:
requirement.raise_error()
except requires.RequirementError as err:
print("ERROR:")
print(err)
ERROR: Module/Package(s) not found/installed; could not import: `import alibrary` pip install alibrary conda install -c conda-forge alibrary-conda-listing Install details
Less verbose version:¶
import requires
try:
import alibrary
except ModuleNotFoundError:
requires.Requirement(
_import='alibrary',
pip=True,
conda_forge='alibrary-conda-listing',
details="Install details"
).raise_error()
Future ideas?¶
- Adding support for requiring particular package versions?
- Auto install?
- Allow non pip/conda/conda-forge locations?