Prompt toolkit write multiline input to file and close the prompt - python

I would like to make some form of terminal editor for text-based files.
When started, it prints the current content of the file and makes it possible for user to edit in (multiline input). On press of CTRL + E, it should write that multiline input into specific file and close the prompt.
I have tried using this code, but it doesn't seem to work.
from prompt_toolkit import prompt, PromptSession
from prompt_toolkit.lexers import PygmentsLexer
from pygments.lexers.python import PythonLexer
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.key_binding import KeyBindings
file_path = 'output.txt'
file = open(file_path, 'r')
content = file.read()
new_content = None
session = PromptSession()
bindings = KeyBindings()
#bindings.add('c-e')
def _(event):
global new_content
global file_path
file = open(file_path, 'w')
file.write(new_content)
session.app.exit()
def show_prompt():
global new_content
global session
bottom_toolbar = HTML('<b><style background-color="white" color="green">Input</style></b>')
lexer = PygmentsLexer(PythonLexer)
new_content = session.prompt('\n',
default=content,
lexer=lexer,
multiline=True,
bottom_toolbar=bottom_toolbar,
key_bindings=bindings)
# Start of the program
if __name__ == '__main__':
show_prompt()

Related

Using Python Click to read a JSON file

I am new to python and I am trying to read in a JSON file, that for now I can just write out to a new file without any changes. I have been attempting to use the python package Click to do this but keep running into errors.
I'm sure this is relatively basic but any help would be appreciated. The latest version of the code I've tried is below.
import json
import os
import click
def dazprops():
"""Read Daz3D property File"""
path = click.prompt('Please specify a location for the Daz3D Properties File')
path = os.path.realpath(path)
#dir_name = os.path.dirname(path)
print(path)
dazpropsf = open('path')
print(dazpropsf)
if __name__ == '__main__':
dazprops()
Something like this could give you an idea how to achieve that using click:
import click
def read_file(fin):
content = None
with open(fin, "r") as f_in:
content = f_in.read()
return content
def write_file(fout, content):
try:
print("Writing file...")
with open(fout, "w") as f_out:
f_out.write(content)
print(f"File created: {fout}")
except IOError as e:
print(f"Couldn't write a file at {fout}. Error: {e}")
#click.command()
#click.argument('fin', type=click.Path(exists=True))
#click.argument('fout', type=click.Path())
def init(fin, fout):
"""
FINT is an input filepath
FOUT is an output filepath
"""
content = read_file(fin)
if content:
write_file(fout, content)
if __name__ == "__main__":
init()

I am making a txt file where if you input a word it opens a program and it opens the program if there is no word

it wont stop opening the program even if there is nothing in the txt file or nothing opens
import os
with open(r'file.txt'):
if "start" in 'file.txt':
os.startfile(r'C:\Program Files (x86)\Minecraft Launcher\MinecraftLauncher.exe')
Try something like this.
Currently your if statment is asking if "start" is in the string "file.txt" not in the file.
import os
GAME_LOCATION = r"C:\Program Files (x86)\Minecraft Launcher\MinecraftLauncher.exe"
with open("file.txt", 'r') as f:
line = f.readline()
print(line)
if "start" in line:
os.startfile(GAME_LOCATION)
else:
print("start is not in the file")
based on #loganRowe , you should put your code to this
import os
GAME_LOCATION = r'C:\"Program Files (x86)"\"Minecraft Launcher"\MinecraftLauncher.exe'
with open("file.txt", "r") as f:
line = f.readline()
if "start" in line:
os.system(GAME_LOCATION)
else:
print("start is not in the file")
IMPORTANT NOTE :
Make sure your file.txt is on the same directory as your .py file
Make sure the directory of the launcher is valid
"Program Files(x86)" is needed because if you don't have it, the console will read as Program Files(x86) which had an error of a space between the 2 word

Pycharm and sys.argv[1]

I'm trying to run in Pycharm this programm :
# Chap02-03/twitter_hashtag_frequency.py
import sys
from collections import Counter
import json
def get_hashtags(tweet):
entities = tweet.get('entities', {})
hashtags = entities.get('hashtags', [])
return [tag['text'].lower() for tag in hashtags]
if __name__ == '__main__':
fname = sys.argv[1]
with open(fname, 'r') as f:
hashtags = Counter()
for line in f:
tweet = json.loads(line)
hashtags_in_tweet = get_hashtags(tweet)
hashtags.update(hashtags_in_tweet)
for tag, count in hashtags.most_common(20):
print("{}: {}".format(tag, count))
I want to run the programm twitter_hashtag_frequency.py in Pycharm using a json file stream_.jsonl as a parameter, this file is in the same directory as the programm. Can you show me how can I edit this code ? I tried several time, I did'nt succeed, I got this error :
fname = sys.argv[1]
IndexError: list index out of range
Thank you for your help.
If you run the file by pressing the green play button (next to Edit Configurations), you'll need to specify the argument in the configurations menu in Parameters. Enter stream_.jsonl in the text box.
Also double check that the working directory is set to the one containing both these files

