Pass a value to the ftp.retrbinary callback - python

I'm writing a module that uses FTPLib to fetch files. I want to find a way to pass a value(in addition to the block) to the callback. Essentially, my callback is
def handleDownload(block, fileToWrite):
fileToWrite.write(block)
And I need to call
ftp.retrbinary('RETR somefile', handleDownload)
And have it pass a file handle. Is there a way to do this?

You can close over the fileToWrite variable with a lambda:
fileToWrite = open("somefile", "wb")
ftp.retrbinary("RETR somefile", lambda block: handleDownload(block, fileToWrite))

This code worked for me.
class File:
cleared = False
def __init__(self, filepath):
self.filepath = filepath
def write(self,block):
if not File.cleared:
with open(f'{self.filepath}', 'wb') as f:
File.cleared = True
with open(f'{self.filepath}', 'ab') as f:
f.write(block)
else:
with open(f'{self.filepath}', 'ab') as f:
f.write(block)
ftp.retrbinary("RETR somefile", File(filepath).write)

Related

How to make json file a list in Python

as said, I'd like to open a json file and make it into a list, in order to append new elements to it and then dump all back into the json file.
Here is my code(the commented part is what I previously tried):
class Carta:
def __init__(self,filename):
self.__filename = filename
self.__lista = []
# try:
# f = open(self.__filename,"r")
# except:
# f = open(self.__filename, "w")
# f.close()
# f = open(self.__filename, "r")
with open(self.__filename) as file:
self.__lista = json.load(file)
# read=json.load(f)
# for c in leggi:
# self.__lista.append(c)
# print(self.__lista)
# f.close()
def add(self, c):
self.__lista.append(c)
def save(self):
f = open(self.__filename, "w")
for c in self.__lista:
f.write("%s\n" % str(c))
f.close()
It wouldn't work if you read from a JSON file, json list and then write custom string. Because next time you read the JSON file it's gonna fail.
So, during write/save you should make it json itself. Here's the code the explains how to do it.
import json
class Carta:
def __init__(self, filename):
self.__filename = filename
self.__lista = list()
self.read_from_json_file()
def read_from_json_file(self):
with open(self.__filename) as file:
self.__lista = json.load(file)
def write_to_json_file(self):
with open(self.__filename, 'w') as f:
json.dump(self.__lista, f)
def add(self, value):
self.__lista.append(value)
The reason you should use with open(filename, mode) as f: instead of f = open(filename) is because at the end of with block the file is automatically closed. Otherwise you've to call f.close() every time you open a file.
json.load - reads json data from file, converts to python data type/structure.
json.dump - read python data type/structure, converts it into string and stores it in the file (file handle) and saves the file.
Using pdb to trace errors
import json
import pdb
class Carta:
def __init__(self, filename):
self.__filename = filename
self.__lista = list()
self.read_from_json_file()
def read_from_json_file(self):
pdb.set_trace() # to pause execution and start debugger
# When paused,
# type n to continue to next line,
# type c to continue execution or to continue to the next loop
# type b <file_name>:<line_number> to add another break point, where <file_name> and <line_number> are place holders
# Example, b /home/username/hello.py:43, will add breakpoint at 43 line of hello.py in /home/username path
# type q to quit debugger and halt execution
with open(self.__filename) as file:
self.__lista = json.load(file)
def write_to_json_file(self):
with open(self.__filename, 'w') as f:
json.dump(self.__lista, f)
def add(self, value):
# Second breakpoint
pdb.set_trace()
self.__lista.append(value)
Or just run your file with
python -m pdb file.py and then add breakpoints. It will pause in the first line itself and return you a (pdb) console where you can add breakpoint.
import json
#read from file
with open("demofile.txt", "r") as f: x = f.read()
#parse
y = json.loads(x)
#edit
y["user"] = { "fname": "John", "lname": "Who"}
#save to file
with open("demofile.txt", "w") as f: f.write(json.dumps(y))
https://repl.it/#KrzysztofPecyna/PythonJsonExample
To read JSON from a file:
import json
with open('data.txt') as json_file:
data = json.load(json_file)
To add new data:
data['key'] = "value"
To write JSON to a file:
with open('data.txt', 'w') as outfile:
json.dump(data, outfile)

Saving integers within pickle and calling them

So this is my code, I would like to save the value 'test' to the file so that it can be called to be used when the program is reopened.
import pickle
test = 0
def Save():
with open('objs.pickle', 'wb') as f:
pickle.dump(test, f)
def Load():
with open('objs.pickle', 'rb') as f:
test = pickle.load(f)
The problem with this code is that when I reopen the program and run in and then type in Load(), it says that 'test' is still equal to 0. (Missing somehting obvious probably)
And so my question is, how could I fix the problem issued in italics?
The global variable test has nothing to do with test inside the function Load(). Change your function to:
def Load():
with open('objs.pickle', 'rb') as f:
return pickle.load(f)
Now this function returns the value it reads from the pickle file.
Call it like this:
print(Load())
Side note: By convention functions names are all lowercase in Python. So the function name should be actually load().
EDIT
The whole program in a better style:
import pickle
def save(file_name, obj):
with open(file_name, 'wb') as fobj:
pickle.dump(obj, fobj)
def load(file_name):
with open(file_name, 'rb') as fobj:
return pickle.load(fobj)
def main():
test = 0
file_name = 'objs.pickle'
save(file_name, test)
print(load(file_name))
if __name__ == '__main__':
main()

