Trouble iterating through lines in a file in Python - python

I have a class that simulates a scenario for calculating paths in a network using the distance vector routing algorithm. The class has an attribute, map_file, which is the name of a file that describes the connections in the network. Here is a snippet of code from the DVSimulator class:
def populate_map(self):
with open(self.map_file,'r') as f:
for line in f:
data = line.split()
length_of_link = data[2]
...
There is a file called "test_map1". It looks like this:
A B 2.1
B C 1.2
A C 1.0
C D 1.5
Every line in the file indicates a connection between two nodes. Here, Node A is connected to Node B with a distance of 2.1, Node B to Node C with a distance of 1.2, etc.
Here is the setUp() method from my pyunit TestDVSimulator class:
def setUp(self):
self.split_horizon_simulator1 = dv_simulator.DVSimulator("test_map1",True)
self.no_split_simulator1 = dv_simulator.DVSimulator("test_map1", False)
self.split_horizon_simulator2 = dv_simulator.DVSimulator("test_map2",True)
self.no_split_simulator2 = dv_simulator.DVSimulator("test_map2",True)
Here is a snippet of code from the test_populate_map() method in the TestDVSimulator class:
def test_populate_map(self):
"""Tests the populate_map() method in DVSimulator"""
splitty1 = self.split_horizon_simulator1
no_splitty1 = self.no_split_simulator1
splitty2 = self.split_horizon_simulator2
no_splitty2 = self.no_split_simulator2
splitty1.populate_map()
no_splitty1.populate_map()
splitty2.populate_map()
splitty2.populate_map()
...
Now, when I try to unittest the populate_map() method using the map_file shown above I get the following error message:
ERROR: Tests the populate_map() method in DVSimulator
----------------------------------------------------------------------
Traceback (most recent call last):
File "dv_simulator_test.py", line 28, in test_populate_map
splitty1.populate_map()
File "/home/grads/klepp/6760/DistanceVectorProject/dv_simulator.py", line 33, in populate_map
length_of_link = data[2]
IndexError: list index out of range
However, I know that each line in the file has length 3, and so data[2] is most definitely not out of range. Interestingly, if edit the populate_map() method as follows:
def populate_map(self):
with open(self.map_file,'r') as f:
for line in f.readlines():
print "line from map file: " + line
data = line.split()
print "data: " + str(data)
print str(data[0])
print str(data[1])
print str(data[2])
length_of_link = data[2]
...
the output looks like this:
line from map file: A B 2.1
data: ['A', 'B', '2.1']
A
B
2.1
line from map file: B C 1.2
data: ['B', 'C', '1.2']
B
C
1.2
line from map file: A C 1.0
data: ['A', 'C', '1.0']
A
C
1.0
line from map file: C D 1.5
data: ['C', 'D', '1.5']
C
D
1.5
line from map file:
data: []
EF
======================================================================
ERROR: Tests the populate_map() method in DVSimulator
----------------------------------------------------------------------
Traceback (most recent call last):
File "dv_simulator_test.py", line 28, in test_populate_map
splitty1.populate_map()
File "/home/grads/klepp/6760/DistanceVectorProject/dv_simulator.py", line 30, in populate_map
print str(data[0])
IndexError: list index out of range
That is to say, that str(data[0]) clearly prints out some value, in fact it prints it out four times in a row, but then it says that data[0] is out of range nonetheless. For some reason the code seems to be iterating through the lines in the file and calling line.split() on each line before it runs the line of code for length_of_link = data[2].
Does anyone know what is going wrong and how I can fix this?
Here is the full script of the populate_map() method in the DVSimulator class:
#The DVSimulator class simulates a Distance Vector Routing scenario
import routingtable
import dv_router
class DVSimulator:
def __init__(self, map_file, split_horizon,verbosity = False, test_destination=''):
self.routers_dictionary = {}
self.neighbors_dictionary = {} #a dictionary of router:dict pairs where dict is a dictionary of router values keyed by their names
self.breakables = [] #string tuples of (router1, router2) signifying a link to break upon convergence
self.using_split_horizon = split_horizon
self.map_file = map_file
self.verbose = verbosity
self.number_of_iterations = 0
self.test_dest = test_destination
def populate_map(self):
with open(self.map_file,'r') as f:
for line in f:
print "line from map file: " + line
data = line.split()
print "data: " + str(data)
print str(data[0])
print str(data[1])
print str(data[2])
length_of_link = data[2]
if len(data) == 4:
breakables.append((data[0],data[1]))
router1 = data[0]
router2 = data[1]
neighbor_pair = [router1, router2]
for each in neighbor_pair:
if each == router1:
other = router2
else:
other = router1
if each not in self.routers_dictionary:
self.routers_dictionary[each] = dv_router.DVRouter(each, self.using_split_horizon)
self.neighbors_dictionary[each] = {}
for router in self.routers_dictionary:
if router != other:
self.routers_dictionary[router].add_link(each)
self.routers_dictionary[each].routing_table.edit_distance_to(each, 0, each)
for each in neighbor_pair:
if each == router1:
other = router2
else:
other = router1
self.routers_dictionary[each].add_link(other,length_of_link)
self.neighbors_dictionary[each][other] = self.routers_dictionary[other]

