how to interact between 2 python scripts? - python-3.x

I'm writing program to run one script that takes pictures and writes the number into txt file and after its done it should tell other file you can read that txt file. I can't seem to import this "Perrasytas" variable to other script. It just says its not defined.
Script1
if line==('echo:SD card ok'):
Perrasytas=0
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
GPIO.output(4,GPIO.LOW)
with open(cnt, 'r') as f:
line = f.read()
num = int((line.split())[0])+1
with open(cnt, 'w') as f:
f.write(str(num))
Perrasytas=1
Script2
import Script1
if Script1.Perrasytas == 1:
cnt2='/home/pi/Prints_photos/counter.txt'
with open(cnt2, 'r') as f:
num2 = f.read()
If I leave "Perrasytas=0" variable at the first line of code it does import, but it doesn't change its state..
is it even possible to do such communication thing between scripts?

Importing a module only runs its code once -- the first time you import it. Since the value of line is probably not equal to "echo:..." when the import happens, the if block is never entered, and the Perrasytas variable is never set.
You could put all of that code into a function, and return the value of Perrasytas from that function. That way, you can execute that code whenever you call the function.
def get_perrasytas(line):
if line==('echo:SD card ok'):
Perrasytas=0
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
GPIO.output(4,GPIO.LOW)
with open(cnt, 'r') as f:
line = f.read()
num = int((line.split())[0])+1
with open(cnt, 'w') as f:
f.write(str(num))
Perrasytas=1
return Perrasytas
Then, you could call it like so:
import Script1
if Script1.get_perrasytas(line) == 1:
cnt2='/home/pi/Prints_photos/counter.txt'
with open(cnt2, 'r') as f:
num2 = f.read()
Note that you will need to have line before you call the function, or include a way to get line inside the function.

Related

Dataclass that can 'yeld' a new line from a file when requested

With something like the following code I've used until now to create a generator that would read a very big file line by line and allow me to work on each line as I wish.
def readfile(self):
with open(self.filename) as infile:
for line in infile:
yield line
What would be a good way to edit this so as to get the new line every time I am calling a function, e.g.:
#dataclass
class Reader:
filename: str
line: int = field(default=None)
def __post_init__(self):
self.file = open(self.filename)
self.line = 1
def __del__(self):
self.file.close()
def next_line(self):
...
So ideally I would call next_line and get back the next line of file filename.
I don't quite understand why you want to create a class just to call a method that returns the next line of a file so I created just a function. If you need to, you can use it as a method in some class as well.
A file object IS already a generator. Therefore you can call the __next()__ method directly on the file object. __next__() returns the next value of a generator.
def next_line():
return f.__next__()
with open('file.txt') as f:
print(next_line()) # a line
second = next_line() # next line
print(next_line()) # next line
Or you can even omit the function completely:
with open('file.txt') as f:
print(f.__next__()) # a line
second = f.__next__() # next line
print(f.__next__()) # next line

Reading from file raises IndexError in python

I am making an app which will return one random line from the .txt file. I made a class to implement this behaviour. The idea was to use one method to open file (which will remain open) and the other method which will close it after the app exits. I do not have much experience in working with files hence the following behaviour is strange to me:
In __init__ I called self.open_file() in order to just open it. And it works fine to get self.len. Now I thought that I do not need to call self.open_file() again, but when I call file.get_term()(returns random line) it raises IndexError (like the file is empty), But, if I call file.open_file() method again, everything works as expected.
In addition to this close_file() method raises AttributeError - object has no attribute 'close', so I assumed the file closes automatically somehow, even if I did not use with open.
import random
import os
class Pictionary_file:
def __init__(self, file):
self.file = file
self.open_file()
self.len = self.get_number_of_lines()
def open_file(self):
self.opened = open(self.file, "r", encoding="utf8")
def get_number_of_lines(self):
i = -1
for i, line in enumerate(self.opened):
pass
return i + 1
def get_term_index(self):
term_line = random.randint(0, self.len-1)
return term_line
def get_term(self):
term_line = self.get_term_index()
term = self.opened.read().splitlines()[term_line]
def close_file(self):
self.opened.close()
if __name__ == "__main__":
print(os.getcwd())
file = Pictionary_file("pictionary.txt")
file.open_file() #WITHOUT THIS -> IndexError
file.get_term()
file.close() #AttributeError
Where is my mistake and how can I correct it?
Here in __init__:
self.open_file()
self.len = self.get_number_of_lines()
self.get_number_of_lines() actually consumes the whole file because it iterates over it:
def get_number_of_lines(self):
i = -1
for i, line in enumerate(self.opened):
# real all lines of the file
pass
# at this point, `self.opened` is empty
return i + 1
So when get_term calls self.opened.read(), it gets an empty string, so self.opened.read().splitlines() is an empty list.
file.close() is an AttributeError, because the Pictionary_file class doesn't have the close method. It does have close_file, though.

