python argparse hex error - python

I'm trying to read some hex values i need for my pythonscript using argparser, an example input looks like:
parser.add_argument("start", type=hex, help="hex PC address you want to start recording data")
The problem occurs when i try to start the script with a hexvalue.
example:
python testscript.py 0x21c
Then ik get error:
error: argument start: invalid hex value: '0x21c'
is also tried following values: 0X21C, 21C, 21c, 21. All of them result in the same error.
EDIT: i don't nee the hex value converted to a int. I just need the hex value i inputted. Its a PC address where a µC needs to jump to.
Does anyone know what i'm doing wrong here?
Thanks!

Inspired by:
Convert hex string to int in Python
I tried
In [471]: parser=argparse.ArgumentParser()
In [472]: parser.add_argument('ahex',type=lambda x: hex(int(x,0)))
In [473]: parser.parse_args(['0x21c']) # valid hex string input
Out[473]: Namespace(ahex='0x21c')
In [474]: parser.parse_args(['21']) # converts valid int to hex string
Out[474]: Namespace(ahex='0x15')
In [475]: parser.parse_args(['21c']) # error if string is not valid hex
usage: ipython3 [-h] ahex
ipython3: error: argument ahex: invalid <lambda> value: '21c'
As #mgilson stressed in the comments, the type parameter is a function, one that takes a string and returns something. It also raises an error if the string is not 'valid'. hex() does not work as type, because it takes an integer and returns a hex string. hex('0x21c') is not valid use of that function.
For this quick-n-dirty solution I used a lambda function. It could just as well been a def. I used int(x,0) to convert the string to a int, in a way that handles both hex strings and integer strings. Then I converted that integer back to a string using the hex function.
So the net effect of my lambda is to just validate the hex string. If a valid string it just returns the same thing (same as if type was the default identity lambda x: x).
Confusion over the nature of the type parameter arises most often when people want a boolean value. bool() does not take a string like 'True' or 'False' and return a boolean value. Look up those SO questions if the issue is still confusing.

Related

Convert string with "_" to int?

I have a function which takes a string input, tries to convert it to integer and then proceeds with two alternative paths depending on whether the conversion succeeded or not:
def make_int(arg):
try:
int_value = int(arg)
except ValueError:
str_value = arg
I now was quite surprised when the string '123_2307_7' was happily converted to the integer 12323077 - whereas I was expecting it to follow the str path here. What details of str -> int conversion is it I have not yet grokked?
As pointed out by #jonrsharpe the docs says you can embed single _ charcaters in your integer literal - which are simply ignored. Closing.
In python you can write any integer/float this way :
XXX_XXX_XXX
Keep in mind that integer/float are objects in python.

How do I hash integers and strings inputs using murmurhash3

I'm looking to get a hash value for string and integer inputs.
Using murmurhash3, I'm able to do it for strings but not integers:
pip install murmurhash3
import mmh3
mmh3.hash(34)
Returns the following error:
TypeError: a bytes-like object is required, not 'int'
I could convert it to bytes like this:
mmh3.hash(bytes(34))
But then I'll get an error message if the input is string
How do I overcome this without converting the integer to string?
How do I overcome this without converting the integer to string?
You can't. Or more precisely, you need to convert it to bytes or str in some way, but it needn't be a human-readable text form like b'34'/'34'. A common approach on Python 3 would be:
my_int = 34 # Or some other value
my_int_as_bytes = my_int.to_bytes((my_int.bit_length() + 7) // 8, 'little')
which makes a minimalist raw bytes representation of the original int (regardless of length); for 34, you'd get b'"' (because it only takes one byte to store it, so you're basically getting a bytes object with its ordinal value), but for larger ints it still works (unlike mucking about with chr), and it's always as small as possible (getting 8 bits of data per byte, rather than a titch over 3 bits per byte as you'd get converting to a text string).
If you're on Python 2 (WHY?!? It's been end-of-life for nearly a year), int.to_bytes doesn't exist, but you can fake it with moderate efficiency in various ways, e.g. (only handling non-negative values, unlike to_bytes which handles signed values with a simple flag):
from binascii import unhexlify
my_int_as_bytes = unhexlify('%x' % (my_int,))

How to check for a string's "natural" datatype in Python?

I have a user inputting arguments to the command line when running a python3 script, and I wish to check whether specific arguments are floats, ints, booleans, or strings. I'm familiar with the errors that are thrown when a string like 'car' is cast to an int using the int() function, and am also familiar with using a try/except block to attempt to cast a string to an int, and if this is unsuccessful, how to map error messages to helpful output to the user. I've also seen this previous question, which will probably do the job. Was just wondering if there had been any new development.
Not sure if this is possible, but looking for a smart type() function that could operate as such:
#!/usr/bin/env python3
import sys
smarttype(sys.argv[-1])
and is capable of handling the following kinds of inputs:
./script.py 50
./script.py True
./script.py 50.0
./script.py run
and output:
int
bool
float
str
I usually use ast.literal_eval to parse “elementary” data types:
type(ast.literal_eval('50')) # outputs int
You need however a set of quotes to mark something as a string (otherwise every input could be taken as a string):
type(ast.literal_eval('run')) # error
type(ast.literal_eval('"run"')) # string
If you want to allow unqouted strings you could do the following:
def parse_data(x):
"""Takes a string x and returns the "value" of x"""
try:
return ast.literal_eval(x)
except (ValueError, SyntaxError):
return x

How to detect and cast string back into right type in Python

In my python server code, I am getting all arguments as strings. I am unaware of the original type of the argument.
For example,
if the actual value is integer 10, the argument received is string value '10'
if the actual value is string "apple". The argument received is unchanged string 'apple'
if the actual value is float 10.0 , the argument received is string value '10.0'
What is the best way to detect the right type of the argument and cast them back to 'int' in the first example, 'string' in the second example, 'float' in the third example?
Ideally, you want to fix the client code so it doesn't throw away type information in the first place. Or, if you can't do that, you at least want to know what the rule is for how these strings are generated, so you can work out how to reverse the rule.
But if neither of those is possible, and you need to guess, one possibility is something like this:
def parseval(s):
try:
return int(s)
except ValueError:
pass
try:
return float(s)
except ValueError:
pass
return s
This will treat anything that could be a valid int as an int, anything that can't be a valid int but could be a valid float as a float, and anything else as a str.
In the special case where the output comes from just calling repr or str in Python, you may want this:
import ast
def parseval(s):
try:
return ast.literal_eval(s)
except ValueError:
return s
This will convert any Python literal, or any collection display made up of literals and other collection displays made up of etc. recursively, to the original value, but leave anything else as itself. (If you know the client is using repr rather than str, you should leave off the try/except. But if it's using str, this works, because it relies on the fact that, for every kind of literal but strings, the str is interpretable as a repr.)
However, note that this makes it impossible to, e.g., send the string "10" to your server.

How do I create unicode characters with variable numbers?

Basically what I want to do is print u'\u1001', but I do not want the 1001 hardcoded. Is there a way I can use a variable or string for this? Also, it would be nice if I could retrieve this code again, when I use the output as input.
According to the python doc on unicode (located Here):
One-character Unicode strings can also be created with the unichr()
built-in function, which takes integers and returns a Unicode string
of length 1 that contains the corresponding code point. The reverse
operation is the built-in ord() function that takes a one-character
Unicode string and returns the code point value:
unichr(40960)
results in the character :
u'\ua000'

Categories