Why Python is adding unnecessary characters at the beginning of a file while overwriting it?

In a Django project I have created a .env file to store my application's secret credentials. And I am using console command to generating some of the credentials. Here is my initial .env file,
SECRET_KEY=CHANGE_IT
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=database_name
DB_USERNAME=database_username
DB_PASSWORD=database_password
DB_SCHEMA=database_schema_name
And here is my generate_secret console command to overwrite the SECRET_KEY with random string,
import re
import os
from django.core.management import BaseCommand
from django.core.management.utils import get_random_secret_key
class Command(BaseCommand):
help = ''
def handle(self, *args, **options):
env_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../.env'))
self.set_secret_key(env_path, get_random_secret_key())
#staticmethod
def set_secret_key(env_file_path, secret_key):
fp = open(env_file_path, 'r+')
current_env = fp.read()
regex = r"(SECRET_KEY=.*?)\n"
matches = re.findall(regex, current_env, re.MULTILINE)
updated_env = current_env.replace(matches[0], 'SECRET_KEY={}'.format(secret_key))
fp.truncate(0)
fp.write(updated_env)
fp.close()
The problem is when I am running the command, it overwrites the SECRET_KEY correctly but also adding bunch of wired characters at the start of the .env file. I running on Ubuntu 18.04 operating system. Here is the .env file after running the command,
I am not sure why but I can not copy those wired characters, so I have attached the screenshot of it.
Not sure why, but fp.truncate(0) seems to be the culprit (see Behaviour of truncate() method in Python for more info).
Personally I would do it in two steps: first read the file, then rewrite it.
#staticmethod
def set_secret_key(env_file_path, secret_key):
with open(env_file_path, 'r') as fp:
current_env = fp.read()
regex = r"(SECRET_KEY=.*?)\n"
matches = re.findall(regex, current_env, re.MULTILINE)
updated_env = current_env.replace(matches[0], 'SECRET_KEY={}'.format(secret_key))
with open(env_file_path, 'w')as fp:
fp.write(updated_env)
If you want to do it in one step, use fp.seek(0) before fp.truncate() as Open file for reading and writing with truncate suggests.
#staticmethod
def set_secret_key(env_file_path, secret_key):
fp = open(env_file_path, 'r+')
current_env = fp.read()
regex = r"(SECRET_KEY=.*?)\n"
matches = re.findall(regex, current_env, re.MULTILINE)
updated_env = current_env.replace(matches[0], 'SECRET_KEY={}'.format(secret_key))
fp.seek(0)
fp.truncate()
fp.write(updated_env)
fp.close()

Get a file name with tkinter.filedialog.asksaveasfilename to append in it

from an GUI application designed with tkinter, I wish to save some datas in a file in appending mode. To get the file's name I use asksaveasfilename from filedialog module. Here is the code:
from tkinter.filedialog import asksaveasfilename
def save_file():
file_name = asksaveasfilename()
if file_name:
f = open(file_name, 'a')
contents = tab_chrono.text_area.get(1.0, 'end')
f.write(contents)
f.close()
The problem happens when I select in the dialog an existing file, I got a warning that the file will be overwritten. It is not true since I append in the file.
Is there a way to get rid of this warning ? Or do I have to rewrite a askappendfilename myself ? This is missing in filedialog module.
The asksaveasfilename dialog accepts a confirmoverwrite argument to enable or disable the file existence check.
file_name = asksaveasfilename(confirmoverwrite=False)
This can be found in the Tk manual for tk_getSaveFile but doesn't appear to be documented for tkinter. It was introduced in Tk 8.5.11 so is relatively new in Tk terms (released Nov 2011).
Use the option confirmoverwrite to prevent the message, when selecting an existing file.
import tkFileDialog
import time
class Example():
dlg = tkFileDialog.asksaveasfilename(confirmoverwrite=False)
fname = dlg
if fname != '':
try:
f = open(fname, "rw+")
text = f.read()
print text
except:
f = open(fname, "w")
new_text = time.time()
f.write(str(new_text)+'\n')
f.close()
Edit: Note that I am using f.read() to be able to print the existing text.
You may want to remove the f.read() and subsequent print statement and replace them with a f.seek(0,2) which positions the pointer at the end of the existing file.
The other option is as follows using the append option in the file open, which will create the file if it doesn't already exist:
import tkFileDialog
import time
class Example():
dlg = tkFileDialog.asksaveasfilename(confirmoverwrite=False)
fname = dlg
if fname != '':
f = open(fname, "a")
new_text = time.time()
f.write(str(new_text)+'\n')
f.close()

Categories