How to save command line file as .txt file every time. In CMD need to display the speedtest output save the those command line as .txt file

This is the program as given below
import os
import time
index=0
file=open("out_{index}.txt", 'a')
while True:
ps=os.system(f"speedtest.exe")
file.append(ps)
index+=1
time.sleep(4)
I believe it is file.write() and not file.append().
I think you want to write to a new file every time.
I would do this.
import time
import os
index = 0
while True:
ps = os.system("speedtest.exe")
with open(f"out_{index}.txt", 'w+') as f:
f.write(ps)
index += 1
time.sleep(4)
However, if you want to write in the same file.
I would do this.
import time
import os
with open("out_file.txt", 'a+') as f:
index = 0
while True:
ps = os.system("speedtest.exe")
f.write(ps)
index += 1
time.sleep(4)

Exporting Python to Excel is only showing one row of data [duplicate]

I have data which is being accessed via http request and is sent back by the server in a comma separated format, I have the following code :
site= 'www.example.com'
hdr = {'User-Agent': 'Mozilla/5.0'}
req = urllib2.Request(site,headers=hdr)
page = urllib2.urlopen(req)
soup = BeautifulSoup(page)
soup = soup.get_text()
text=str(soup)
The content of text is as follows:
april,2,5,7
may,3,5,8
june,4,7,3
july,5,6,9
How can I save this data into a CSV file.
I know I can do something along the lines of the following to iterate line by line:
import StringIO
s = StringIO.StringIO(text)
for line in s:
But i'm unsure how to now properly write each line to CSV
EDIT---> Thanks for the feedback as suggested the solution was rather simple and can be seen below.
Solution:
import StringIO
s = StringIO.StringIO(text)
with open('fileName.csv', 'w') as f:
for line in s:
f.write(line)
General way:
##text=List of strings to be written to file
with open('csvfile.csv','wb') as file:
for line in text:
file.write(line)
file.write('\n')
OR
Using CSV writer :
import csv
with open(<path to output_csv>, "wb") as csv_file:
writer = csv.writer(csv_file, delimiter=',')
for line in data:
writer.writerow(line)
OR
Simplest way:
f = open('csvfile.csv','w')
f.write('hi there\n') #Give your csv text here.
## Python will convert \n to os.linesep
f.close()
You could just write to the file as you would write any normal file.
with open('csvfile.csv','wb') as file:
for l in text:
file.write(l)
file.write('\n')
If just in case, it is a list of lists, you could directly use built-in csv module
import csv
with open("csvfile.csv", "wb") as file:
writer = csv.writer(file)
writer.writerows(text)
I would simply write each line to a file, since it's already in a CSV format:
write_file = "output.csv"
with open(write_file, "wt", encoding="utf-8") as output:
for line in text:
output.write(line + '\n')
I can't recall how to write lines with line-breaks at the moment, though :p
Also, you might like to take a look at this answer about write(), writelines(), and '\n'.
To complement the previous answers, I whipped up a quick class to write to CSV files. It makes it easier to manage and close open files and achieve consistency and cleaner code if you have to deal with multiple files.
class CSVWriter():
filename = None
fp = None
writer = None
def __init__(self, filename):
self.filename = filename
self.fp = open(self.filename, 'w', encoding='utf8')
self.writer = csv.writer(self.fp, delimiter=';', quotechar='"', quoting=csv.QUOTE_ALL, lineterminator='\n')
def close(self):
self.fp.close()
def write(self, elems):
self.writer.writerow(elems)
def size(self):
return os.path.getsize(self.filename)
def fname(self):
return self.filename
Example usage:
mycsv = CSVWriter('/tmp/test.csv')
mycsv.write((12,'green','apples'))
mycsv.write((7,'yellow','bananas'))
mycsv.close()
print("Written %d bytes to %s" % (mycsv.size(), mycsv.fname()))
Have fun
What about this:
with open("your_csv_file.csv", "w") as f:
f.write("\n".join(text))
str.join() Return a string which is the concatenation of the strings in iterable.
The separator between elements is
the string providing this method.
In my situation...
with open('UPRN.csv', 'w', newline='') as out_file:
writer = csv.writer(out_file)
writer.writerow(('Name', 'UPRN','ADMIN_AREA','TOWN','STREET','NAME_NUMBER'))
writer.writerows(lines)
you need to include the newline option in the open attribute and it will work
https://www.programiz.com/python-programming/writing-csv-files

