how to put a valid filepath as a function parameter in python - python

I am trying to write a save/load function for a text based game in python 3.5.1, and I found some helpful code on this site, unfortunately, both functions just need a file path as one of the parameters. I am learning python as I go and am relatively new to both this site and coding in general, so help on how to enter in a valid file path (and examples of what a valid file path is in this case!) would be greatly appreciated (once again, I'm like Jon Snow). The relevant methods are posted below:
def __init__(self, name):
self.name = name
self.maxHealth = 100
self.health = self.maxHealth
self.baseAttack = 10
self.credits = 10
self.augs = 0
self.weap = ["Basic Nanite Pack"]
self.currWeap = ["Basic Nanite Pack"]
global playerFile
playerFile = {"name":self.name, "health":self.maxHealth, "maxHealth":self.health, "baseAttack":self.baseAttack,
"weapon":self.weap, "currWeap":self.currWeap, "credits":self.credits, "augs":self.augs}
def saveGame(playerFile, filepath):
with open(filepath, 'w') as outfile:
for name,num in playerFile.items():
outfile.write("{};{};\n".format(num, name))
import csv
def loadGame(filepath):
with open(filepath) as infile:
# purposeful misspell for variable name
playerFil = dict((v,k) for v,k,_ in csv.reader(infile, delimiter=';'))
return playerFil

A file path is a path to a file from start to end.
e.g c:\users\John\my_document.txt
This is a valid file path and you should normally pass it like this:
r'c:\users\John\my_document.txt'
Note that if you dont give a path for an actual file
e.g c:\users\John
Python won't be able to open any file since that would be a directory path.

Related

How can I avoid repeating a for loop in two different functions

I am writing an ImageCollection class in python that should hold a dictionary with a name and the image-object (pygame.image object).
In one case I want to load all images inside a folder to the dictionary and in another case just specific files, for example only button-files.
What I have written so far is this:
class ImageCollection:
def __init__(self):
self.dict = {}
def load_images(self, path):
directory = os.fsencode(path)
for file in os.listdir(directory):
file_name = os.fsdecode(file)
img_path = path + "/" + file_name
if file_name.endswith(".jpg") or file_name.endswith(".png"):
# Remove extension for dictionary entry name and add image to dictionary
#-----------------------------------------------------------------------
dict_entry_name = file_name.removesuffix(".jpg").removesuffix(".png")
self.dict.update({dict_entry_name: image.Image(img_path, 0)})
def load_specific_images(self, path, contains_str):
directory = os.fsencode(path)
for file in os.listdir(directory):
file_name = os.fsdecode(file)
img_path = path + "/" + file_name
if file_name.endswith(".jpg") or file_name.endswith(".png"):
if file_name.rfind(contains_str):
# Remove extension for dictionary entry name and add image to dictionary
#-----------------------------------------------------------------------
dict_entry_name = file_name.removesuffix(".jpg").removesuffix(".png")
self.dict.update({dict_entry_name: image.Image(img_path, 0)})
The only problem is that this is probably bad programming pattern, right? In this case it probably doesnt matter but I would like to know what the best-practice in this case would be.
How can I avoid repeating myself in two different functions when the only difference is just a single if condition?
I have tried creating a "dict_add" function that creates the entry.
Then I was thinking I could create two different functions, one which directly calls "dict_add" and the other one checks for the specific condition and then calls "dict_add".
Then I thought I could add create just a single function with the for-loop but pass a function as an argument (which would be a callback I assume?). But one callback would need an additional argument so thats where I got stuck and wondered if my approach was correct.
You could make the contains_str an optional argument.
In cases where you want to load_images - you just provide the path
In cases where you want to load specific images - you provide the path and the contains_str argument
In both cases you call load_images(...)
Code:
class ImageCollection:
def __init__(self):
self.dict = {}
def load_images(self, path, contains_str=""):
directory = os.fsencode(path)
for file in os.listdir(directory):
file_name = os.fsdecode(file)
img_path = path + "/" + file_name
if file_name.endswith(".jpg") or file_name.endswith(".png"):
if contains_str == "" or (contains_str != "" and file_name.rfind(contains_str)):
# Remove extension for dictionary entry name and add image to dictionary
#-----------------------------------------------------------------------
dict_entry_name = file_name.removesuffix(".jpg").removesuffix(".png")
self.dict.update({dict_entry_name: image.Image(img_path, 0)})

Export JSON data from python objects

I'm trying to make a phone book in python and I want to save all contacts in a file, encoded as JSON, but when I try to read the exported JSON data from the file, I get an error:
Extra data: line 1 column 103 - line 1 column 210 (char 102 - 209)
(It works fine when I have only one object in "list.txt")
This is my code:
class contacts:
def __init__(self, name="-", phonenumber="-", address="-"):
self.name= name
self.phonenumber= phonenumber
self.address= address
self.jsonData=json.dumps(vars(self),sort_keys=False, indent=4)
self.writeJSON(self.jsonData)
def writeJSON(self, jsonData):
with open("list.txt", 'a') as f:
json.dump(jsonData, f)
ted=contacts("Ted","+000000000","Somewhere")
with open('list.txt') as p:
p = json.load(p)
print p
The output in list.txt:
"{\n \"phonenumber\": \"+000000000\", \n \"name\": \"Ted\", \n \"address\": \"Somewhere\"\n}"
Now, if I add another object, it can't read the JSON data anymore. If my way of doing it is wrong, how else should I export the JSON code of every object in a class, so it can be read back when I need to?
The reason this isn't working is that this code path gives you an invalid JSON structure. With one contact you get this:
{"name":"", "number":""}
While with 2 contacts you would end up with this:
{"name":"", "number":""}{"name":"", "number":""}
The second one is invalid json because 2 objects should be encoded in an array, like this:
[{"name":"", "number":""},{"name":"", "number":""}]
The problem with your code design is that you're writing to the file every time you create a contact. A better idea is to create all contacts and then write them all to the file at once. This is cleaner, and will run more quickly since file I/O is one of the slowest things a computer can do.
My suggestion is to create a new class called Contact_Controller and handle your file IO there. Something like this:
import json
class Contact_Controller:
def __init__(self):
self.contacts = []
def __repr__(self):
return json.dumps(self)
def add_contact(self, name="-", phonenumber="-", address="-"):
new_contact = Contact(name,phonenumber,address)
self.contacts.append(new_contact)
return new_contact
def save_to_file(self):
with open("list.txt", 'w') as f:
f.write(str(self.contacts))
class Contact:
def __init__(self, name="-", phonenumber="-", address="-"):
self.name= name
self.phonenumber= phonenumber
self.address= address
def __repr__(self):
return json.dumps({"name": self.name, "phonenumber": self.phonenumber, "address": self.address})
contact_controller = Contact_Controller()
ted = contact_controller.add_contact("Ted","+000000000","Somewhere")
joe = contact_controller.add_contact("Joe","+555555555","Somewhere Else")
contact_controller.save_to_file()
with open('list.txt') as p:
p = json.load(p)
print(p)
I've also changed it to use the built in __repr__() class method. Python will call that method whenever it needs a string representation of the object.
in writeJSON, you opened the file for append (mode='a'), which works fine the first time, but not the subsequent calls. To fix this problem, open the file with overwrite mode ('w'):
with open("list.txt", 'w') as f:

python create a file in a directory errors

write a python program to create a .html file in a directory, the directory can be created correctly, use function open to create this .html file and try to write some content in this file,but the .html file can not be created,
def save_public_figure_page(self,type,p_f_name):
glovar.date = time.strftime("%Y%m%d", time.localtime())
p_f_page_file_directory = os.path.join("dataset", "html",type,glovar.date,p_f_name)
data_storage.directory_create(p_f_page_file_directory)
html_user_page = glovar.webdriver_browser.page_source
p_f_page_file = os.path.join(p_f_page_file_directory,type + "_" + p_f_name + ".html")
html_file = open(p_f_page_file, "w", encoding='utf-8')
html_file.write(html_user_page)
html_file.close()
the directory_create function in data_storage is:
#create the file storage directory
def directory_create(path):
directory = os.path.join(os.path.dirname(__file__),path)
if not os.path.exists(directory):
os.makedirs(directory)
it errors:
<class 'FileNotFoundError'> at /public_figure_name_sub
[Errno 2] No such file or directory: 'dataset\\html\\public_figure\\20170404\\Donald Trump \\public_figure_Donald Trump .html'
the current directory is under /dataset/, I found the directory:
F:\MyDocument\F\My Document\Training\Python\PyCharmProject\FaceBookCrawl\dataset\html\public_figure\20170404\Donald Trump
has been created correctly,but the file——public_figure_Donald Trump .html can not be created correctly,could you please tell me the reason and how to correct
As suggested by Jean-François Fabre, your file has a space just before the ".html".
To solve this, use trim() in the variable p_f_name in your 7th line:
# Added trim() to p_f_name
p_f_page_file = os.path.join(p_f_page_file_directory,type +
"_" + p_f_name.trim() + ".html")
This will create the file:
public_figure_Donald Trump.html
instead of
public_figure_Donald Trump .html
PD: Anyway your filename has a lot of spaces between Donald and Trump. I don't know where the file name comes but you might want to fix it.
Function save_public_figure_page
class public_figure:
def save_public_figure_page(self, type, p_f_name):
glovar.date = time.strftime("%Y%m%d", time.localtime())
p_f_name = p_f_name.trim() # Trim the name to get rid of extra spaces
p_f_page_name = '{t}_{pfn}.html'.format(t=type, pfn=p_f_name)
p_f_page_file_directory = os.path.join(
directory, # Add the directory from the data_storage.directory property
"dataset", "html",
type, glovar.date, p_f_name,
)
if data_storage.directory_create(self.p_f_page_file_directory):
html_user_page = glovar.webdriver_browser.page_source
p_f_page_file = os.path.join(p_f_page_file_directory, p_f_page_name)
html_file = open(p_f_page_file, "w", encoding='utf-8')
html_file.write(html_user_page)
html_file.close()
directory_create method of data_storage
#create the file storage directory
class data_storage:
def directory_create(self, path):
self.directory = os.path.join(os.path.dirname(__file__), path)
if not os.path.exists(self.directory):
try:
os.makedirs(self.directory)
except:
raise
else:
return True
else:
return True

How should I replace parts from a text file through Python?

Okay, so here's the deal, folks:
I've been experimenting with Python(3.3), trying to create a python program capable of generating random names for weapons in a game and replacing their old names, which are located inside a text file. Here's my function:
def ModifyFile(shareddottxt):
global name
a = open(str(shareddottxt) , 'r')
b = a.read()
namefix1 = '''SWEP.PrintName = "'''
namefix2 = '''" //sgaardname'''
name1 = b.find(namefix1) + len(namefix1)
name2 = b.find(namefix2, name1)
name = name + b[name1:name2] ## We got our weapon's name! Let's add the suffix.
c = open((shareddottxt + ".lua"), 'r+')
for line in b:
c.write(line.replace(name, (name + namesuffix)))
c.close()
a.close
As you can see, I first open my text file to find the weapon's name. After that, I try to create a new file and copy the contents from the old one, while replacing the weapon's name for (name + namesuffix). However, after calling the function, I get nothing. No file whatsoever. And even if I DO add the file to the folder manually, it does not change. At all.
Namesuffix is generated through another function early on. It is saved as a global var.
Also, my text file is huge, but the bit I'm trying to edit is:
SWEP.PrintName = "KI Stinger 9mm" //sgaardname
The expected result:
SWEP.PrintName = "KI Stinger 9mm NAMESUFFIX" //sgaardname
Where did I mess up, guys?
Something like this is more pythonic.
def replace_in_file(filename, oldtext, newtext):
with open(filename, 'r+') as file:
lines = file.read()
new_lines = lines.replace(oldtext, newtext)
file.seek(0)
file.write(new_lines)
If you don't want to replace that file
def replace_in_file(filename, oldtext, newtext):
with open(filename, 'r') as file, open(filename + ".temp", 'w') as temp:
lines = file.read()
new_lines = lines.replace(oldtext, newtext)
temp.write(new_lines)

LRU cache on hard drive python

I want to be able to decorate a function as you would do with functools.lru_cache, however, I want the results to be cached on the hard drive and not in memory. Looking around, I get a feeling this is a solved problem, and I was wondering if anyone could point me in the right direction (or at least give me a few more keywords to try googling)
I don't know if this will help or if it matters, but the function is computing images from unique filenames.
Here's some code to get you started:
from pathlib import Path
import pickle
import hashlib
import os
class LRU_Cache:
def __init__(self, directory, original_function, maxsize=10):
self.directory = directory
self.original_function = original_function
self.maxsize = maxsize
try:
os.mkdir(directory)
except OSError:
pass
def __call__(self, *args):
filename = hashlib.sha1(pickle.dumps(args)).hexdigest()
fullname = os.path.join(self.directory, filename)
try:
with open(fullname, 'rb') as f:
value = pickle.load(f)
Path(fullname).touch()
return value
except FileNotFoundError:
pass
value = self.original_function(*args)
with open(fullname, 'wb') as f:
pickle.dump(value, f)
filenames = os.listdir(self.directory)
if len(filenames) <= self.maxsize:
return
fullnames = [os.path.join(self.directory, filename)
for filename in filenames]
oldest = min(fullnames, key=lambda fn: os.stat(fn).st_mtime)
os.remove(oldest)
It uses hashes the arguments to create a unique filename for each function call. The function return value is pickled using that filename.
Cache hits unpickle the stored result and update the file modification time.
If the cache directory exceeds a target size, the oldest cache file is removed.
Use it like this:
def square(x):
print('!')
return x ** 2
sqr = LRU_Cache('square_cache', square, 10)
Now call sqr normally and results will be cached to disk.

Categories