The error lies in the test_map1 file. At the end of the file is a blank line. If the line is removed, the code runs as expected. An if statement, as suggested, could also be added to branch correctly for blank lines.

Related

How to fix TypeError: 'int' object is not callable from a divided number

Im trying to create a program to generate text with usernames from a txt file but I keep getting a TypeError: 'int' object is not iterable i know what this means but I have no idea how to fix my issue. I tried just doing y = 12 / 2 and the same error came up when i passed the for loop y i am really confused so if someone could help me that would be great
This is my code
def generateNum():
#imports random
from random import randint
for _ in range(10):
value = randint(0, 900000)
return(str(value))
def getNumOfLines( file):
#opens txt file
with open(file) as f:
Lines = f.readlines()
count = 0
# Strips the newline character
for line in Lines:
count += 1
return(count)
class debug:
def __init__(self, credsTxt, tagsTxt):
self.credsTxt = credsTxt
self.tagsTxt = tagsTxt
self.numOfCreds = getNumOfLines(credsTxt)
self.numOfTags = getNumOfLines(tagsTxt)
self.ammountPerAccount = round(self.numOfTags / self.numOfCreds)
def getComments(self):
#initializes comment
comment = ""
#opens txt file
file1 = open(self.tagsTxt, 'r')
count = 0
while True:
count += 1
# Get next line from file
line = file1.readline()
for i in self.ammountPerAccount:
# if line is empty
# end of file is reached
if not line:
break
comment += ' ' + line.strip() + ' ' + generateNum() + '.'
return(comment)
print(debug('D:/FiverrWork/user/instagram-bot/textGen/assets/login_Info.txt', 'D:/FiverrWork/user/instagram-bot/textGen/assets/tags.txt').getComments())
this is my stack trace error
Traceback (most recent call last):
File "d:\FiverrWork\user\textgenerator\textgenerator\txt.py", line 57, in <module>
print(debug('D:/FiverrWork/user/textgenerator/textgenerator/assets/login_Info.txt', 'D:/FiverrWork/user/textgenerator/textgenerator/assets/tags.txt').getComments())
File "d:\FiverrWork\user\textgenerator\textgenerator\txt.py", line 47, in getComments
for i in self.ammountPerAccount():
TypeError: 'int' object is not callable
Your for loop as posted cannot iterate over an int. You meant to iterate over a range():
for _ in range(self.ammountPerAccount):
# if line is empty
# end of file is reached
if not line:
break
comment += ' ' + line.strip() + ' ' + generateNum() + '.'
I used _ as a placeholder variable since the actual value of i each time was not used.

TypeError when trying to call functions in run

Edit; Thanks everyone! It's working now!
I'm trying to make a program that reads a csv file and calculates using that data. I have my csv_reader function and my average_temperature function working independently but I don't understand how to call them in the run() function.
I understand what the error means but I'm completely lost on how to fix it, but here's the closest I've gotten. It ends up with this error and then below it is the code:
Traceback (most recent call last):
File "main.py", line 100, in <module>
run()
File "main.py", line 82, in run
avgfile = average_temperature("Temperatures.csv", input)
File "main.py", line 40, in average_temperature
if filter in row[date_index]:
TypeError: 'in <string>' requires string as left operand, not builtin_function_or_method
Code:
import csv
date_index = 0
temp_index = 2
def csv_reader(file):
lst = []
with open("Temperatures.csv", 'r') as weather_file:
weather_reader = csv.reader(weather_file)
first_row = True
for row in weather_reader:
if first_row:
first_row = False
continue
lst.append(row)
return lst
def average_temperature(weather, filter):
thefile = csv_reader("Temperatures.csv")
sum = 0
len = 0
for row in thefile:
if filter in row[date_index]:
sum += float(row[temp_index])
len += 1
avg = sum / len
return avg
def run():
thefile = csv_reader("Temperatures.csv")
avgfile = average_temperature("Temperatures.csv", input)
print("{}".format(avgfile))
return
if __name__ == '__main__':
run()
The error is because input is the name of a built-in function. I think what you need to do is call it and get a value to pass as the filter parameter to your average_temperature() function something like this:
def run():
date_filter = input('What date? ') # Get value from user.
thefile = csv_reader("Temperatures.csv")
avgfile = average_temperature("Temperatures.csv", date_filter)
print("{}".format(avgfile))
return

