Python line too long for string with arguments - python

Hey I have the following code:
#node.route('/txions')
def transactions():
txions_str = ""
for txion in this_nodes_transactions:
txions_str + "FROM: %s \n TO: %s \n AMOUNT: %d \n" % (txion['from'], txion['to'], txion['amount'])
return txions_str
I get my Python linter complaining that the line is too long for txions_str, what is the correct way to format this line for when using mulitple parameters?

First, it's worth pointing out that you are returning an empty string there...
Anyways, you already have line breaks.
So, break your code to accommodate them
#node.route('/txions')
def transactions():
txions = []
for txion in this_nodes_transactions:
txions.append("FROM: {} ".format(txion['from']))
txions.append(" TO: {} ".format(txion['to']))
txions.append(" AMOUNT: {} ".format(txion['amount']))
return '\n'.join(txions)
Python also supports multi-line strings and line-continuation characters, but those dont seem needed here.

Related

Improper center() alignment of Python strings

I'm working on a projects that shows basic user details.
Here's the respective code that I'm having problem with.
#wrap
def show(self, *ids):
for id in ids:
try:
user = self.api.get_user(id)
print(user.name.center(80, '~'))
print('%d Followers %d Following'.center(80, '~') %
(user.followers_count, user.friends_count))
except Exception:
print('Error')
finally:
print()
The code shows both the lines with the max-width of 80 chars.
At this point it should only print maximum of 80 chars on each line.
But I'm getting this output :
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Twitter~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~58312564 Followers 1 Following~~~~~~~~~~~~~~~~~~~~~~~~~~~
The first line is seems perfect but the second line is really not looking at the center.
I read the docs and I also tried using .format() inside the print statement but I'm getting the same problem.
How can I print both the line contents at the center?
(One character difference is considerable)
Please help.
Does This work for you?
followers_count= 5831256
friends_count = 1
var = f" {followers_count} Followers {friends_count} Following "
print(f"{' Twitter ':~^80}")
print(f"{var:~^80}")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Twitter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~ 5831256 Followers 1 Following ~~~~~~~~~~~~~~~~~~~~~~~~
Adapt it to your method definition.
Note: var is unnecessary

Read Null terminated string in python

