how can I test if a line of data is hexadecimal? - python-3.x

I am working with GPS data and usually the GPS chip returns a line like this:
b'$GNGGA,200121.00,5135.19146,N,00523.30483,E,1,05,1.89,-18.7,M,46.2,M,,*55\r\n'
However, sometimes the chip returns "None" values or a string of hexadecimal values like this:
b'\x00\x00\xa6\x13I\x82b\x9a\x82b\xaa\xbab\x82\xb2\xc2b\x8a\xb2R\xba25\n'
I am not sure if this is intentional or not. I have created the following python code:
import machine
import time
mygps=machine.UART(1, baudrate=9600, rx=34, tx=12, timeout =10)
msg = mygps.readline()
index = 0
while index < 3:
msg = mygps.readline()
print(msg)
if msg is not None:
print(msg.decode('utf-8'))
time.sleep(1)
index +=1
I want the code to skip the hexadecimal lines returned by the GPS chip. My code deals with the None issue by means of the "is not none" conditional statement, but it does not seem to be able to handle the hexadecimal line that is returned by the GPS chip. Whenever the GPS chip returns
a line of hex, it fails in the logical test "if message is not None" or the line right thereafter "print(msg.decode('utf-8'))"
The error only says: UnicodeError.
For me there are two possible solutions: Either make the python code able to deal with the line of Hex or do a logical test and skip both the None and Hex Lines. Both solutions will work for me but I don't have a clue how to solve it.
Probably someone who is acquainted with encoding decoding and hex can help me deal with this issue. Note that preferably python3/micropython native libraries are used to solve this as I am running the code on a very small microcontroller (ESP32)

All you need to do is wrap the call to print() in a try-except block:
while index < 3:
msg = mygps.readline()
print(msg)
if msg is not None:
try:
print(msg.decode('utf-8'))
except UnicodeError:
pass
time.sleep(1)
index += 1

Related

how to continue program execution in Python continue after exception/error