Multiprocessing in enumerate loop

I have a script that downloads images from urls, but I would like to parallelise it otherwise it will take hours. With this code:
import requests
from math import floor, log10
import urllib
import time
import multiprocessing
with open('images.csv', 'r') as f:
images = f.readlines()
num_position = floor(log10(len(images)) + 1)
a = time.time()
for i, image in enumerate(images[1:10]):
if (i+1) % 1000 == 0:
print('Downloading {} image'.format(i+1) )
# a = time.time()
with open(str(i).zfill(num_position)+'a.jpg', 'wb') as file:
try:
writing = file.write(requests.get(image.split(',')[2]).content)
p = multiprocessing.Process(target=writing, args=(image,))
p.start()
p.join()
except:
print('Skipping an image!')
pass
b = time.time()
print('multiple process -- {}'.format(b-a))
I get an error :
Process Process-9:
Traceback (most recent call last):
File "/usr/lib/python3.4/multiprocessing/process.py", line 254, in _bootstrap
self.run()
File "/usr/lib/python3.4/multiprocessing/process.py", line 93, in run
self._target(*self._args, **self._kwargs)
TypeError: 'int' object is not callable
Why am I getting an error but the task is still completed and the code doesn't break? (and by that I mean the piece in try: )
What would be the easiest way to include some kind of paralleling here?
You get the error because AFAIK this line
writing = file.write(requests.get(image.split(',')[2]).content)
has the output of integer type. write returns the number of written characters which is equal to the length of the string-representation of your image. Now you assign that to the variable writing -> writing becomes a number.
p = multiprocessing.Process(target=writing, args=(image,))
calls writing as target function, which raises the error since your are not calling a function but integer-type writing (not callable). The code works since your workers do not have anything to do and close immediatly and the file is already written.
To get things working, your would have to define a function that takes your image as argument and maybe the file name. This function you later call in the setup of your workers. Something like that:
def write_file(image, filename):
filestream = open(filename, mode="w")
filestream.write(requests.get(image.split(',')[2]).content)
filestream.close()
And in your application
p = multiprocessing.Process(target=write_file, args=(image, filename,))
However, that is just the writing part. If you want to do the downloads in separate task too then you have to put the code for that into your separate function.
def download_write(urls):
for url in iter(urls.get, 'STOP'):
#download code here#
filestream = open(filename, mode="w")
filestream.write(requests.get(image.split(',')[2]).content)
filestream.close()
And your main application:
list_urls = [] # your list of urls to download
urls = Queue()
for element in list_urls:
urls.put(element)
p = multiprocessing.Process(target=download_write, args=(urls,))
urls.put("STOP") #signals end of tasks for your workers
p.start() #start worker
p.join() #wait for worker to finish

Resources