Why does my open function need a single letter text string? - python-3.x

I'm going through lpthw and am messing with the open() function. The code I copied includes "target = open(filename, 'd'). I'm wondering why I have to include the 'd'?
I copied this code directly from the book. When I remove the 'd', the code fails, but I can't find any explanation of why it's necessary. I changed the 'd' to another letter and the code works fine.
from sys import argv
script, filename = argv
print(f"We're going to erase {filename}.")
print("If you don't want that, hit CTRL-C (^C).")
print("If you do want that, hit RETURN.")
input("?")
print("Opening the file...")
target = open(filename, 'd')
print("Truncating the file. Goodbye!")
target.truncate()

The second argument ('d') is a mode which tells the interpreter and developer which way the file will be used.
Mode :
Including a mode argument is optional because a default value of ‘r’ will be assumed if it is omitted. The ‘r’ value stands for read mode, which is just one of many.

Related

How to make it so my code remembers what is has written in a text file?

Hello python newbie here.
I have code that prints names into a text file. It takes the names from a website. And on that website, there may be multiple same names. It filters them perfectly without an issue into one name by looking if the name has already written in the text file. But when I run the code again it ignores the names that are already in the text file. It just filters the names it has written on the same session. So my question is how do I make it remember what it has written.
image of the text file
kaupan_nimi = driver.find_element_by_xpath("//span[#class='store_name']").text
with open("mainostetut_yritykset.txt", "r+") as tiedosto:
if kaupan_nimi in tiedosto:
print("\033[33mNimi oli jo tiedostossa\033[0m")
else:
print("\033[32mUusi asiakas vahvistettu!\033[0m")
#Kirjoittaa tekstitiedostoon yrityksen nimen
tiedosto.seek(0)
data = tiedosto.read(100)
if len(data) > 0:
tiedosto.write("\n")
tiedosto.write(kaupan_nimi)
There is the code that I think is the problem. Please correct me if I am wrong.
There are two main issues with your current code.
The first is that you are likely only going to be able to detect duplicated names if they are back to back. That is, if the prior name that you're seeing again was the very last thing written into the file. That's because all the lines in the file except the last one will have newlines at the end of them, but your names do not have newlines. You're currently looking for an exact match for a name as a line, so you'll only ever have a chance to see that with the last line, since it doesn't have a newline yet. If the list of names you are processing is sorted, the duplicates will naturally be clumped together, but if you add in some other list of names later, it probably won't pick up exactly where the last list left off.
The second issue in your code is that it will tend to clobber anything that gets written more than 100 characters into the file, starting every new line at that point, once it starts filling up a bit.
Lets look at the different parts of your code:
if kaupan_nimi in tiedosto:
This is your duplicate check, it treats the file as an iterator and reads each line, checking if kaupan_nimi is an exact match to any of them. This will always fail for most of the lines in the file because they'll end with "\n" while kaupan_nimi does not.
I would suggest instead reading the file only once per batch of names, and keeping a set of names in your program's memory that you can check your names-to-be-added against. This will be more efficient, and won't require repeated reading from the disk, or run into newline issues.
tiedosto.seek(0)
data = tiedosto.read(100)
if len(data) > 0:
tiedosto.write("\n")
This code appears to be checking if the file is empty or not. However, it always leaves the file position just past character 100 (or at the end of the file if there were fewer than 100 characters in it so far). You can probably fit several names in that first 100 characters, but after that, you'll always end up with the names starting at index 100 and going on from there. This means you'll get names written on top of each other.
If you take my earlier advice and keep a set of known names, you could check that set to see if it is empty or not. This doesn't require doing anything to the file, so the position you're operating on it can remain at the end all of the time. Another option is to always end every line in the file with a newline so that you don't need to worry about whether to prepend a newline only if the file isn't empty, since you know that at the end of the file you'll always be writing a fresh line. Just follow each name with a newline and you'll always be doing the right thing.
Here's how I'd put things together:
# if possible, do this only once, at the start of the website reading procedure:
with open("mainostetut_yritykset.txt", "r+") as tiedosto:
known_names = set(name.strip() for name in tiedosto) # names already in the file
# do the next parts in some kind of loop over the names you want to add
for name in something():
if name in known_names: # duplicate found
print("\033[33mNimi oli jo tiedostossa\033[0m")
else: # not a duplicate
print("\033[32mUusi asiakas vahvistettu!\033[0m")
tiedosto.write(kaupan_nimi) # write out the name
tiedosto.write("\n") # and always add a newline afterwards
# alternatively, if you can't have a trailing newline at the end, use:
# if known_names:
# tiedosto.write("\n")
# tiedosto.write(kaupan_nimi)
known_names.add(kaupan_nimi) # update the set of names

Why does my code run successfully but give not output?