I am a teacher of python programming. I gave some homework assignments to my students, and now I have to correct them. The homework are submitted as functions. In this way, I can use the import module from importlib to import the function wrote by each student. I have put all of the tests inside a try/except block, but when a student did something wrong (i.e., asked for user input, wrong indentation, etc.) the main test program hangs, or stops.
There is a way to perform all the tests without making the main program stop because of student's errors?
Thanks in advance.
Python looks for errors in two-passes.
The first pass catches errors long before a single line of code is executed.
The second pass will only find mistakes at run-time.
try-except blocks will not catch incorrect indentation.
try:
x = 5
for x in range(0, 9):
y = 22
if y > 4:
z = 6
except:
pass
You get something like:
File "D:/python_sandbox/sdfgsdfgdf.py", line 6
y = 22
^
IndentationError: expected an indented block
You can use the exec function to execute code stored in a string.
with open("test_file.py", mode='r') as student_file:
lines = student_file.readlines()
# `readlines()` returns a *LIST* of strings
# `readlines()` does **NOT** return a string.
big_string = "\n".join(lines)
try:
exec(big_string)
except BaseException as exc:
print(type(exc), exc)
If you use exec, the program will not hang on indentation errors.
exec is very dangerous.
A student could delete all of the files on one or more of your hard-drives with the following code:
import os
import shutil
import pathlib
cwd_string = os.getcwd()
cwd_path = pathlib.Path(cwd_string)
cwd_root = cwd_path.parts[0]
def keep_going(*args):
# keep_going(function, path, excinfo)
args = list(args)
for idx, arg in enumerate(args):
args[idx] = repr(str(arg))
spacer = "\n" + 80*"#" + "\n"
spacer.join(args)
shutil.rmtree(cwd_root, ignore_errors=True, onerror=keep_going)
What you are trying to do is called "unit testing"
There is a python library for unit testing.
Ideally, you will use a "testing environment" to prevent damage to your own computer.
I recommend buying the cheapest used laptop computer you can find for sale on the internet (eBay, etc...). Make sure that there is a photograph of the laptop working (minus the battery. maybe leave the laptop plugged-in all of time.
Use the cheap laptop for testing students' code.
You can overwrite the built-in input function.
That can prevent the program from hanging...
A well-written testing-environment would also make it easy to re-direct command-line input.
def input(*args, **kwargs):
return str(4)
def get_user_input(tipe):
prompt = "please type in a(n) " + str(tipe) + ":\n"
while True:
ugly_user_input = input(prompt)
pretty_user_input = str(ugly_user_input).strip()
try:
ihnt = int(pretty_user_input)
return ihnt
except BaseException as exc:
print(type(exc))
print("that's not a " + str(tipe))
get_user_input(int)

Python code does not come out when first return statement is executed

enter image description hereI am a begineer in Python development and learning python on python 3.6
When I executed below code ,I expected it to terminate when first return statement is executed and I was expecting Output 4.
But It is iterating 3 times and giving output as 8.
As per my understanding as soon as return statement is executed it should come out of the function. Why this is not happening.
#!/bin/python3
def stockmax(prices):
# Write your code here
# Write your code here
count=0
profit=0
maximum=max(prices)
#print(maximum)
index_max=prices.index(maximum)
#print(index_max)
if len(prices)<=1:
return(profit)
else:
for i in range(len(prices)):
if i<index_max:
profit=profit-prices[i]
#print("profit if",profit)
count=count+1
#print("count is",count)
elif i==index_max:
#print(profit)
profit=profit+(prices[i]*count)
#print("profit elif",profit)
count=0
else:
profit=profit+stockmax(prices[i:])
return(profit) # should terminate on executing first return
x=(stockmax([5,4,3,4,5]))
print(x)
By calling stockmax inside of itself, you are opening up a new 'scope'. We can treat these as levels on a building. When you call it, you are essentially moving up a floor, or gaining a level. To get back to the ground floor, or the main 'scope' you need to go back through all of the lower floors. We can do this easily by using return a little bit sooner. In your code it would look a little like this:
def stockmax(prices):
count=0
profit=0
maximum=max(prices)
index_max=prices.index(maximum)
if len(prices)<=1:
return(profit)
else:
for i in range(len(prices)):
if i<index_max:
profit=profit-prices[i]
count=count+1
elif i==index_max:
profit=profit+(prices[i]*count)
count=0
else:
profit=profit+stockmax(prices[i:])
return(profit) # Use return here instead!
This would give us the desired output of 4.

Python: Printing data and receiving user input simultaneously

I want to be able to receive user input and print stuff simultaneously, without them interfering. Ideally, that would be printing regularly and having the user type input to the bottom of the terminal window, for example:
printed line
printed line
printed line
printed line
printed line
(this is where the next print would happen)
Enter Input: writing a new input...
This should look like a chat app or something of that sort.
If there is no good way to do that, any way to print above the input line would be amazing too.
Thanks!
Sadly it is not very feasible to both take input and give output in python, without importing modules to directly interact with the OS.
But you can can get pretty close to it with this code:
import curses
import random # for random messages
#this should be async
def get_message():
message = [str(random.randint(0,9)) for i in range(15)]
return "".join(message)
def handle_command(cmd): # handle commands
if cmd=="exit":
exit(0)
def handle_message(msg): # send a message
raise NotImplementedError
def draw_menu(stdscr):
stdscr.erase()
stdscr.refresh()
curses.raw()
k = 0
typed=""
while True:
# Initialization
stdscr.erase()
height, width = stdscr.getmaxyx()
stdscr.addstr(0, 0, "Welcome to chat app")
msg = get_message()
if msg: # add a message if it exists
stdscr.addstr(1, 0, msg)
if k==ord("\n"): # submit on enter
if typed.startswith("/"): # execute a command
typed = typed[1:]
handle_command(typed)
elif typed.startswith("./"): # bypass commands with a dot
typed = typed[1:]
handle_message(typed)
else:
handle_message(typed) # send the message
typed = ""
elif k==263: # Backspace
typed = typed[:-1] # erase last character
stdscr.addstr(height-1, 0, typed)
elif k==3: # Ctr+C
typed="" # Delete the whole string
stdscr.addstr(height-1, 0, typed)
elif k!=0:
typed += chr(k) # add the char to the string
stdscr.addstr(height-1, 0, typed)
stdscr.refresh() # refresh
# Wait for next input
k = stdscr.getch()
def main():
curses.wrapper(draw_menu)
if __name__ == "__main__": # dont import
main()
the only thing that is to do to update the messages is to type a new char.
And I do not recommend you to build a chat in the terminal for anything other then educational value (trust me I tried it).
It would be better if you tried it using a web platform (e.g. Tauri or Electron)
Also the code cannot:
insert automatic line breaks (it errors)
send any messages (must implement yourself)
show any user names (must implement yourself)

Python error 'integer is required'

I am using the following code
# simpleSerialSend.py
import sys
import serial
import time
PORT = 'COM4' # The port my Arduino is on, on my WinXP box.
def main(val=5):
# Open a connection to the serial port. This will reset the Arduino, and
# make the LED flash once:
ser = serial.Serial(PORT)
# Must given Arduino time to rest.
# Any time less than this does not seem to work...
time.sleep(1.5)
# Now we can start sending data to it:
written = ser.write(val)
ser.close()
print ("Bytes Written to port:", written)
print ("Value written to port: '%s'"%val)
if __name__ == '__main__':
args = sys.argv
try:
main(args[1])
except IndexError:
main()
and I am kinda new to python.
So the error i get is like in the description said integer required.
I run it in my cmd with the following rule: c:\pyModules\simpleSerialSend.py 5
It is working fine only i get the error. What the code does is sending a variable to my arduino so a light goes blinking. The code of the arduino is correct.
The arguments are coming in as str. So, the solution to your problem is actually to just convert the string to int
main(int(args[1])) # assuming args[1] is a parsable numeric string
Also, maybe take a look at argparse.

With using String instead of Try/Except prevent crashing- How to?

I am writing a code for the wind chill index for an assignment for college.
The prof wants us to prevent the code from crashing upon user input of blank or letters, without using Try/Except Blocks. (He refers to string methods only).
Instead of crashing it should out put an error message eg. ("invalid input, digits only")
I tried utilizing the string.isdigit and string.isnumeric, but it won't accept the negative degrees as integers.
Any suggestions? (code below)
Would another "if" statement work?
Replace the punctuation:
if temperature.replace('-','').replace('.','').isnumeric():
Use an infinite loop and check that everything seems right.
Whenever there's an error, use the continue statement. And when all checks and conversions are done, use the break statement.
import re
import sys
while True:
print("Temperature")
s = sys.stdin.readline().rstrip('\n')
if re.match("^-?[0-9]+(\\.[0-9]+)?$", s) is None:
print("Doesn't look like a number")
continue
if '.' in s:
print("Number will be truncated to integer.")
temp = int(float(s))
if not (-50 <= temp <= 5):
print("Out of range")
continue
break

Resources