Requireit is smart on-run package install for your Python code. Basically you add 13 lines of code to the top of your code, switch out import bla
for requireit(['bla'])
, and missing packages get installed on run with pip
.
There are three versions of requireit:
- The full version. It has docstrings and works if you paste it at the top of your code or if you include it.
- The mini version. It's half as small as the full version, but has everything except docstrings and nice formatting.
- The mini inline version, only 13 lines. It is hard-coded so you have to paste it at the top of your code, or do this instead of an import:
exec(open("requireitmini-inline.py", "r").read())
Requireit is easy to use, no matter which version you choose. The mini inline version is recommended.
from subprocess import check_output as A;import sys#git.io/JUVEE
class VersionError(Exception):0
class InstallError(Exception):0
E="Couldn't auto-install ";F=[sys.executable,"-m","pip","install"]
def requireit(B):
for C in B:
J=C if isinstance(C,str)else C[0]
try:from importlib import import_module as L
except ImportError:raise VersionError("β¬π")
try: globals()[J]=L(J)
except ModuleNotFoundError if sys.version_info.minor > 5 else ImportError:
try:A(F+[C]) if isinstance(C,str)else A(F+[C[1]]);globals()[J]=L(J)
except Exception:raise InstallError(E+J)
requireit([["onedrivesdk", "git+https://github.com/OneDrive/onedrive-sdk-python.git"], "shutdown"])
# Requireit automatically imports and installs!
shutdown(time=120)
Use the instructions from earlier. To require something, call requireit
with your list of stuff.
For custom sources, use a sub array. The first item is the name of the library, and the second is the pip command.
Example to install shutdown
and onedrivesdk
:
# Do your other code and add requireit here...
requireit([["shutdown", "shutdown==0.0.1"],
["onedrivesdk", "git+https://github.com/OneDrive/onedrive-sdk-python.git"]])
emailHelpers
, one of your other projects is available on pip. Why isn't requireit
available there too?
Because it wouldn't make sense to install a package that installs other packages.
- I'd appreciate it if you'd contribute to the repo, by letting me know about bugs in issues, by making pull requests that make things better, or just the simple act of
- Bundle
requireit
with your example code for yourpip
package, or with your code for anything that requires something installable frompip
. - Spread the word. If you think
requireit
makes writing and running code easier, tell your friends.
You can use shields.io
for your badges. Here's some URLs for requireit. The first one is longer, and the second one is shorter.
Click to show badge URLs
https://img.shields.io/badge/smart%20dependency%20install-powered%20by%20requireit-099
https://img.shields.io/badge/dependencies-auto--installed-099
https://img.shields.io/badge/dependencies%20auto--installed-by%20requireit-099
Click to show Markdown
[![Smart dependency install powered by requireit](https://img.shields.io/badge/smart%20dependency%20install-powered%20by%20requireit-099)](https://github.com/KTibow/requireit/)
[![Dependencies are auto-installed](https://img.shields.io/badge/dependencies-auto--installed-099)](https://github.com/KTibow/requireit/)
[![Dependencies are auto-installed by requireit](https://img.shields.io/badge/dependencies%20auto--installed-by%20requireit-099)](https://github.com/KTibow/requireit/)
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Looks like it's time for an upgrade! Report an issue if this still happens, even after upgrading.
Click to expand explanation and fix
Requireit uses something I (unoficially) like to call "dynamic variable assignment". Let's look at the source: ```python3 try: if isMain: globals()[libName] = import_module(libName) else: __main__.__dict__[libName] = import_module(libName) ``` This is **very** hacky, but it is still real Python code. Basically, we found out if we were included inline or imported seperately from this: ```python3 isMain = __name__ == '__main__' ``` We get the module as a variable from `importlib`'s `import_module`. Then if we are main, we set the module globally to that name. Otherwise, we import `__main__`, and access its `__dict__`. The thing is, **your lint wasn't built for dynamic variable assignment**. To fix this, and be safe, do something like this: ```python3 shutdown, onedrivesdk = [None] * 2 # Requireit stuff here # Require them if shutdown is None or onedrivesdk is None: print("Error with requireit. Try changing all of this to:") print("import shutdown, onedrivesdk") exit() # Your code here ``` That should make your lint happy!Well, I've designed the requireIt Helper
for that purpose. It's only for development, but it can make things easier.
It uses Import Hooks to intercept when you import a package.
If you import something, and it asks you if you want to install something other than the original thing you imported, say no.
Anyway, here it is:
# requireIt Helper (dev only) https://ktibow.github.io/requireit/#requireit-helper
import sys # Import sys for importing
from importlib.abc import MetaPathFinder # Subclassing
from importlib.util import find_spec # Other imports
importing = False
importingName = ""
class RequireItHelper(MetaPathFinder):
def find_spec(self, fullname, path, target=None): # Import hook for finding
global importing
global importingName
if not importing:
importing = True
importingName = fullname
try:
try:
del sys.meta_path[0] # Remove myself
res = find_spec(fullname) # Try importing
finally:
sys.meta_path.insert(0, self) # Add myself
if res is not None: # If found, return
importing = False
return res
except Exception as e: # If exception, return
importing = False
return None
if (
"._" in fullname
or (importing and importingName != fullname)
or fullname in list(sys.modules.keys())
):
importing = False
return None # Attempt to find internals and not bother asking for install.
shouldinstall = input(
"=== Should I try to install "
+ fullname
+ " with pip because I couldn't import it? (Beware of typosquatting) y/n: "
) # Confirm
if shouldinstall.lower()[0] == "y":
print("Loading pip...")
try:
del sys.meta_path[0] # Remove myself
from subprocess import check_output as pip # Import pip
finally:
sys.meta_path.insert(0, self) # Add myself
pip(
[
sys.executable,
"-m",
"pip",
"install",
input("What is this package called on pip? "),
]
) # Run pip to install
print("Done, I'll try again...")
try:
try:
del sys.meta_path[0]
res = find_spec(fullname)
finally:
sys.meta_path.insert(0, self)
if res is not None:
importing = False
print("Successful import!")
return res
except Exception as e:
res = None
print("Error importing due to this exception:")
print(e)
print("Try manually running pip install " + fullname + ".")
importing = False
return None
if res == None:
print(
"Error importing. Try manually importing or manually running pip install "
+ fullname
+ "."
)
importing = False
return res
importing = False
return None
sys.meta_path.insert(0, RequireItHelper()) # Install requireIt Helper
In a REPL, wrap the whole thing in
exec("""
""")