-1

I have

headers = {'content-type': 'application/soap+xml'}

which works fine. however I want this to be able to be specified as an argument so in my args lets say I have

--wsheaders {'content-type':\s'application/soap+xml'}

This comes through fine as

{'content-type': 'application/soap+xml'}

... however when I do

headers = args.wsheaders

I get a ton of errors. So obviously headers cant be a string. But there must be a way to store this where it can be read back in a variable? Any ideas?

EDIT: I cant use the single quotes around the argument. I'm still learning this but it appears I can't use single or double quotes around an argument when passing the arguments from a file, like I CAN but it doesn't work to group the chars together, it instead becomes a literal part of the argument which isn't helpful since I lose everything before or after a space. see the attachment for what it looks like in the file.

wsheaders in properties file

--wsheaders '{'content-type': 'application/soap+xml'}'

error when using single quotes or double quotes

Sync03.py: error: unrecognized arguments: 'application/soap+xml'}'
Sync03.py: error: unrecognized arguments: 'application/soap+xml'}"

so instead I use

--wsheaders {'content-type':\s'application/soap+xml'}

but then the \s needs to be replaced after the arg is entered which I do, but then the variable is a string and I'm back to the origial problem.

type=json.loads

doesn't work in the argument definition when there's a \s since it's an unrecognized json. If there was a way to replace the \s with argparse it might work to do that first...but I dont think thats possible. With a space then with a \s

Sync03.py: error: argument --wsheaders: invalid loads value: "{'content-type':"
Sync03.py: error: argument --wsheaders: invalid loads value: "{'content-type':\\s'application/soap+xml'}"

EDIT

parser.add_argument('--wsheaders', type=lambda x: json.loads(x.replace('\s', '').replace('\'', '"')))

This worked as per bschlueter comment directly below.

Carver Stone
  • 105
  • 2
  • 15
  • You should post at least the errors that originate in your code if you can. – bschlueter Mar 26 '16 at 10:46
  • `'{'content-type': 'application/soap+xml'}'` doesn't work because the inner `'` match with the earlier ones. You would need to escape the inner ones in order to have this be a valid string. `'{\'content-type\': \'application/soap+xml\'}'` would make it a single, valid string, but it is not valid json, because json requires double quotes. `'{"content-type": "application/soap+xml"}'` is the valid json representation of the same data. – bschlueter Mar 26 '16 at 19:51
  • You absolutely can replace the *\s* with argparse, just use a custom type which fixes the input: `parser.add_argument('--wsheaders', type=lambda x: json.loads(x.replace('\s', '').replace('\'', '"')))`. – bschlueter Mar 26 '16 at 20:00
  • bschlueter - that last method of adding the argument with the replace worked! Thank you! I'm not sure how exactly. I know how the replaces work since I'm doing like 50 replacements of the returned data, but I've never used "type=lambda x:" before. – Carver Stone Mar 26 '16 at 20:12

2 Answers2

1

Assuming you're consuming --wsheaders in your python script as an argument somehow, all that you need to do is quote the headers when you pass them to the script:

the_script --wsheaders '{"content-type": "application/soap+xml"}'

Then parse them as json to get the dict.

Using pyyaml:

>>> import yaml
>>> yaml.load(args.wsheaders)
{'content-type': 'application/soap+xml'}

EDIT:

If you are using argparse (as you should be), you can easily do the parsing when the args are parsed by declaring the argument with:

parser = argparse.ArgumentParser()
parser.add_argument('--wsheaders', type=json.loads)
args = parser.parse_args()
bschlueter
  • 3,817
  • 1
  • 30
  • 48
  • What? Could the downvoter kindly explain their reasoning? – bschlueter Mar 26 '16 at 10:24
  • donno why the downvote, but that worked perfectly. didn't really know what yaml was until now. I was hoping to be able to do it without adding another package (yaml) as on the live environment im using this script in, installing outside things is tough. cant even use pip there. but what you said works with pyaml installed an import of yaml. Will have to find a standalone way to install it Thanks a bunch! – Carver Stone Mar 26 '16 at 10:45
  • Yaml is a superset of json, and I have my shell load it by default, so it was easier to get to than json by a tiny amount. Obviously, `json.loads(args.wsheaders)` would work just as well. – bschlueter Mar 26 '16 at 10:50
  • hmm the edit doesnt seem to work for me. I get: sync.py: error: argument --wsheaders: invalid loads value: "{'content-type':\\s'application/soap+xml'}" the space after th colon is \s in my arg. I can't use "" around it or '' as in a properties file it reads the"'s as part of the arg and only takes the stuff before the space, so I need to fill it with \s and replace it later. But it wont accept that arg now because it has the \s in it – Carver Stone Mar 26 '16 at 18:54
  • You cannot use json.loads with single quotes – Padraic Cunningham Mar 26 '16 at 19:10
  • Yep, that's why I changed the input to `'{"content-type": "application/soap+xml"}'`. – bschlueter Mar 26 '16 at 19:14
  • added an edit to my question to show the output of the latest attempt. Sorry if I'm just being thick here but I'm trying to find a way to use the type=json.loads in the argument and cant seem to – Carver Stone Mar 26 '16 at 19:34
  • The easiest way to represent a python dictionary as a string is using json, and [it's spec](https://tools.ietf.org/html/rfc7159#section-7) dictates the use of quotation marks around strings. Interestingly that rfc doesn't seem to explicitly state that a quotation mark is `"` and not `'`, but every example uses `"` as does every implementation I've interacted with. The spec also means that you can't use `\s` in place of a space. It sounds like you want to implement your own bastardized version of json, which I highly discourage, though is possible. You would just have write your own parser. – bschlueter Mar 26 '16 at 19:46
  • I dont think i want to introduce my own version. Lets say I wanted to use standard operations as is, but i wanted to put my headers value in a file containing the args rather than type them out manually on the command line. Thats all I'm trying to do. – Carver Stone Mar 26 '16 at 19:59
  • For that, just put the json representation of the headers into a file and [load](https://docs.python.org/2/library/json.html#json.load) it with the json lib: `parser.add_argument('--wsheaders-file', type=json.load)` – bschlueter Mar 26 '16 at 20:11
1

I assumed you used argparse.

In fact argparse uses sys.argv which captures passed arguments as string. So in this case you are passing dictionary as string and for this reason you need to parse it as dictionary because requests needs header as dictionary.

For this reason headers = args.wsheaders is useless since args.wsheaders is string. You need to use json or ast to parse it as dictionary as below-

headers = ast.literal_eval(args.wsheaders)

More details of passing dictionary as command-line argument and parsing them correctly at here, here and here.

Community
  • 1
  • 1
Learner
  • 5,192
  • 1
  • 24
  • 36
  • This doesn't account for how the headers are passed to the script. – bschlueter Mar 26 '16 at 10:47
  • @bschlueter seeing `--wsheaders` and `args.wsheaders` i *assumed* he uses commandline argument passing using `argparse` as i mentioned above. – Learner Mar 26 '16 at 10:50
  • Right, but the way the OP described passing the argument to `--wsheaders` would necessarily fail because of how the shell would pass it to python. – bschlueter Mar 26 '16 at 10:56
  • yes argparse and yes its a command line argument. though i have about 30 args specified in a file so i load them all via --file filename.properties but i assume these come in the same as if manually typing them in the command line. i.e. as mentioned as a string. Though when loading from a file i can't use "" around args so spaces like \s and such need to be replaced later which is annoying a bit. especially when it comes to the body. Thank you for the info, I'll definitely be reading into this tomorrow when i wake up so I understand it better. – Carver Stone Mar 26 '16 at 10:57