I'm trying to read a null terminated string but i'm having issues when unpacking a char and putting it together with a string.
This is the code:
def readString(f):
str = ''
while True:
char = readChar(f)
str = str.join(char)
if (hex(ord(char))) == '0x0':
break
return str
def readChar(f):
char = unpack('c',f.read(1))[0]
return char
Now this is giving me this error:
TypeError: sequence item 0: expected str instance, int found
I'm also trying the following:
char = unpack('c',f.read(1)).decode("ascii")
But it throws me:
AttributeError: 'tuple' object has no attribute 'decode'
I don't even know how to read the chars and add it to the string, Is there any proper way to do this?
Here's a version that (ab)uses __iter__'s lesser-known "sentinel" argument:
with open('file.txt', 'rb') as f:
val = ''.join(iter(lambda: f.read(1).decode('ascii'), '\x00'))
How about:
myString = myNullTerminatedString.split("\x00")[0]
For example:
myNullTerminatedString = "hello world\x00\x00\x00\x00\x00\x00"
myString = myNullTerminatedString.split("\x00")[0]
print(myString) # "hello world"
This works by splitting the string on the null character. Since the string should terminate at the first null character, we simply grab the first item in the list after splitting. split will return a list of one item if the delimiter doesn't exist, so it still works even if there's no null terminator at all.
It also will work with byte strings:
myByteString = b'hello world\x00'
myStr = myByteString.split(b'\x00')[0].decode('ascii') # "hello world" as normal string
If you're reading from a file, you can do a relatively larger read - estimate how much you'll need to read to find your null string. This is a lot faster than reading byte-by-byte. For example:
resultingStr = ''
while True:
buf = f.read(512)
resultingStr += buf
if len(buf)==0: break
if (b"\x00" in resultingStr):
extraBytes = resultingStr.index(b"\x00")
resultingStr = resultingStr.split(b"\x00")[0]
break
# now "resultingStr" contains the string
f.seek(0 - extraBytes,1) # seek backwards by the number of bytes, now the pointer will be on the null byte in the file
# or f.seek(1 - extraBytes,1) to skip the null byte in the file
(edit version 2, added extra way at the end)
Maybe there are some libraries out there that can help you with this, but as I don't know about them lets attack the problem at hand with what we know.
In python 2 bytes and string are basically the same thing, that change in python 3 where string is what in py2 is unicode and bytes is its own separate type, which mean that you don't need to define a read char if you are in py2 as no extra work is required, so I don't think you need that unpack function for this particular case, with that in mind lets define the new readString
def readString(myfile):
chars = []
while True:
c = myfile.read(1)
if c == chr(0):
return "".join(chars)
chars.append(c)
just like with your code I read a character one at the time but I instead save them in a list, the reason is that string are immutable so doing str+=char result in unnecessary copies; and when I find the null character return the join string. And chr is the inverse of ord, it will give you the character given its ascii value. This will exclude the null character, if its needed just move the appending...
Now lets test it with your sample file
for instance lets try to read "Sword_Wea_Dummy" from it
with open("sword.blendscn","rb") as archi:
#lets simulate that some prior processing was made by
#moving the pointer of the file
archi.seek(6)
string=readString(archi)
print "string repr:", repr(string)
print "string:", string
print ""
#and the rest of the file is there waiting to be processed
print "rest of the file: ", repr(archi.read())
and this is the output
string repr: 'Sword_Wea_Dummy'
string: Sword_Wea_Dummy
rest of the file: '\xcd\xcc\xcc=p=\x8a4:\xa66\xbfJ\x15\xc6=\x00\x00\x00\x00\xeaQ8?\x9e\x8d\x874$-i\xb3\x00\x00\x00\x00\x9b\xc6\xaa2K\x15\xc6=;\xa66?\x00\x00\x00\x00\xb8\x88\xbf#\x0e\xf3\xb1#ITuB\x00\x00\x80?\xcd\xcc\xcc=\x00\x00\x00\x00\xcd\xccL>'
other tests
>>> with open("sword.blendscn","rb") as archi:
print readString(archi)
print readString(archi)
print readString(archi)
sword
Sword_Wea_Dummy
ÍÌÌ=p=Š4:¦6¿JÆ=
>>> with open("sword.blendscn","rb") as archi:
print repr(readString(archi))
print repr(readString(archi))
print repr(readString(archi))
'sword'
'Sword_Wea_Dummy'
'\xcd\xcc\xcc=p=\x8a4:\xa66\xbfJ\x15\xc6='
>>>
Now that I think about it, you mention that the data portion is of fixed size, if that is true for all files and the structure on all of them is as follow
[unknow size data][know size data]
then that is a pattern we can exploit, we only need to know the size of the file and we can get both part smoothly as follow
import os
def getDataPair(filename,knowSize):
size = os.path.getsize(filename)
with open(filename, "rb") as archi:
unknown = archi.read(size-knowSize)
know = archi.read()
return unknown, know
and by knowing the size of the data portion, its use is simple (which I get by playing with the prior example)
>>> strins_data, data = getDataPair("sword.blendscn", 80)
>>> string_data, data = getDataPair("sword.blendscn", 80)
>>> string_data
'sword\x00Sword_Wea_Dummy\x00'
>>> data
'\xcd\xcc\xcc=p=\x8a4:\xa66\xbfJ\x15\xc6=\x00\x00\x00\x00\xeaQ8?\x9e\x8d\x874$-i\xb3\x00\x00\x00\x00\x9b\xc6\xaa2K\x15\xc6=;\xa66?\x00\x00\x00\x00\xb8\x88\xbf#\x0e\xf3\xb1#ITuB\x00\x00\x80?\xcd\xcc\xcc=\x00\x00\x00\x00\xcd\xccL>'
>>> string_data.split(chr(0))
['sword', 'Sword_Wea_Dummy', '']
>>>
Now to get each string a simple split will suffice and you can pass the rest of the file contained in data to the appropriated function to be processed
Doing file I/O one character at a time is horribly slow.
Instead use readline0, now on pypi: https://pypi.org/project/readline0/ . Or something like it.
In 3.x, there's a "newline" argument to open, but it doesn't appear to be as flexible as readline0.
Here is my implementation:
import struct
def read_null_str(f):
r_str = ""
while 1:
back_offset = f.tell()
try:
r_char = struct.unpack("c", f.read(1))[0].decode("utf8")
except:
f.seek(back_offset)
temp_char = struct.unpack("<H", f.read(2))[0]
r_char = chr(temp_char)
if ord(r_char) == 0:
return r_str
else:
r_str += r_char

Python Triple-quoted strings with variable

