Comments (51)
@ssnkhan stash pip does not handle path configuration for sub-packages. It is however easy to fix by moving the thirdparty
folder to directly under site-packages
.
from stash.
@briarfox My opinion is to use stash modules as much as possible to avoid repetition. I do realise that the current shell script is quite limited due to lack of program control constructs. So I am not sure how much functionality the pip module would have. I am still thinking about the possibility to interleave python code in a shell script so the shell script can be more useful.
from stash.
Ok currenly pyhonisa sie-packages does no load .pth files ( it's not in the site path list) I am wondering what the best way to handle packges is. When downloading a pypi package there is the root folder which usually contains documentation, examples and the acual package. The acual package needs to be in site-packages direcly. So the question is do we keep he documentation/examples and if so where?
Options:
- Move the package folder into site-packages, delete root folder.
- Keep the root folder in site-packages and move the package folder into site-packages as well.
- Create a pypi_packages folder inside of site-packages. Store root package folder there. Move package folder into site-packages.
- Same as 3 but put the pypi_packages folder in documents and add the package folder to site-packages.
- currently wont work Put the root package folder inside site-packages. Create a pypi_path.pth file and append each package location.
from stash.
Another option: for each top level package (can a pypi contain more than one?), create a .py file in site-packages with that name. That py would then redirect any imports to the proper location, under the root wherever you place it. See below for an example..
In this example, typing
import myModule
first imports site-packages/myModule.py
. But that script below tries to import myModule, starting at the root, in this example '~/Documents/myModule-1.0/`. If successful, it points sys.modules to whatever it imported. Importing hierarchical packages work as expected, because of how the import system works. To make things truly transparent probably requires mucking with the traceback if an ImportError occurs, to make it seem as if the script in site-packages was not the caller.
# site-packages/myModule.py
# import myModule will import this script first, but then will end up importing
def _do_import(p):
import sys, os, imp
m=imp.find_module(__name__)
path=os.path.expanduser(p)
module_path = imp.find_module(__name__,[path])
if module_path:
try:
module = imp.load_module(__name__,*module_path)
except ImportError:
raise #maybe fake traceback?
sys.modules[__name__]=module
else:
pass
#. What to do if package not found anymore? Haven't tested...
# maybe del sys.modules[__name__] so it doesn't point back here?
# maybe raise an ImportError?, which maybe does the same thing
_do_import('~/Documents/myModule-1.0/')
pip could write out this script, just substituting the proper path.
Alternatively, you could be a little more generic, and always write the same file. That file would be a slight variation of the above, except instead of providing the path explicitly, it would scan site-packages for .pth files, then provide that path list to find_module
from stash.
@briarfox I would prefer to simply use Option 1, i.e. move the actual package folder directly under site-packages
. As I understand it, this behaviour is more in line with what the real pip does:
- Copy the actual package folder directly under site-packages
- Creates some metadata information under an egg-info directory. We don't really need this, but if you really want it, a possible solution is to parse the
setup.py
file (mainly to get the description, author, contact etc.) - The original doc and examples are not kept anyway.
An additional useful feature is make pip keep track of what packages were installed by it.
Stash can manage its own python path. In fact, I am going to add a PYTHONPATH
environment variable so that additional path can be added on top of Pythonista default path. The downside of this approach is that the packages will only be available when Stash is running. So I only plan to use it for helper libraries, e.g. a lib
folder under stash
folder which contains some helper function such as unexpanduser
(i.e. these functions are only meant to be used from within stash).
@jsbain your approach is indeed quite clever. But for this issue, I kinda think a simple approach is viable.
from stash.
@ywangd Going with Option 1. It turns out that pypi does use .zip as well. I should have that added in tonight and will get a working pull request up. I agree that it would be useful to have pip keep track of packages installed through pip. Having the ability to update, list and remove packages would be handy. I'll work on that next.
@jsbain Clever script, thanks.
from stash.
Current pull request of pip uses the common package naming conventions but I'm finding packages that do not use the standard. It looks like I'll need to parse setup.py to find the package folders.
from stash.
@briarfox I noticed the same issue when trying to install github3.py. So it is probably necessary to somehow parse the setup function (mainly to get the packages
argument).
@jsbain Regarding to your idea about letting pip
handle github package installation, I personally think the github package handling deserves its own command as pypi and github behaves quite differently. It would be ideal to have a github command that also does the search, (release) versions, download etc. through formal GitHub APIs ( the one I am thinking to use right now is github3.py).
With that being said, I do agree that since both pypi and github manage packages, they should be somehow unified to simply the overall user-experience. So maybe add a wrapper function , e.g. require()
, as an entry point to call either pypi or github. This function will be located in the lib
folder (#5) of stash. It seems to me that this approach is more modular and easier to maintain down the path.
Thanks!
from stash.
@ywangd @dgelessus I'm running into issues with parsing setup.py. The average setup.py is easy to parse:
setup(name='somepackage', packages = [somepackage], etc
However there are may ways to pass params to setup.py. example:
NAME = 'somepackage' PACKAGES = [somepackage'] params = dict(name=NAME,packages=PACKAGES) setup(**params)
How can we handle all the different syntax? If I could just mock setup to return a dict of the params I'd be set. However I cant import or execfile setup.py becuase of the setuptools/distutils imports.
from stash.
How about exec
ing the code in an environment with a modified __import__
function that returns simple dummy modules for setuptools and distutils? The fake setup
function could assign its **kwargs
to some other attribute accessible from outside, which could then be read afterwards.
from stash.
@ywangd I was thinking specifically of pypi packages that are hosed on github, so have a setup.py, etc, and look identical to the real pypi modules except their source ( and in many cases I think pypi points to a github archive for the actual download!). The use case would be forked versions needed to run on pythonista. I agree a separate mechanism might be needed for true github modules that don't have setup.py.
@dgelessus That is similar to the approach used by @pudquick for pipista v2, though he served an actual slimmed down version of setuptools with mods for the pythonista environment. Note that this script would need a lot of updates for pythonista 1.5+, since xmlrpclib is already installed, etc. also, as I recall there were issues in using exec script in g
inside of a function, breaking some setup.py that had imports, though exec script in g,g
did work as expected.
Another question.... What prevents running setup.py in general? 1) missing _osx_support.py 2) some errors in getting some sysconfig parameters, because pythonista lies about some paths. 3) And maybe some other issues.
I think I was recently able to get a package to install by patching a few distutils functions which were raising exceptions, modifying the offending sysconfig parameters, and providing a minimal _osx_support.py. At the time I didn't see much value in that approach, but I forget why...
from stash.
Neat. Didn't know this project existed. Thanks for the mention.
I did a custom setuptools with shortcircuited code in it because it expected an environment where some kind of alternate process spawning was possible.
Not all python modules are pure python and setuptools didn't have native support for detecting the (jailed/sandboxed) Pythonista environment, thereby knowing to fail if compilation was required.
I tried to wanted to just "let it fail", but the exec bug didn't let a core piece of the logic work.
So I resorted to basic heuristics where most modules contained a single modulename.py or modulename/ folder and just extract -> installed them. It was on the user to know if it would work or not.
I may have to look into this again :)
from stash.
@jsbain I get your point now. I agree this specific use case of GitHub repo shares a lot similarity with pypi. This is indeed the situation of the external libraries that the git
command depends on.
from stash.
@briarfox
Here is a solution I came up with based on all previous discussions. The key idea is to fake the setuptools
module and execute the pakcage's setup.py
file. Compared to @pudquick 's approach, one difference is that the fake is more light weighted as the faked module is created programmatically instead of from files. Another difference is that the setup()
function is now provided by pip
. So once the setup.py
is executed. the installation is mostly completed.
A few things to note are:
- The sample code is not a complete
pip
. It focus only on howsetup.py
can be executed with the faked modules, not actually install it. Thesetup()
function needs to be expanded to contain actual installation code. - github3.py is used as the test case for the code.
The sample code is as follows:
import sys
import os
from types import ModuleType
def make_module(new_module, doc="", scope=locals()):
"""
modified from
http://dietbuddha.blogspot.com.au/2012/11/python-metaprogramming-dynamic-module.html
make_module('a.b.c.d', doc="", scope=locals()]) -> <module built-in="built-in" d="d">
* creates module (and submodules as needed)
* adds module (and submodules) to sys.modules
* correctly nests submodules as needed
* not overwritting existing modules (my modification to the original function)
"""
module_name = []
for name in new_module.split('.'):
m = ModuleType(name, doc)
parent_module_name = '.'.join(module_name)
if parent_module_name:
if parent_module_name not in sys.modules.keys(): # do not overwrite existing modules
print 'creating parent', parent_module_name
setattr(sys.modules[parent_module_name], name, m)
else:
if m not in scope.keys(): # do not overwrite existing modules
scope[name] = m
module_name.append(name)
name_path = '.'.join(module_name)
if name_path not in sys.modules.keys(): # do not overwrite existing modules
sys.modules[name_path] = m
return sys.modules['.'.join(module_name)]
def setup(*args, **kwargs):
print kwargs['packages']
# NOTE: pip installation code here
# e.g. _stash('mv package_folder ~/Documents/site-packages/package_folder') etc.
pass
saved_modules = sys.modules
saved_cwd = os.getcwd()
try:
# pip code here (download and unzip)
# Fake the setuptools modules so setup.py can run
# fake from setuptools import setup
st = make_module('setuptools')
st.__dict__['setup'] = setup # the custom setup function will perform the installation
# more sub-modules to fake
# fake from setuptools.command.test import test
test = make_module('setuptools.command.test')
test.__dict__['test'] = type('test', (), {}) # dummy class so setup can run
os.chdir('TOP_LEVEL_FOLDER_of_the_UNZIPPED_PACKAGE')
execfile('setup.py')
finally: # remove the fake modules
sys.modules = saved_modules
os.chdir(saved_cwd)
from stash.
I do realise above code has some limitations:
- The faked modules, sub modules and functions have to be manually added. For now it only deals with
from setuptools import setup
andfrom setuptools.command.test import test
. These two imports seem to cover a great number of packages. - This approach as well as the entire
pip
command work only for pure Python packages. I think this is fine as packages require compilations are out of scope imo.
from stash.
@ywangd looks good, thanks. I should have an update today.
from stash.
@pudquick Did you want to handle pip for stash? I used pipista for reference. I've been sick and have a new born so my time coding has been greatly reduced. If you'd like to take it over let me know, no issues if you scrap my pip version.
from stash.
@briarfox Please take time to rest and look after the baby. No pressure here at all.
from stash.
@yawngd Thanks. I'll keep working at it, but its slow going. Figured if @pudquick wanted to work on it, that be fine.
Do we want pip handleing setup.py or would that be more appropriate for the python module? Since users might like to install a script without pip by python setup.py install.
from stash.
@briarfox I would prefer to let pip
handle setup.py
. Because what we do here really is to fake the install process by hijacking the normal execution of setup.py
. It is not really a true equivalent to python setup.py install
in my opinion.
I just realised @pudquick is the original author of shellista. Thanks for the inspiration on getting me started on StaSh.
from stash.
@ywangd I'm finding a wierd issue with python cwd. it seems that using the cd module is different then using os.chdir(). I'm finding that I need to use _stash('cd') to manipulate paths when jusing stash modules and os.chdir() for any paths needed outside of a stash module.
example:
#example 1 cwd ~/Documents #Change directory with cd module _stash('cd ~/Documents/site-packages') _stash('tar -xzf ~/Documents/site-packages/some_file.tar.gz) #tar extracts to current dir #This results in the unarchived file in Documents/site-packages #example 2 cwd ~/Documents os.chdir(os.path.expanduser('~/Documents/site-packages')) _stash('tar -xzf ~/Documents/site-packages/some_file.tar.gz) #This results in tar extracting into Documents/
from stash.
@ywangd The setup.py is running with mixed results. Simple setup.py files work great but more complicated ones seem to run into a lot of import errors, even when the package works in pythonista. This is my current thought, let me know what you think.
First we look for common module naming. Such as mymodule, mymodule.py. If found, simpley move folder/script. If not found, then try to run setup.py
from stash.
@briarfox The answer to the cd
issue quite involved. A general rule is that you cannot mix the use of _stash('cd XXX')
and os.chdir('XXX')
.
In your two examples, they actually both correctly extract archives to ~/Documents/site-packages
. But I guess in your real code there may be a _stash('cd XXX')
comes before the os.chdir
in the 2nd example. This would cause the extraction goes in to the wrong place.
The reason is stash keeps track of its own cwd for each sub-shell. If no _stash('cd xxx')
has to been called, the cwd is equal to the system's cwd. But once a _stash('cd xxx')
command is called, stash records it and use xxx
as the cwd onwards (subsequent os.chdir
will then have no effect on other stash command).
This behavior is to simulate the sub-shell environment where cwd changes in sub-shell does not affect its parent shell. I have to admit this may not be the best design as I sometimes get confused by my own code. But if you stick to use _stash()
command, things should be more consistent.
from stash.
@briarfox I agree with you that we can try simple module names first before resorting to execute setup.py
.
Could you please given me an example of the more complicated setup.py
. I'd like to see if there is chance to remedy failed imports on the fly.
from stash.
@ywangd Would I be better off sticking to using os.chdir() instead of _stash('cd ...')?
Two of the modules that I've tried are scapy and Twisted. The current Twisted does not work in pythonista but I believe it will after next pythonista update. We could try to stub in other modules that are missing, but it seems that most cases can be solved by looking for the package directory.
from stash.
@briarfox As long as you use the same function to manipulate directory, it should be fine. I personally would prefer to use _stash('cd ...')
. Because other commands needs to be executed by stash anyway, I kinda think it is better to allow stash keep track of all the information.
I had a look at the two modules. Yes the import processes really vary quite a bit. It is probably too much bandage work to cater all of them.
from stash.
@briarfox Another reason to use _stash('cd')
over os.chdir()
is that a command, e.g. pip
, usually does not want affect parent shell's cwd once it is finished, i.e. Users normally do not expect their cwd gets changed after calling pip
. If os.chdir()
is used, pip
has to keep track of it and revert back to the original cwd once it is finished. These tasks will be handled automatically if _stash('cd')
is used.
from stash.
Does this version of pip attempt to handle dependencies in any way? If it is possible to read the required dependencies from the setup.py file, it might be useful to at least check if the dependency is part of default Pythonista or found in site-packages
, and if not print a warning.
from stash.
@dgelessus It currently does not install dependencies. It will attempt to load the module and print out a warning on possible dependencies if failed. I'd really like to grab dependencies but there are many ways to use setup.py so simplely parsing it is not a guarantee. If we could just find a way to handle majority of setup.py imports it would be easy to rely on setup.py working. I'll look into at least displaying the needed dependencies, if i can't auto install them.
I'm still working on adding 3rd party github packages.
from stash.
@ywangd re: shellista inspiration - you're welcome :)
from stash.
So. Diving back into this (whee).
pip is an exceedingly complex tool. But honestly, I only ever use a fraction of the functionality of it. Really what I want is the ability to: find, download, unpack, and install a package from PyPI
When I was attempting to do this before, I came to the realization that pip (or at least the pieces I was using of it) only was really handling the search/download/unpack part. The install was still being handled by setuptools.
To see what it's doing in the handoff, do the following:
- run python (cpython, not Pythonista) on a system:
python -c 'import pip; print pip'
- Check the directory that pip is installed into
- Search the file contents of that module directory for:
def call_subprocess
- Depending on which version of pip you have, it could be defined in one of several files
- Right after the function definition, you'll probably see this as the first line of code:
if command_desc is None:
- At the same level of indentation, right before it, add one more line of code, so it looks like this:
print cmd.__repr__()
if command_desc is None:
- To trigger what I'm talking about, then install a package with pip. Here's an example:
sudo pip install beautifulsoup4
(If it's already installed, you may need to uninstall first - or use "install -I" to ignore its presence)
You will get the commands that pip (after finding, downloading, unpacking, and analyzing the package) sends to python to kick off the install process.
Here's example output from beautifulsoup4:
Collecting beautifulsoup4
Downloading beautifulsoup4-4.3.2.tar.gz (143kB)
100% |################################| 143kB 1.6MB/s
['/usr/bin/python2.7', '-c', "\n__file__ = '/tmp/pip-build-YtDF6D/beautifulsoup4/setup.py'\nfrom setuptools.command import egg_info\nimport pkg_resources\nimport os\nimport tokenize\ndef replacement_run(self):\n self.mkpath(self.egg_info)\n installer = self.distribution.fetch_build_egg\n for ep in pkg_resources.iter_entry_points('egg_info.writers'):\n # require=False is the change we're making:\n writer = ep.load(require=False)\n if writer:\n writer(self, ep.name, os.path.join(self.egg_info,ep.name))\n self.find_sources()\negg_info.egg_info.run = replacement_run\nexec(compile(\n getattr(tokenize, 'open', open)(__file__).read().replace('\\r\\n', '\\n'),\n __file__,\n 'exec'\n))\n", 'egg_info', '--egg-base', 'pip-egg-info']
Installing collected packages: beautifulsoup4
Running setup.py install for beautifulsoup4
['/usr/bin/python2.7', '-c', "import setuptools, tokenize;__file__='/tmp/pip-build-YtDF6D/beautifulsoup4/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec'))", 'install', '--record', '/tmp/pip-rHy2y4-record/install-record.txt', '--single-version-externally-managed', '--compile']
Successfully installed beautifulsoup4-4.3.2
As you can see, pip essentially "bows out" of the process. It's generated a temporary script that's passed to python as the -c argument which relies on only setuptools from that point onwards.
Basically, if you're building a pip equivalent - or at least trying to cover 80%+ of the functional code involving downloading from PyPI, unpacking, and installing - then really you only need:
- Searching PyPI
- Unpacking the archived file
- Triggering install using setuptools
The hard part I was running into before and I'm seeing again (now that I'm revisiting it) is controlling the installation so that it doesn't muck up your globals() and locals(), since we only have one running python interpreter instance. pip on a normal system (aka not Pythonista) solves this by running a new separate instance of python.
If we can keep that segmented (if we care about that, even), we can probably patch around the rest. For instance: I already know how to control / redirect the directory that setuptools will attempt to install the package into :)
from stash.
@pudquick I do not believe we have access to setuptools. We had tried to mock distutils, setuptools but the list is long. It works great on simple packages but it was getting rather cumbersome on more complet setup.py files. The current pip handling:
- Check for a folder inside the archive of the package. This is pretty common, so we simply move that folder into site-packages.
- Look for the package name in a src folder, if found move that folder into site-packages.
- When the above two fail, we try to run setup.py to grab the packages, py_modules and scripts variables.
It would be great to get a working setuptools and distutils.
from stash.
@pudquick Thanks for your explanation.
I haven't spent much time on this topic. So I don't quite understand what exactly you mean by "muck up globals() and locals()". Is it possible to run the script with a copy of globals() and locals()? e.g. execfile('filename', dcit(globals()), dict(locals())
so that the original namespace will not be changed?
I did notice that pip is a wrapper of setuptools, which in turn is a wrapper of distutils. So only implementing pip is not going to solve the whole problem as Pythonista does not have full functional distutils
module. The most used function in pip is setup()
, which is a function from distutils
and not available in Pythonista.
What I think is that if we can intercept the call to setup()
, we can get most if not all information required to install the module. For pure python modules, we will then be able to find the actual files/directories need to be copied over.
from stash.
@briarfox I like your pip module so far :)
Here's a different take on it: https://gist.github.com/pudquick/cb7b6413a54162fd1c00
Try it out as 'pip2.py' if you want to see it in action. It's not a complete implementation, but vanilla 'install' is functional. Mine's not stash-specific, so it carries its own support for handling gzip / tar / zip files (makes up about 50% of the code in itself).
But it's got progress indicators for download (with current speed), its own method for parsing setup.py (I split out the 'setup(...)' call and then dummy out up to a max of 10 undefined object names), plus it safely contains modifications to global/local variables by setup.py.
I've got additional ideas for handling setup.py that can probably increase its parsing resilience, but as it's written right now, it's confirmed as able to install simple packages.
If anything in there is helpful, grab what you like.
from stash.
@pudquick
I had some quick tries using the script from within stash. Here are the findings:
- The script throw an error "operation not permitted". I think it is caused by the
tmp_dir
creation which is not allowed in Pythonista. I made a minor change and it now works in Pythonista (or any iOS, OS X):tmp_dir = os.environ['TMPDIR']
- I do like how it shows the progress bar and speed. I may grab them for
wget.py
if that's OK. - I have yet to read through the code and see how it works and understand your explanation. I tried to install a package called uritemplate, but it gave an error as "unable to simply parse setup.py"
- To make the script easily accessible in Stash, I have added its link to the "Pythonista Command Script Index". So it can be easily installed and managed in stash using
pcsm install pip-mini
(can also trypcsm list
andpcsm info pip-mini
).
from stash.
@ywangd Sorry about that (the first error)! Just updated the code, should be fine now.
It intentionally makes temp files in __pip_tmp because the intent, later, is to provide an option to preserve the temporary directory when module download succeeds but parsing fails (allowing for a manual option / seeing where it failed).
By all means grab what code you like.
As for the other error you ran into - it indicates there's code outside of the setup(...) block in setup.py necessary for building the 'packages' dict key. I want to try some other tricks before resorting to naively executing setup.py. Pretty sure I can tweak better performance out of it.
from stash.
@pudquick Great! I'll have a look at it when I get to work.
from stash.
@ywangd @briarfox Updated mocking/dummy capabilities.
There is now a '_dummy' global object it creates that can act like an object with attributes or even like a function. You can do any of the following with a _dummy object:
something = _dummy
something = _dummy.arbitrary_attribute
something = _dummy['arbitrary_key']
something = _dummy(...)
(returns the _dummy object)something = _dummy.arbitrary_function(...)
(returns the _dummy object)
This stubs out most "key = " actions in setup(...).
Also replaced the built-in open(...) with a version that, if unable to open a particular file it returns a _dummy object instead.
@ywangd: This makes it successfully install 'uritemplate' now, for example, which had setup(...) lines like:
version = uritemplate.__version__,
url = base_url,
download_url = '%starball/uritemplate-py-%s' % (base_url, uritemplate.__version__),
long_description=open("README.rst").read(),
from stash.
Looking at the pip module lines 281 ff, I wondered why you chose to prefer manual unpacking of modules (for instance _stash('mv ~/Documents/site-packages/{basename}/{name} ~/Documents/site-packages/{name}'.format(basename=dir_name,name=package_name)
) to calling the fake setup module. The setup module at least honors some of the settings that are encoded in the setup.py file, while the other methods just make educated guesses.
I would like to suggest to prefer the setup method to the others if a setup.py file can be found.
Georg
from stash.
if you look through the history, pip has gone through multiple iterations. at one time the fake setup was used.... the problem is that pythonista has a funny folder system, and some of the places setup would try to install things are not writable.
that said, pip does routinely fail on some modules... if you can figure out ways to make it more reliable, i think pull requests are welcome!
from stash.
@jsbain Thanks, I think I'll have a look at how to improve pip. No promises though...
One more questions: pip has code snippets such as _stash('echo Removing setup files.')
Any particular reason why this does not use print()
?
Georg
from stash.
You can use print
instead and it should be faster.
from stash.
Finally come back to this topic ...
I have just largely rewrite the pip
command. It nows handles dependencies and also install from github.
The major change is that pip
now always try executing the setup.py
file first (instead of guessing the source directory). It works in most cases for me. It even works for when the setup call is something like
setup(**kwargs)
or
setup(**get_my_kwargs())
or
setup(packages=find_packages())
This is made possible by parsing the setup file into AST and modify AST to hijack the setup call. So the setup file pretty much runs normally until it reaches the setup()
call, where the program flow is then redirected to a stub function. The stub function then records the passed arguments and acts accordingly. This approach seems to work well for all pure Python packages. Only one exception I found is crypto-enigma
which has a broken setup file (messed up dependencies). So it is not really the pip
's fault. The new code still falls back to package directory guessing when execution of setup file fails. So it does not lose any functionalities compared to the old version.
Try pip install boto3
and you'll see how it works.
Also try pip install selectel/pyte
to install pyte from its github repo.
This change is now available in both dev
and py3
branch and you can selfupdate
to get it.
from stash.
Thank you for your efforts with pip. I installed oletools (installed within /site-packages/oletools/), but when executing a python script (such as mraptor.py), I am presented with the following error:
stash: <type 'exceptions.ImportError'>: No module named thirdparty.xglob
The thirdparty directory exists within the oletools folder, suggesting that the toolkit was correctly installed. I suspect this is more likely to be a path issue. Can anyone offer any guidance please?
from stash.
Thank you @ywangd. This makes some scripts work (such as olevba.py), however, some tools, existing at the same location as /olevba.py (such as /mraptor.py) throw up the following error:
stash: <type 'exceptions.ImportError'>: No module named thirdparty.xglob
I also find that the auto-complete for scripts only works within the active directory in which the tool is stored - is there anyway I can link these somehow, so that I can accept the script from any directory?
I am taking a foundation in Python at present, so I apologise for what would otherwise be considered a very newbie question.
EDIT: Call script from any location -- solved, I used alias.py and linked the script from there. However, the alias does not persist after Pythonista is closed. How can the alias be made more permanent?
from stash.
The errors can be fixed by add a few settings in .stashrc
file located inside stash's installation root. You can create a new file if it does not exist.
Add following contents to the file:
PYTHONPATH=~/Documents/site-packages/oletools:$PYTHONPATH
BIN_PATH=~/Documents/site-packages/oletools:$BIN_PATH
The first line should solve the import issue and the second line allows you to call the script anywhere with auto-completion. The aliases can also be persistent by add them to this file.
To create this file, you can issue following commands:
cd $STASH_ROOT
touch .stashrc
edit .stashrc
Now you should have this file opened in an editor tab. You'll need to restart StaSh or even Pythonista after you finish typing.
from stash.
Thank you, that works perfectly! Supposing I have other scripts in other directories which I also wish to call from anywhere, how is that best achieved? For instance, I installed balbuzard via pip, and adding the following lines to .stashrc didn't work:
PYTHONPATH=~/Documents/site-packages/oletools:$PYTHONPATH
BIN_PATH=~/Documents/site-packages/oletools:$BIN_PATH
PYTHONPATH=~/Documents/site-packages/balbuzard:$PYTHONPATH
BIN_PATH=~/Documents/site-packages/balbuzard:$BIN_PATH
oletools scripts still auto-complete, but balbuzard ones don't. I have googled this too, but struggling to find the answer, so I appreciate your continued patience with me!
from stash.
It worked for me. Did you try restart Pythonista (i.e. double click Home button and swipe up to remove Pythonista from the task list)?
Also it is possible to add multiple entries in one line as:
PYTHONPATH=~/Documents/site-packages/balbuzard:~/Documents/site-packages/oletools:$PYTHONPATH
BIN_PATH=~/Documents/site-packages/balbuzard:~/Documents/site-packages/oletools:$BIN_PATH
from stash.
@ywangd oletools works, balbuzard refuses to autocomplete. I've tried placing the instructions on seperate lines as well in their short hard form as you've suggested, but while oletools continues to work, balbuzard does not autocomplete. I have killed the app from the dock and checked via cat and the file has saved the commands.
from stash.
Resolved — pardon my stupidity, I was editing the file in ~Documents, rather than $STASH_ROOT! All working now, many thanks :)
from stash.
What are the outstanding tasks to close this issue out?
from stash.
Related Issues (20)
- stash does not run with Pythonista v3.4 Beta HOT 8
- Fix failing pytests
- install eye3d error , "signal only works in main thread" HOT 1
- "[BUG]stash: <class 'stashutils.wheels.WheelError'>: top_level.txt entry 'GPTserver' not found in toplevel directory!" When trying to install the package on pythonista iPad
- Cannot pip install notion-client
- The distutils package is deprecated and slated for removal in Python 3.12
- site-packages-3 is now just site-packages HOT 2
- dev branch is 55 commits ahead, 19 commits behind master branch
- Error launch_stash.py:28 in the latest Pythonista 3 (python3.10) - module ‘plistlib’ has no attribute ‘readPlist’ HOT 3
- pythonista_ui.py isAlive -> is_alive HOT 2
- shruntime.py comment out stderr
- please delete and reinstall pythonista 3.4 to get stash clean install HOT 3
- Pythonista 3.4 Error pip install mysql.connector
- Running ``setup.py`` directly is now deprecated HOT 1
- Error on launch stash on pythonista PY:3.10 HOT 2
- Only first line in .stashrc or first command in a single-line multiple commands separated by ; is executed. HOT 1
- pip install fyiban error
- Pythonista crash during start launch_stash.py HOT 9
- When typing in 'pip install', 'install' autocapitalizes
- Unable to install pyzmq with pip - TypeError("unsupported operand type(s) for +: 'OmniClass' and 'list'") HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from stash.