skip to Main Content

I’ve been wrapping my head around this problem and can’t find a solution.

I have a pretty simple code:

import argparse
import json

def main():
    parser = argparse.ArgumentParser(description="Process a JSON argument.")
    parser.add_argument(
        "--json",
        type=str,
        required=True,
        help="JSON string or path to a JSON file."
    )
    args = parser.parse_args()
    
    # Try to parse the argument as a JSON string or file path
    try:
        # First, attempt to parse it as a JSON string
        data = json.loads(args.json)
        print("Parsed JSON string successfully:", data)
    except json.JSONDecodeError:
        # If that fails, treat it as a file path
        try:
            with open(args.json, 'r') as file:
                data = json.load(file)
                print("Parsed JSON file successfully:", data)
        except FileNotFoundError:
            print("Error: Input is not a valid JSON string or file path.")
            return

    # Use the parsed dictionary (data)
    print("JSON as dictionary:", data)

if __name__ == "__main__":
    main()

saved as script.py
When I run it from Powershell with

python script.py --json '{"key": "value", "number": 42}'

I receive:

Traceback (most recent call last):
  File "C:mypathscript.py", line 17, in main
    data = json.loads(args.json)
  File "C:Usersmyuserminiconda3envsti_nlplibjson__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "C:Usersmyuserminiconda3envsti_nlplibjsondecoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "C:Usersmyuserminiconda3envsti_nlplibjsondecoder.py", line 353, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:mypathscript.py", line 33, in <module>
    main()
  File "C:mypathscript.py", line 22, in main
    with open(args.json, 'r') as file:
OSError: [Errno 22] Invalid argument: '{key: value, number: 42}'

When i run it with cmd (Anaconda prompt):

python script.py --json "{"key": "value", "number": 42}"

it works just fine:

Parsed JSON string successfully: {'key': 'value', 'number': 42}
JSON as dictionary: {'key': 'value', 'number': 42}

So… what is the issue with Powershell and how can I solve this problem?

3

Answers


  1. Powershell handels differently than cmd – Ref

    python script.py --json "{""key"": ""value"", ""number"": 42}"
    

    Or use like so

    python script.py --json @"
    {"key": "value", "number": 42}
    "@
    

    I use like this – put that json in a file and pass like so

    python script.py --json data.json
    
    Login or Signup to reply.
  2. The issue arises because PowerShell handles quotes differently from CMD or other shells. When you run the script in PowerShell, it interprets the single quotes (‘) in the JSON string literally instead of processing them correctly as part of the string. This causes a JSONDecodeError because JSON requires keys and string values to be enclosed in double quotes (").

    You can try below approaches to resolve the issue. One: Use Escaped Double Quotes:

    python script.py --json "{"key": "value", "number": 42}"
    

    Or use single quote for entire argument like below:

    python script.py --json '{"key": "value", "number": 42}'
    
    Login or Signup to reply.
  3. This is an issue prior to the introduction of PSNativeCommandArgumentPassing, before that the double-quotes are consumed when passed as arguments. For comparison, you can change your Python script to:

    import sys
    
    def main():
        print(sys.argv)
    
    if __name__ == "__main__":
        main()
    

    Then when called from PowerShell 7.2 and below you would see:

    PS ..pwsh> python script.py --json '{"key": "value", "number": 42}'
    ['script.py', '--json', '{key: value, number: 42}']
    

    And in 7.3+ you will see that the " are preserved:

    PS ..pwsh> python script.py --json '{"key": "value", "number": 42}'
    ['script.py', '--json', '{"key": "value", "number": 42}']
    

    That’s the cause of your issue. To solve this you will need to escape the " with . A way to handle this dynamically could be via .Replace('"', '"'):

    $json = '{"key": "value", "number": 42}'
    if ($PSVersionTable.PSVersion -lt '7.3' -or $PSNativeCommandArgumentPassing -eq 'Legacy') {
        $json = $json.Replace('"', '"')
    }
    python script.py --json $json
    

    There are other alternatives too, for example encoding your Json to Base64 on PowerShell side and decoding it in Python, so in PowerShell:

    $json = '{"key": "value", "number": 42}'
    $b64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($json))
    python script.py --json $b64
    

    And in Python:

    # First, attempt to b64decode and parse it as a JSON string
    data = json.loads(b64decode(args.json))
    

    Then you code should be compatible with all versions.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search