Trying to write to a file with variables, but that is returning error:
template = """1st header line
second header line
There are people in rooms
and the %s
"""
with open('test','w') as myfile:
myfile.write(template.format()) % (variable)
The .format method expects you to template the blanks to be filled in your string with the {}-style, not %s. It also expects the interpolated values to be given as its arguments.
template = """1st header line
second header line
There are people in rooms
and the {}
"""
myfile.write(template.format(variable))
The given string literal is printf-style string. Use str % arg:
with open('test', 'w') as myfile:
myfile.write(template % variable)
To use str.format, you should use placeholder {} or {0} instead of %s.
The Error
myfile.write(template.format()) returns nothing to which you are using % operator to concatenate
Minimal Edit
You can perfectly use %s .The problem is you mismatched parenthesis and the parenthesis i.e. ) should be after your variable as in myfile.write(template.format() % (variable)). But as template.format() is redundant, it can be ignored. Thus the correct way is
myfile.write(template % (variable))
Note:- Any string with an empty format() and no {} in the string returns the string itself

Python Not Web Linking Entire variable in str.ljust

I have Python code that pulls info from a sqlite database and then write to a html file. I'm trying to write as preformatted text and the code below places the text in columns like I am try to accomplish, but (obviously) the link is the entire length of the string, including the whitespace to the right from the .ljust.
How can I get it to only link the text of item.title instead of the entire string, plus whitespace?
content += '%s %s' % (item.slug, str(item.title).ljust(25), item.date.ljust(10)
Edit
title = str(item.title)
spaces = ' '*(25-len(title)) if len(title) <= 25 else ''
'%s%s %s' % (item.slug, title, spaces, item.date.ljust(10))
If you must do it on one line, the following should work for you:
content += '%s %s %s' % tuple(itertools.chain((item.slug,),
str(item.title).ljust(25).split(" ", 1), (item.date.ljust(10),)))
However the following should be a little easier to read
values = [item.slug]
values += str(item.title).ljust(25).split(" ", 1)
values.append(item.date.ljust(10))
content += '%s %s %s' % values
Notice I've added one extra space to your formatting string to make up for the one lost to the string split operation.
EDIT: The above code fails when item.title is greater than 25 characters. A revised version is below.
title, spaces = (str(item.title).ljust(25)+" ").split(" ", 1)
content += '%s%s %s' % (item.slug, title,
spaces, item.date.ljust(10))
This version adds a space to the end of the justified title, so the split operation is guaranteed to return a tuple of length 2.

Python Textwrap - forcing 'hard' breaks

I am trying to use textwrap to format an import file that is quite particular in how it is formatted. Basically, it is as follows (line length shortened for simplicity):
abcdef <- Ok line
abcdef
ghijk <- Note leading space to indicate wrapped line
lm
Now, I have got code to work as follows:
wrapper = TextWrapper(width=80, subsequent_indent=' ', break_long_words=True, break_on_hyphens=False)
for l in lines:
wrapline=wrapper.wrap(l)
This works nearly perfectly, however, the text wrapping code doesn't do a hard break at the 80 character mark, it tries to be smart and break on a space (at approx 20 chars in).
I have got round this by replacing all spaces in the string list with a unique character (#), wrapping them and then removing the character, but surely there must be a cleaner way?
N.B Any possible answers need to work on Python 2.4 - sorry!
A generator-based version might be a better solution for you, since it wouldn't need to load the entire string in memory at once:
def hard_wrap(input, width, indent=' '):
for line in input:
indent_width = width - len(indent)
yield line[:width]
line = line[width:]
while line:
yield '\n' + indent + line[:indent_width]
line = line[indent_width:]
Use it like this:
from StringIO import StringIO # Makes strings look like files
s = """abcdefg
abcdefghijklmnopqrstuvwxyz"""
for line in hard_wrap(StringIO(s), 12):
print line,
Which prints:
abcdefg
abcdefghijkl
mnopqrstuvw
xyz
It sounds like you are disabling most of the functionality of TextWrapper, and then trying to add a little of your own. I think you'd be better off writing your own function or class. If I understand you right, you're simply looking for lines longer than 80 chars, and breaking them at the 80-char mark, and indenting the remainder by one space.
For example, this:
s = """\
This line is fine.
This line is very long and should wrap, It'll end up on a few lines.
A short line.
"""
def hard_wrap(s, n, indent):
wrapped = ""
n_next = n - len(indent)
for l in s.split('\n'):
first, rest = l[:n], l[n:]
wrapped += first + "\n"
while rest:
next, rest = rest[:n_next], rest[n_next:]
wrapped += indent + next + "\n"
return wrapped
print hard_wrap(s, 20, " ")
produces:
This line is fine.
This line is very lo
ng and should wrap,
It'll end up on a
few lines.
A short line.

Categories