I am new to python. I am trying to open a text file with name 'P' and show the lines as an output. I wrote the code below, and it runs but not output. Why is this so?
with open('/Users/LENOVO/Desktop/P.txt','rt') as a_file:
for lines in a_file.readlines():
print(lines,ends='')`
because your print contains end=""
usually the \n is used to flush the output.
if you want to force it to flush the buffer (so to print it without the \n) you can add the flush option :
print(lines,end='', flush=True)
But maybe you just want to remove the end keyword:
print(lines)
When to use end=''?
When you use the end parameter you replace the usual \n (carret return) by something else, that is useful if you want to display a série of things next to each other without going next line everytime. (for instance if you want to print a dot . or x for each call to a function that you're calling in a loop for a big number of times.
And yes it should be end and not ends
See reference here :
https://www.w3schools.com/python/ref_func_print.asp
I do not know where you got ends='' from, but if you remove it, it produces an output.
I also figured I would also add that you are most likely referring to end, this will essentially just replace the \n which is the default value with whatever you wish.

how to fix if-else problem in calling functions in python?

if file is not None:
content = file.readlines()
if 'I' and 'J' in content:
display_oval()
else:
display_polygon()
in this case,suppose i opened a file containing I&J . i expect to call display_oval() but it calls display_polygon(). when i opened file not containing I&J,display_polygon() calls as expected.
when i replaced 'I' and 'J'with 'I' or 'J',when i opened a file containing I&J,display_oval() works fine. But when i opened file not containing I&J, nothing works.
I want to call display_oval()if file contains I&J and display_polygon()otherwise. how it can be done?
You have a couple of intersecting issues with your code.
Thie first issue is that 'I' and 'J' in content gets grouped as ('I') and ('J' in content), which is surely not what you intend. A string like 'I' is always truthy, so testing in that way is not useful. You probably mean 'I' in content and 'J' in content`.
But that's not enough to fix your code (it makes fewer inputs match, not more). The condition will still not work right because your content is a list of strings, all but the last of which will be newline terminated. When done on a list, the in operator expects exact matches, not substring matches as in does when both arguments are strings.
I'm not exactly sure what fix would be best for that second issue. It depends on the logic of your program, and the contents of your file. If you want to test if I and J show up as individual lines in the file (each separately, on a line with no other characters), you might want to test for 'I\n' in content and 'J\n' in content using the same content you're using now. On the other hand, if you want to check for a capital I and J characters anywhere in the text of the file, without regard to lines, then you probably need to change content instead of changing the matching logic. Use content = file.read() to read the whole file into a single string, rather than a list of strings. Then 'I' in content will do a substring search.

Input on multiple lines

I try to write a short program which takes multiple pdf files and merges them into one file. The whole thing should operate over a command line.
I use the argparse-package from python. The program works when I call it and give exactly two files to merge. But I want it to be more flexible. Concrete, what I want to do is calling the program, give the first file and hit enter. Then it should ask for the second file: I give it and hit enter, and so on until I hit enter without inserting any file. Like this, the program should know that all files are given.
Every time I hit enter, the program executes and I don't have any chance to do anything else. I searched for a workaround but didn't find any.
You can use input:
files = []
file = input("Your file: ").strip()
while file:
files.append(file)
file = input("Your file: ").strip()
print(f"Files to process: {files}")

How to allow argument containing spaces with python3 cmd library?

I'm using cmd library to create simple command line interface with code completion. Problem occurs when command argument contains special characters. Code completion runs only on last part separated by these special characters.
Here is simple code to test it:
class Test(Cmd):
def complete_test(self, text, line, b, e):
print(text)
print(line)
print(b)
print(e)
Type test and argument containing, for example, slash. Only last part after / is included in text, and if you return something, only this last part gets replaced.
I used comments under this answer to fix problems with other special characters. But I can't just do readline.set_completer_delims(""), because code completion does not work. I need to at least set space as delimiter (readline.set_completer_delims(" ")), so that it code completion finds where argument starts. But now I can't pass paths containing spaces (see my completion code below):
def complete_export(self, text:str, line:str, begidx, endidx):
return [x for x in glob(text + "*") if x.startswith(text)]
My export command only requires one argument - path, so ideal behavior would be to consider first space as beginning of argument and other spaces would be considered part of path.
Note: I have realized that it's possible to use line argument, and extract path manually, but code completion would still replace only last part, so path would have to be edited. I submitted this as an answer, but it's not very elegant solution.
Here is solution manually separating path from line, performing globbing and returning only parts of path after spaces that are already present. One problem is, that if paths contain spaces, if you press tab twice, you get suggestions only for rest of text after space. Depending on use case, this might be problem.
def complete_export(self, text:str, line:str, begidx, endidx):
path = line[line.find(" ")+1:] # get everything after space
return [" ".join(x.split(" ")[(line.count(" ") - 1):]) for x in glob(path + "*")] # completion suggestions after last space

Resources