I have written code for a simulateBeamRun and when i run it it says i have a syntax error

import beamModel
import personModel
def createPersonList(fileName):
"""Function will go through each line of file and
create a person object using the data provided in
the line and add it to a list
"""
theFile = open(fileName)
next(theFile)
for line in theFile:
aList = line.split(',')
bList = map(lambda s: s.strip('\n'), aList)
cList = [float(i) for i in bList]
return cList
def simulateBeamRun(personList, beam, times):
"""Takes a list of times covering the duration of
the simulation (0-35 s), the list of person
objects and a beam object to simulate a beam run
"""
ps = personList
b = beam
ts = times
dList = []
for time in ts:
eList = []
if ps is None:
return "No values in personList"
else:
for person in ps:
loadTuples = personModel.person.loadDisplacement(time)
if beamModel.b.L > loadTuples[1] > 0:
eList.append(loadTuples)
else:
return None
beamModel.b.setLoads(eList)
dList.append(beamModel.b.getMaxDeflection())
return (dList, eList)
this is the code i have created and when i run it, putting in the inputs in IPython console i get syntax error:
b = beamModel.beam(8.0E9, 1.333E-4, 5.0)
ps = createPersonList("personData.csv")
ts = numpy.linspace(0,35,500)
print simulateBeamRun(personList, beam, times)
File "<ipython-input-18-63875d960559>", line 1
print simulateBeamRun(personList, beam, times)
^
SyntaxError: invalid syntax

How to decode bencoded torrent data

