I am trying to read a string in a python script within vim, but something goes wrong. I do it in a function getting an argument called key, using s = vim.eval("a:key"), but this is a simpler example demonstrating the problem:
:py import vim
:py s = vim.eval("'foo'")
:py print s # this prints 'foo' (without the quotes)
:py if s is 'foo': print 'yes' # this doesn't print 'yes'
The problem is that s is 'foo' does not evaluate to True. My guess is that it has something to do with vim.eval, but it's only a guess.
Related
I started to learn Python with learn Python the Hard Way and I am facing some issues with ex13. I would like to now if it is a mistake of mine or because of the way PyCharm works.
Basically to make the script work as the exercise suggests I saw I have to manually enter the parameters names in PyCharm with run>edit configuration
I put "first" "second" and "third"
But I would like to combine raw_input and argv so I can let the user choose the name of the parameters. Here's what I wrote:
from sys import argv
first = raw_input("First argument: ")
second = raw_input("Second argument: ")
third = raw_input("Third argument: ")
script, first, second, third = argv
print "The script is called:", script
print "Your first variable is:", first
print "Your second variable is:", second
print "Your third variable is:", third
It runs but it returns:
ValueError: need more than 1 value to unpack
It seems that in PyCharm I have to enter manually all the script parameters ? There is no way to combine it with raw input ?
Thanks for your help.
note check out Joran's answer which shows a good combination of using command line args and prompting for user inputs. Below is a break down of what is going on:
This is expected behaviour in PyCharm to specify the parameters you want PyCharm to execute your script with. Think of it like PyCharm doing something like this:
python my_script.py
However, PyCharm does not know the arguments you want to pass, you need to provide this, so it knows how to run your script. If you look near the bottom of your PyCharm window, there is a Terminal tab. You can use that to quickly execute your script and provide args.
Secondly, the reason why you are getting the error you are getting is because you are not handling your script inputs properly when trying to use argv.
You are mixing up using raw_input, which takes in user input when your Python script is running, as opposed to argv which takes parameters in to your Python script when you run it.
So, what you are looking to actually do here, is not use raw_input, but simply argv. Here is a small demo to clarify all this:
from sys import argv
script, first, second, third = argv
print "The script is called:", script
print "Your first variable is:", first
print "Your second variable is:", second
print "Your third variable is:", third
Now, go in to your command prompt and do this:
python my_script one two three
You will get:
The script is called: my_script.py
Your first variable is: one
Your second variable is: two
Your third variable is: three
This is a very simplified example, and you're probably going to need to add some handling of your inputs, or you're going to get a lot of errors with different inputs to your script. With that, I suggest maybe looking at argparse instead
Im not sure i understand the question ... but the code below will use the command line arguments if there are 3(or more) ... otherwise it will prompt and split the same way as the shell splits command line arguments
import shlex # shlex.split will split the string the same way that the shell would for command line args
if len(sys.argv) < 3:
args = (list(sys.argv) + shlex.split(raw_input("Enter Args:")))[:3]
else:
args = sys.argv[:3]
print "Using Args:",args
one,two,three = args
I'm trying to remap a key to yank/put selected text from a script into a Python interpreter using ConqueTerm. Everything is fine, except this...
def main():
print "Testing 123"
main()
turns into this...
>>> def main(): print "Testing 123"main()
in the interpreter. How can I keep the multi-line formatting?
Note: I've already tried plugins like vim-conque-repl and vim-ipython, but I haven't been able to get either of them to work correctly.
I'm trying to convert to get a command executed which is passed to the print statement. Eg:
print "exec(raw_input())"
Can I get to run the exec() in some way?
do this
command = raw_input("Command: ")
exec(command)
why are you trying to print it? be more clear if this isnt what you are looking for
I Guess this is what you are looking for ?
>>> exec("x = raw_input()")
23
>>> x
'23'
>>>
Are you asking for something simple like
aString = "raw_input()"
print "exec(" + aString + ")"
exec(aString)
from __future__ import print_function
def foo(x):
exec x
print = foo
print("exec(raw_input())")
Running
% test.py
kaboom
results in:
NameError: name 'kaboom' is not defined
From the tags you applied, it seems like you're looking for a magic string that will allow you to run any arbitrary code when Python passes that string to the print statement.
There are no such known strings. You might try very long strings, just over the obvious boundaries, looking for the traditional stack- and heap-overflow cases, but if you find one in Python X.Y.Z, chances are it was already fixed in X.Y.Z+1.
If the Python script is actually doing an exec or eval on your string, of course that's easy to exploit; if it's just doing a print, the contents never even get compiled, much less run; they're just a plain old string. The fact that the string happens to have dangerous-looking things like exec in it is irrelevant; it's not more exploitable than getting Python to print the string "rm -rf /".
Of course if you can arrange for the output of one Python interpreter to feed in as the input to an interactive session in another interpreter, then whatever you get the first interpreter to print will get executed in the second one… but in that case, you don't need the exec in the middle of the string anyway.
The print statement writes to sys.stdout by default, and sys.stdout is like a file. You can make a class that looks like a file, with a write method, which would be called by the print statement. I put together a script which demonstrates this, print_exec.py. Also note, this doesn't work if the code in the print statement contains print, itself. i.e., print "print 'foo'" won't work. So, in the example, I had to print to sys.stderr to actually see something happening. Hope this helps.
print_exec.py
import sys
class file_like(object):
def write(self, x):
exec(x)
sys.stdout = file_like()
y = "exec(raw_input())"
print "exec(y)"
Example running the print_exec.py:
>python print_exec.py
print "import sys; print >> sys.stderr, 'hi'"
hi
>
As described in the accepted answer to Most pythonic way of accepting arguments using optparse, I have a program with a function that performs operations on a string. The program uses argparse to check whether the string is provided as-is or in a file and massages the input as needed to pass it to the function.
Now I want to extend the program with a more advanced version of my function, but still leave the basic version in for comparison, somewhat as in Use argparse to run 1 of 2 functions in my script. Where I believe my situation differs is that regardless of the function that gets called, I want the option of also passing my existing input flags.
Just adding a new argument to the parser and nesting my previous code inside a if/else that checks for that flag doesn't work: it complains about the wrong number of arguments. I am aware of sub-commands, but I am still pretty new with argparse and it just seems like that would be overkill for what I want - but maybe not.
tl;dr: I need to choose one of two functions and one of two input types; both input types apply to both functions. Thanks for any help!
Edited to add code:
p = argparse.ArgumentParser(description="program.py")
p.add_argument("-e", dest='extended') #The new flag causing the trouble
p.add_argument("-s", dest="string")
p.add_argument("-f", dest="infile")
args = p.parse_args()
if args.extended:
if args.infile:
with open(args.infile,'r') as f:
for line in enumerate(f.readlines()):
print 'Input: ', line[1],
output = funcExtended(line[1]) #new and improved function
print 'Extended output: ', output
elif args.string:
output = funcExtended(args.string)
print output
else: #my future default option to grab strings from a database
print 'This will soon work: extended'
else: #I fully realize that I shouldn't have to essentially copy and paste here
if args.infile:
with open(args.infile,'r') as f:
for line in enumerate(f.readlines()):
print 'Input: ', line[1],
output = funcBasic(line[1]) #old and tired function
print 'Basic output: ', output
elif args.string:
output = funcBasic(args.string)
print output
else: #my future default option to grab strings from a database
print 'This will soon work: basic'
This is a command line utility. Issuing
$ python program.py -s 'string'
returns a properly formatted string, as before. But issuing
$ python program.py -s 'string' -e
returns
program.py: error: argument -e: expected one argument
Whew. Thanks again to anybody who can help!
If you change your extended argument to a boolean flag with
p.add_argument("-e", dest='extended', action="store_true")
it will no longer expect an argument. You can then invoke your script with
$ python program.py -e -s 'string'
Finally as a bonus here are some ideas to make your code less redundant:
import argparse
def funcExtended(line):
return " ".join(line)
def funcBasic(line):
return line.upper()
p = argparse.ArgumentParser(description="program.py")
p.add_argument("-e", "--extended", dest="func", action="store_const", const=funcExtended, default=funcBasic)
p.add_argument("-s", "--string")
p.add_argument("-f", "--infile")
args = p.parse_args()
def readlines(args):
if args.infile:
with open(args.infile,'r') as f:
for line in f:
yield line.rstrip("\n")
elif args.string:
yield args.string
else: #my future default option to grab strings from a database
print 'This will soon work: extended'
for line in readlines(args):
print 'Input: ', line
output = args.func(line)
print "Output: ", output
I have a file that I've made executable. It has a function in it that I would like to return its results to the command line but, I keep getting NameError messages. To break things down, I'm using LinuxMint Lisa and so far I have:
#! /usr/bin/env python
import mechanize
from BeautifulSoup import BeautifulSoup
import sys
def dictionary(word):
br = mechanize.Browser()
response = br.open('http://www.dictionary.reference.com')
br.select_form(nr=0)
br.form['q'] = word
br.submit()
definition = BeautifulSoup(br.response().read())
trans = definition.findAll('td',{'class':'td3n2'})
fin = [i.text for i in trans]
query = {}
for i in fin:
query[fin.index(i)] = i
return query
print dictionary(sys.argv)
Then I chmod from my terminal:
sudo chmod +x this_file.py
When I call this file from the command-line, I'll enter:
./this_file.py 'pass'(or any other string argument)
Which will return:
TypeError: Must assign a string
So I know I'm obviously not using sys.argv correctly but, I have a feeling like I'm mucking something else up when attempting to return this functions results to the command-line.
Ok, I might as well post this as my answer instead of just a comment:
In
print dictionary(agrv)
argv is misspelled.
It should be
print dictionary(sys.argv)
Also, use sys.argv, argv by itself won't suffice
argv is an attribute of the sys module
Use either
sys.argv
or do
from sys import argv
Shouldn't it have been print dictionary(sys.argv[1]). I guess you want to search the commandline argument in the dictionary.com
The problem with the question as currently posted is that sys.argv is a list, not a string, so when you set the form entry 'q' you are setting it to a list of arguments to the program. You could change the program to pass in the first argument:
print dictionary(sys.argv[1])
Or call the dictionary functions multiple times:
for i in sys.argv[1:]:
print dictionary(i)
Note that we don't want to include the program name itself so omit sys.argv[0].
You don't make it clear what you mean by 'returning' results to the command line. If you just want to print the results, you can do print.
But the error message you're getting has nothing to do with that. It's caused by two things: one, you've put agrv instead of argv. And second, you've imported sys, so you need to reference sys.argv not just argv.