Save/load function in Python

I have to create a save function and a load function that saves a dictionary in the format of:
123;Kalle;
123;Maria;
321;Anna;
321;Olle;
My dictionary is supposed to look like a phonebook, with the key being the name and the value is the phonenumber:
telebook = {"jacob":"8472923777", "nisse":"092563243"}
How can I write a function that saves my phonebook in the format mentioned? It should look like this:
8472923777;jacob;
This is my current code:
def save(lista, telebook):
import pickle
filename = lista[1]
f = open(filename, "w")
pickle.dump(telebook, f)
f.close()
print telebook
def load(lista, telebook):
import pickle
try:
filename = lista[1]
f = open(filename, "r")
telebook_1 = pickle.load( f )
telebook.clear()
telebook.update(telebook_1)
f.close()
print telebook
except:
print "This file doesn't exist"
EDIT:
My save function was easier than I thought, managed to solve it on my own. Not sure how to get the load function to work though.
book = raw_input("telebook> ").lower()
lista = book.split()
def save(lista, telebook):
filename = lista[1]
f = open(filename, "w")
for name, num in telebook.items():
f.write(num+";"+name+";"+"\n")
f.close()
print telebook
My load is the same as before but obviously I can't use that one anymore.
def save(telebok, filepath):
with open(filepath, 'w') as outfile:
for name,num in telebok.items():
outfile.write("{};{};\n".format(num, name))
And to get it back:
import csv
def load(filepath):
with open(filepath) as infile:
telebok = dict((v,k) for v,k,_ in csv.reader(infile, delimiter=';'))
return telebok

python class file context manager

I am trying to open a file in a class and close it on exit in this manner.
class PlanetaryImage(object):
#classmethod
def open(cls, filename):
with open(filename, 'rb') as fp:
return cls(fp, filename)
def __init__(self, stream, filename=None, memory_layout='DISK'):
self.filename = filename
self._parse_data(stream)
def _parse_data(self, stream):
data_stream = stream
try:
if self.data_filename is not None:
dirpath = os.path.dirname(self.filename)
data_file = os.path.abspath(
os.path.join(dirpath, self.data_filename))
data_stream = open(data_file, 'rb')
data_stream.seek(self.start_byte)
if self.format in self.BAND_STORAGE_TYPE:
return getattr(self, self.BAND_STORAGE_TYPE[self.format])(data_stream)
raise Exception('Unkown format (%s)' % self.format)
finally:
data_stream.close()
There are certain cases where I am having to use open one more file in _parse_data function. I wanted to use with but the if statements make it difficult. Any suggestions on how to make the try section more pythonic.
There's no reason for _parse_data to try to open a file. It should be the caller's responsibility to either use PlanetaryImage.open with a file name or to provide an open file handle to __init__. _parse_data should do just one thing: parse the data from its stream argument.
class PlanetaryImage(object):
#classmethod
def open(cls, filename):
with open(filename, 'rb') as fp:
return cls(fp, filename)
def __init__(self, stream, memory_layout='DISK'):
self._parse_data(stream)
def _parse_data(self, data_stream):
try:
data_stream.seek(self.start_byte)
if self.format in self.BAND_STORAGE_TYPE:
return getattr(self, self.BAND_STORAGE_TYPE[self.format])(data_stream)
raise Exception('Unkown format (%s)' % self.format)
finally:
data_stream.close()
Now, there are simply two options for using the class:
with open(filename, 'rb') as fp:
x = PlanetaryImage(fp)
...
or
x = PlanetaryImage(filename)
....

Python / Function parameters

Main objective:
function to read top score from text file.
Parameters to be passed onto function:
A text document!
def highscore():
try:
text_file = open ("topscore.txt", "r")
topscore = int(text_file.read())
print topscore
text_file.close()
return topscore
except:
print "Error - no file"
topscore = 0
return topscore
How to add a text file as a parameter?
def highscore(filename):
try:
text_file = open (filename, "r")
Oh, and you should stop putting more code than necessary into your try block. A clean solution would look like this:
def highscore(filename):
if not os.path.isfile(filename):
return 0
with open(filename, 'r') as f:
return int(f.read())
Or, if you prefer to return 0 in any case where reading the file fails:
def highscore(filename):
try:
with open(filename, 'r') as f:
return int(f.read())
except:
return 0
Another option is to provide a keyword argument. That may be useful if, for example, you have old code that uses this function and can't be updated for some strange reason. Keyword arguments can include a default value.
def highscore( filename = "filename.txt" ):
try:
text_file = open (filename, "r")
Then you can call this function as before to use the default value, "filename.txt":
highscore()
Or specify any new filename:
highscore( filename = "otherfile.csv" )
See the python documentation for more information.
http://docs.python.org/tutorial/controlflow.html#default-argument-values
def highscore(filename):
try:
text_file = open(filename, "r")
...
Simply add a variable identifier (e.g.,filename) to your parameter list and then refer to it when you open the file.
Then call your function with the filename you choose.
topscore = highscore("topscore.txt")

Categories