I'm trying to extract size and name from a torrent file with decoding the content of a torrent file with bencode.
I did pip install bencode then I tested with one of the line of a torrent file as you can see there.
import bencode
blabla = 'd8:announce70:http://tracker.t411.io:56969/c5faa6720249d33ff6ba2af48640af89/announce7:comment29:https://www.t411.io/t/524280210:created by19:https://www.t411.io13:creation datei1431685353e4:infod6:lengthi14634059e4:name22:Charlie-Hebdo-1178.pdf12:piece lengthi262144e6:pieces1120:'
myprint = bencode.decode_string(blabla,1)
print myprint
This is the file that pip install put in the python lib:
from BTL import BTFailure
def decode_int(x, f):
f += 1
newf = x.index('e', f)
n = int(x[f:newf])
if x[f] == '-':
if x[f + 1] == '0':
raise ValueError
elif x[f] == '0' and newf != f+1:
raise ValueError
return (n, newf+1)
def decode_string(x, f):
colon = x.index(':', f)
n = int(x[f:colon])
if x[f] == '0' and colon != f+1:
raise ValueError
colon += 1
return (x[colon:colon+n], colon+n)
def decode_list(x, f):
r, f = [], f+1
while x[f] != 'e':
v, f = decode_func[x[f]](x, f)
r.append(v)
return (r, f + 1)
def decode_dict(x, f):
r, f = {}, f+1
while x[f] != 'e':
k, f = decode_string(x, f)
r[k], f = decode_func[x[f]](x, f)
return (r, f + 1)
decode_func = {}
decode_func['l'] = decode_list
decode_func['d'] = decode_dict
decode_func['i'] = decode_int
decode_func['0'] = decode_string
decode_func['1'] = decode_string
decode_func['2'] = decode_string
decode_func['3'] = decode_string
decode_func['4'] = decode_string
decode_func['5'] = decode_string
decode_func['6'] = decode_string
decode_func['7'] = decode_string
decode_func['8'] = decode_string
decode_func['9'] = decode_string
def bdecode(x):
try:
r, l = decode_func[x[0]](x, 0)
except (IndexError, KeyError, ValueError):
raise BTFailure("not a valid bencoded string")
if l != len(x):
raise BTFailure("invalid bencoded value (data after valid prefix)")
return r
from types import StringType, IntType, LongType, DictType, ListType, TupleType
class Bencached(object):
__slots__ = ['bencoded']
def __init__(self, s):
self.bencoded = s
def encode_bencached(x,r):
r.append(x.bencoded)
def encode_int(x, r):
r.extend(('i', str(x), 'e'))
def encode_bool(x, r):
if x:
encode_int(1, r)
else:
encode_int(0, r)
def encode_string(x, r):
r.extend((str(len(x)), ':', x))
def encode_list(x, r):
r.append('l')
for i in x:
encode_func[type(i)](i, r)
r.append('e')
def encode_dict(x,r):
r.append('d')
ilist = x.items()
ilist.sort()
for k, v in ilist:
r.extend((str(len(k)), ':', k))
encode_func[type(v)](v, r)
r.append('e')
encode_func = {}
encode_func[Bencached] = encode_bencached
encode_func[IntType] = encode_int
encode_func[LongType] = encode_int
encode_func[StringType] = encode_string
encode_func[ListType] = encode_list
encode_func[TupleType] = encode_list
encode_func[DictType] = encode_dict
try:
from types import BooleanType
encode_func[BooleanType] = encode_bool
except ImportError:
pass
def bencode(x):
r = []
encode_func[type(x)](x, r)
return ''.join(r)
The fact is that I don't really understand how can I decode my line with this bencode.
I already tried the def bdecode but this is the output:
root#debian:/home/florian/Téléchargements# python decript.py
Traceback (most recent call last):
File "decript.py", line 4, in <module>
myprint = bencode.bdecode(blabla)
File "/usr/local/lib/python2.7/dist-packages/bencode/__init__.py", line 68, in bdecode
raise BTFailure("not a valid bencoded string")
bencode.BTL.BTFailure: not a valid bencoded string
So I tried with the def decode_string but with decode_string(blabla, 1) it decode only the first word:
root#debian:/home/florian/Téléchargements# python decript.py
('announce', 11)
and the number like 2, 3, 4 don't work and display error like:
root#debian:/home/florian/Téléchargements# python decript.py
Traceback (most recent call last):
File "decript.py", line 4, in <module>
myprint = bencode.decode_string(blabla,10)
File "/usr/local/lib/python2.7/dist-packages/bencode/__init__.py", line 29, in decode_string
n = int(x[f:colon])
ValueError: invalid literal for int() with base 10: 'e70'
I want to decode all the line and I don't understand how can I do it with this bencode for example.
The string you're trying to decode seems to be truncated. it ends in pieces1120:, indicating that at least 1120 bytes should follow.
BEncoding is a binary format. It's only partially human-readable and not meant to be embedded in charset-sensitive things such as source code files. I suggest you read it straight from a file.
You have an incomplete Bencoded string.
The first part tells you there is a dictionary:
d...
which is supposed to be parsed until there is an e character. There is no such character in your input string.
A manual parse shows you have the keys announce, comment, created by, creation date, and info, where the latter is a nested dictionary with length, name, piece-length and pieces. Then your string stops; there is no value for pieces, and no e to mark the end of either the outer dictionary or the nested info dictionary. All we have is the type and length indicator: 1120.
You could try and use the decoding functions directly, but then take into account that they return the value and the offset:
>>> bencode.decode_string(blabla, 1)
('announce', 11)
11 is the offset for the next value:
>>> bencode.decode_string(blabla, 11)
('http://tracker.t411.io:56969/c5faa6720249d33ff6ba2af48640af89/announce', 84)
and 84 is again the next:
>>> bencode.decode_string(blabla, 84)
('comment', 93)
If you take into account that the string is incomplete and that not all encoded objects are strings, you can still decode what little is there.
The offset also tells you what function to use for decoding:
>>> blabla[1]
'8'
>>> bencode.decode_func[blabla[1]]
<function decode_string at 0x1004632a8>
The number here spells out how many characters to expect. So skipping the failing d dictionary mapping you get:
>>> offset = 1
>>> while True:
... value, offset = bencode.decode_func[blabla[offset]](blabla, offset)
... print value
...
announce
http://tracker.t411.io:56969/c5faa6720249d33ff6ba2af48640af89/announce
comment
https://www.t411.io/t/5242802
created by
https://www.t411.io
creation date
1431685353
info
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/Users/mj/Development/venvs/stackoverflow-2.7/lib/python2.7/site-packages/bencode/__init__.py", line 44, in decode_dict
while x[f] != 'e':
IndexError: string index out of range
which fails because you hit the nested dictionary without e. You could extract those keys too, by adding one to the last offset:
>>> offset
194
>>> blabla[offset]
'd'
>>> offset += 1
>>> while True:
... value, offset = bencode.decode_func[blabla[offset]](blabla, offset)
... print value
...
length
14634059
name
Charlie-Hebdo-1178.pdf
piece length
262144
pieces
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
IndexError: string index out of range
Or you could just read the data as binary data and not truncate it:
with open(torrentfilename, 'rb') as torrentfile:
torrent = bencode.bdecode(torrentfile.read())
# now you have a dictionary.

Taking a class and making a new class that is object oriented (python)

