So I have been trying to make a program that can display a countdown clock to a GUI. It requests a JSON file from a website and then uses that data- getting the JSON file and it's data is working for other parts of my program except using the data inside datetime.
import time
import requests
import json
import datetime as dt
response = requests.get("https://website.website/mission.json")
data = json.loads(response.text)
a = dt.datetime(data['launch'])
b = dt.datetime.now()
print("T- " + time.strftime("%H:%M:%S", time.gmtime(round((a-b).total_seconds()))))
JSON file:
{
"mission": "GlobeSat2",
"launch": "2020,9,13,19,00,00",
"status": "Go"
}
When I use a = dt.datetime(data['launch']) it gives an error of TypeError: an integer is required (got type str) but when I use a = dt.datetime(2020,9,13,19,00,00) there is no error.
The value is the same as if I put it in myself
>print(data['launch'])
>2020,9,13,19,00,00
What I've tried:
I changed the value of the JSON file to "launch": "20200913120000" and gave an error of OverflowError: Python int too large to convert to C long.
I tried to do int(data['launch']) which obviously didn't work.
If your problem is to change that date to datetime format you can easily use this one line of code to do that
a=dt.datetime(*([int(i) for i in data['launch'].split(",")]))
then a will get converted into datetime.
Beginning programmers often make similar mistakes to yours here, confusing print statements with return values and confusing string representations of values with the actual value.
Remember that standard in and out, or the console are just a text-based user interface. They feel technical and close to the language, but they are still just a user interface.
If you run this script:
x = 123
print(123)
Or you do the same thing on the Python CLI:
>>> x = 123
>>> x
123
You might thing Python showed you the value of the x variable of type int, 123. But 123 is just the text representation of that value. There's many ways you could represent 123, for example 0b1111011 or 0x7B - all valid string representations of the exact same integer number.
Your problem is similar, in that you expect these two things to be the same:
a = dt.datetime(2020,9,13,19,00,00)
parameter = '2020,9,13,19,00,00'
b = dt.datetime(parameters)
But in the case of assigning to a, you call .datetime() with 6 integer values, while in the case of assigning to b, you call .datetime() with a single string value. The fact that the string looks very similar when printed to how you would normally write those 6 integer values in code really means nothing to Python. Note the 'when printed' vs. 'in code'.
You can have Python interpret a string to obtain the values you know it represents, but you'll have to tell it how (there's many approaches).
For example:
a = dt.datetime(*[int(part) for part in data['launch'].split(',')])
This takes the string value of data['launch'], splits it over the ',' into 6 strings in a list (['2020','9','13','19','00','00']) and then turns each part of that list into an integer with the int() function, which can turn a string that represents a single integer into its int value. The resulting list is then spread over the parameters using the * operator on the list.
There's many different approaches, but of course you could also consider fixing the JSON if you wrote the server that returned the value:
{
"mission": "GlobeSat2",
"launch": [2020,9,13,19,0,0],
"status": "Go"
}
By replacing the "" with [], JSON now represents the value of "launch" as a list and when read by Python, it will be read as a list of integers.
If that was your JSON, this would be your code:
a = dt.datetime(*data['launch'])
Still using the * to spread it over the parameters of the function, but everything else would be done automatically when interpreting the JSON.
Related
I am debugging an hardware IP and since I am looking at waveforms it's more tidy and organized if I keep the numbers represented in the hex format ( I am saying this because I could change the representation in the waveform viewer as "decimal", but if there is a way to avoid that, I'd prefer it. And the reason I prefer it is because with decimal I lose track of the single byte values). Example of numbers in the waveform:
The drawback however is that whenever I need to check them against my results in python I need to wrap every number with hex() before printing it. Note that I am using Python as book keeping and to check results on the spot, I don't care about performance or whatever else.
import numpy as np
#Test HW dot product - This is just an example
e = np.arange(0x5a,0x61)
a = np.arange(0x1,0x8)
# Intermediate result
r1 = a[0:4]*e[0:4]
#Final result
c = np.dot(a,e)
In the spyder console then I type the variable to display the content:
>>>c
Out[6]: 2632
>>>r1
Out[7]: array([ 90, 182, 276, 372])
However I would like them to be displayed as hex. Is there any console setting or Pyhton representation setting to make this happen?
I know that I can create a wrapper around a print function that calls hex, but I don't want to have prints all around my code, I like that I can just type a variable name in the console and see the value.
I'm doing a relatively big project for my final thesis and therefore I am using a .ini file for storing and retrieving settings. However, I am unable to find an elegant solution for how to convert the strings (well, actually the strings inside the dictionary) that Configparser returns to numbers (ints and floats) and/or lists.
Googling the issue, I came across this SO thread which only tackles the 'list' part of my problem but using the top rated solution (defining lists inside the .ini file like that: list=item1,item2) didn't do anything for me, as the 'list' still shows up as a string after parsing. Also, I do not want to change format.
So I decided I would try it myself and came up with this solution:
import configparser
# create a new instance of a 'ConfigParser' class
config = configparser.ConfigParser()
# create mock-content for the config file
config["Test"] = {
"test_string":"string",
"test_int":"2",
"test_float":"3.0",
"test_list":"item1, item2"
}
# get the relevant settings
settings = config["Test"]
# pack the relevant settings into a dictionary
settings = dict(settings)
# iterate through all the key-value pairs and convert them, if possible
for key, value in settings.items():
# try to convert to int
try:
settings[key] = int(value)
# if the value can't be converted to int, it might be a float or a list
except ValueError:
# try converting it to a float
try:
settings[key] = float(value)
# if the value can't be converted to float, try converting to list
except ValueError:
if "," in value:
cont = value.split(",")
settings[key] = [item.strip() for item in cont]
else:
settings[key] = value
print(type(settings["test_string"]))
print(settings)
However, this seems so very inelegant and is so heavily nested and the task itself seems so important that I cannot believe that there is no "more official" solution to this that I am simply unable to find.
So, could please someone help me out here and tell me if there really is no better, more straightforward way to achieve this!?
Best I can do is this (though it's kinda hacky and probably dangerous too):
for key, value in settings.items():
try: # will handle both ints and floats, even tuples with ints/floats
settings[key] = eval(value)
except NameError: # this means it's a string or a tuple with strings
get_val = list(map(str.strip, value.split(",")))
settings[key] = get_val if get_val[1:] else get_val[0]
This will work correctly for ints, floats as well as your comma separated values (it will evaluated it as a tuple, I guess that should be fine though I added a condition for that anyway).
Attempting to use script that was built in Python 2, and now use it in Python 3 without adding a version 2 onto system. For the script, the only error I get is related to a struct.unpack at this line....
def go_parse(rec_list):
size = (len(rec_list) - 4) / 4
first_arg = "%sI" % size
return struct.unpack(first_arg, (rec_list.rstrip ('\xff\xff\xff\xff')))
at line 4 of this function, I get the error:
TypeError: a bytes-like object is required, not 'str'
I read several other posts regarding this, and that it needs to be explicitly labeled as bytes, but I cant seem to figure out where to explicitly label that in this context. The other examples on SO i found here and here, did not provide much of an explanation to it. The struct pages don't seem to cover the error possibilities of 2-3...Only that struct.unpack(fmt, buffer) has the two arguments of fmt and buffer. Based on those examples, i have tried identifying this as bytes explicitly as a second arg using b, as well as bytes before the arguments and on the tuple for the .strip. I attempted return this as a bytearray, but that seemed to produce the same errors.
As an alternative, I am able to get the byte data I wanted into a list as shown below, what would be a way to get the list into unpack, attempt b'i' just looks at i as bytes.
list1 = [b'\x03\x00\x00\x00\xff\xff\xff\xff',
b'\x07\x00\x00\x00\x06\x00\x00\x00\xff\xff\xff\xff']
print(struct.unpack('<s', bytes(i)))
The bytes are of varying length, but all end in \xff\xff\xff\xff. The data I am looking at is text, just trying to bring it back to text.
I answered my own question spending some time in the Documentation, and someone pointing me in the right direction.
Generating a list of binary data that needed to be brought back to text for display, I used the codecs, a standard library. All my binary data was saved into a list named bin_list.
import codecs
bin_list = [b'Some Binary data', b'some more binary data']
for i in bin_list: # used the loop to print each to new line, nice and neat
print (codecs.decode(i, "utf-8", "ignore")) # or any other conversion avilable on codecs.
This is my first post, so I apologize if this has been answered previously. I have tried to look through the Python 3 documentation on string formatting and lists, and reviewed similar formatting questions here on SO.
I want to take the string (data1), break it into a list (bigData), and print out a statement using the list items. Eventually, the idea would be to read in a csv file, break it up, and print out a response, but I've tried to simplify the process since there's an error.
"Hello, John Doe. Your current balance is $53.44."
However, I'm not sure why the following code is throwing an IndexError, much less a tuple index.
data1 = "John,Doe,53.44"
bigData = data1.split(",")
bigData[-1] = float(bigData[-1])
print(bigData) # test - []'s indicate a list, not tuple?
greeting = "Hello, {} {}. Your current balance is ${}."
print(greeting.format(bigData))
My guess is that bigData is heterogeneous, which implies a tuple. If I substitute a string value instead of 53.44 (so data1 and bigData are homogeneous), it throws the same error.
data1 = "John,Doe,random"
bigData = data1.split(",")
print(bigData) # test - []'s indicate a list, not tuple?
greeting = "Hello, {} {}. Your current balance is {}."
print(greeting.format(bigData))
However, if I convert the original to Python 2.x string formatting, it formats correctly without an error.
data1 = "John,Doe,53.44"
bigData = data1.split(",")
bigData[-1] = float(bigData[-1])
print(bigData) # test - []'s indicate a list, not tuple?
greeting = "Hello, %s %s. Your current balance is $%.2f."
print(greeting % tuple(bigData))
Why is it converting my string to a tuple?
How do I write this work in Python 3?
Thank you.
Use the splat (*) to unpack your arguments (your format string wants three arguments but you only give it one, a list containter).
print(greeting.format(*bigData))
Also, you may want:
bigData[-1] = str(round(float(bigData[-1]), 2))
The str.format method takes positional arguments, not a single list. You need to unpack your list bigData using the * operator:
data1 = "John,Doe,random"
bigData = data1.split(",")
print(bigData) # test - []'s indicate a list, not tuple?
greeting = "Hello, {} {}. Your current balance is {}."
print(greeting.format(*bigData)) # here's the change
You're correct that bigData is a list, not a tuple, str.split returns a list.
The str.split() method returns a list, by definition.
I think you've misunderstood something you've read - heterogeneous vs. homogeneous refer to typical use cases of tuples vs. lists. Having the types of all the elements match or not does not magically cause the container to change to the other type!
I can see how this is surprising, though what surprises me is that the traceback doesn't show that the exception occurs in the format call.
Python's lists can be heterogenous just like tuples; this is because the common type they store is object references, which all things in Python are. The tuple is actually the argument list to the format method, in this case (bigData,). It ran out of arguments when looking for things to format, since you had three {} placeholders but only one argument (the list bigData). You can use greeting.format(*bigData) to unpack the list and use its contents as arguments.
The % formatting doesn't encounter this error because it actually expects a tuple (or one item) in the right operand.
A more idiomatic and legible approach might actually be to go to the csv module already:
import csv, io
data1 = "John,Doe,random"
for row in csv.DictReader(io.StringIO(data1),
"givenname surname balance".split()):
greeting = "Hello, {givenname} {surname}. Your current balance is {balance}."
print(greeting.format(**row))
This lets us assign meaningful names to the columns, including reordering them in the format string if needed. I've left out the float conversion, and by the way, decimal.Decimal may be better for that use.
I want to go through a list of complex numbers and write the real part as rows in a file. The following code does not make the job
for (column1, column2) in zip(t_inter, tp_inter):
file_t.write("%s\t\n" % column1.real)
file_tp.write("%s\t\n" % column2.real)
What's wrong? I guess the \n command goes to a new line but if I remove it, all data are written in a single line. The main issue is that I don't now a priori the number of elements in the t_inter and tp_inter lists, usually between 2 and 20 max. Therefore is there any command that writes rows without specifying the number of elements through %/s\t? At last, I want to add a constant as a first column, how to do it?
i think pprint is your way:
>>> import pprint
>>> pprint.__doc__
"Support to pretty-print lists, tuples, & dictionaries recursively.\n\nVery simp
le, but useful, especially in debugging data structures.\n\nClasses\n-------\n\n
PrettyPrinter()\n Handle pretty-printing operations onto a stream using a con
figured\n set of formatting parameters.\n\nFunctions\n---------\n\npformat()\
n Format a Python object into a pretty-printed representation.\n\npprint()\n
Pretty-print a Python object to a stream [default is sys.stdout].\n\nsaferepr
()\n Generate a 'standard' repr()-like value, but protect against recursive\n
data structures.\n\n"
>>>