I have to figure out a way to take a code that was already given and improving it by making it a class that is object oriented.
This code: was already given and we use it for our new code. the file 'students2txt' is being extracted line by line (being split based on a ':') and the StudentFileReader class is imported into the new class StudentReport(object). And so the finished project is supposed give a student list that has ID numbers, first and last names, gpa's (all information is give in the 'students2.txt' I just have to make the code print all of the info.
filereader.py:
class StudentFileReader:
def __init__(self, inputSrc):
self._inputSrc = inputSrc
self._inputFile = None
def open(self):
self._inputFile = open(self._inputSrc, 'r')
def close(self):
self._inputFile.close()
self._inputFile = None
def fetchRecord(self):
line = self._inputFile.readline()
if line == "":
return None
record = StudentRecord()
#change
record.idNum = int(line)
record.firstName = self._inputFile.readline().rstrip().rsplit(':')
record.lastName = self._inputFile.readline().rstrip().rsplit(':')
record.classCode = int(self._inputFile.readline())
record.gpa = float(self._inputFile.readline())
return record
class StudentRecord:
def __init__(self):
self.idNum = 0
self.firstName = ""
self.lastName = ""
self.classCode = 0
self.gpa = 0.0
New file:
from filereader import StudentFileReader
class StudentReport(object):
def __init__(self):
self._theList = None
def loadRecords(self, filename):
self.reader = StudentFileReader(filename)
self.reader.open()
theList = []
record = self.reader.fetchRecord()
while record is not None:
theList.append(record)
record = self.reader.fetchRecord()
reader.close()
return theList
def sortByid(self):
self._studentList.sort(key = lambda rec: rec.idNum)
def sortByName(self):
pass
def __str__(self):
classNames = [ "", "Freshman", "Sophomore", "Junior", "Senior" ]
print( "LIST OF STUDENTS".center(50) )
print( "" )
print( "%-5s %-25s %-10s %-4s" % ('ID', 'NAME', 'CLASS', 'GPA'))
print( "%5s %25s %10s %4s" % ('-' * 5, '-' * 25, '-' * 10, '-' * 4))
# Print the body.
for record in theList :
print( "%5d %-25s %-10s %4.2f" % \
(record.idNum, \
record.lastName + ', ' + record.firstName,
classNames[record.classCode], record.gpa) )
# Add a footer.
print( "-" * 50 )
print( "Number of students:", len(theList) )
if __name__ == "__main__":
s = StudentReport()
s.loadRecords('students2.txt')
s.sortByName()
print str(s)
This code was taken from the textbook Data Structures and Algorithms Using Python. I'm supposed to make an object oriented class. I've started the StudentRecord class and written the __init__ but I'm not really sure what to do after that. When I try to run anything it gives me a invalid literal for int() with base 10 error. I'm very new to python so I'm not sure how to make any class object oriented easily..
edit: yes, the error came from the fetchRecord function
Traceback (most recent call last):
File "C:\Users\...\studentreport.py", line 24, in <module>
s.loadRecords('students2.txt')
File "C:\Users\...\studentreport.py", line 13, in loadRecords
record = self.reader.fetchRecord()
File "C:\Users\...\filereader.py", line 22, in fetchRecord
record.idNum = int(line)
ValueError: invalid literal for int() with base 10: '10015:John:Smith:2:3.01\n'
Your line parsing code doesn't match the format of the file.
You are trying to interpret the whole line as an integer, but the line contains more.
Perhaps you wanted to split the line first? That one line contains all elements of the record:
parts = line.strip().split(':')
record.idNum = int(parts[0])
record.firstName = parts[1]
record.lastName = parts[2]
record.classCode = parts[3]
record.gpa = float(parts[4])
You can override the original StudentFileReader.fetchRecord()) method by subclassing the class in your own code:
class MyStudentFileReader(StudentFileReader):
def fetchRecord(self):
line = self._inputFile.readline()
if not line:
return None
record = StudentRecord()
parts = line.strip().split(':')
record.idNum = int(parts[0])
record.firstName = parts[1]
record.lastName = parts[2]
record.classCode = parts[3]
record.gpa = float(parts[4])
return record
Then use MyStudentFileReader() instead of StudentFileReader().
You need to split your line before you start trying to convert the pieces into the formats you want for your individual data items. Right now, you're calling readline repeatedly, so each of the values you're calculating for a student comes from a separate line from the file.
Instead, try splitting and unpacking the result directly into local variables:
idNum, firstName, lastName, classCode, GPA = line.rstrip().split(':')
Then do whatever conversions each of those need (e.g. record.idNum = int(idNum)).

Categories