File Path Concatenation - python

I need to build a Windows (only) file path from a combination of a UNC path passed to my script as a parameter, an API call, and a calculated date.
I'm having a horrible time of it, mostly caused by Windows' use of a backslash character to delimit file paths. I've read that the "pathlib" module should be able to sort this mess out, BUT it apparently doesn't support concatenation when building out file paths.
The UNC path is being passed out to the script as a dictionary from another application (PRTG Network Monitor:
{"fileshare": "//server02/logs/"}
I read that in and then need to append a hostname derived from an API call:
logPath = Path(params["fileshare"] + "/" + apiHostname + "/")
I then calculate a date which needs to be appended to the logpath, along with a delimiter "-" and a filename suffix:
filePath = Path(logPath, + apiHostname + "-", + past_day + ".log" )
The problem arises during the concatenation:
{"text": "Python Script execution error: unsupported operand type(s) for +: 'WindowsPath' and 'str'", "error": 1}}
Can someone please explain how I can build a path so that the calculated filename, which should look like this:
\\server02\logs\log01.rhmgmt.lan\log01.rhmgmt.lan-2021-07-28.log
Can be opened for processing?

Yes "pathlib" module should be able to sort this mess out
Input:
from datetime import date, timedelta
from pathlib import Path
params = {"fileshare": "//server02/logs/"}
apiHostname = 'log01.rhmgmt.lan'
past_day = str((date.today() - timedelta(days=1)))
Create the initial path and append all parts:
fileshare = Path(params['fileshare'])
filepath = fileshare / apiHostname / f"{apiHostname}-{past_day}.log"
Output:
>>> filepath
PosixPath('//server02/logs/log01.rhmgmt.lan/log01.rhmgmt.lan-2021-07-28.log')

Yes, pathlib can easily sort things out.
You can use the joinpath() method, as I suggested in a comment, to concatenate the components are you're building the Path. It does the equivalent of what os.path.join() does.
The only slightly tricky part is you'll have to initially create an empty Path in order use the method they inherit from PurePath.
from datetime import date, timedelta
from pathlib import Path
params = {"fileshare": "//server02/logs/"}
apiHostname = 'log01.rhmgmt.lan'
past_day = str((date.today() - timedelta(days=1)))
filePath = Path().joinpath(params["fileshare"], apiHostname,
apiHostname + '-' + past_day + '.log')
print(filePath) # -> \\server02\logs\log01.rhmgmt.lan\log01.rhmgmt.lan-2021-07-29.log

Related

How to include a variable in 'r' raw string

I've created a new variable for user path, but not sure how to add in to the following.
import os, pwd
path=os.getcwd()
#crif0 = r '/abc/crif/gpio_mem_0_crif.xml' - original
crif0 = r (path+ '/crif/gpio_mem_0_crif.xml') - I tried with this but doesn't work
As mentioned in the comments, r is a literal prefix which you cannot apply to anything but string literals, so path + r'/crif/...' is enough. However, in this particular case when you need to compose a file path, I'd use the standard library, which makes the code more portable:
import os
path = os.getcwd()
crif0 = os.path.join(path, 'crif', 'gpio_mem_0_crif.xml')
or, in a more modern way using path objects rather than strings:
from pathlib import Path
crif0 = Path.cwd() / 'crif' / 'gpio_mem0_crif.xml'

Unsupported operand type(s) for +: 'WindowsPath' and 'str'

The code I'm working on throws the error Unsupported operand type(s) for +: 'WindowsPath' and 'str'. I have tried many things, and none have fixed this (aside from removing the line with the error, but that's not helpful).
For context, this script (when it's done) is supposed to:
Find a file (mp3) based on the ID you type in (in the directory specified in SongsPath.txt)
Back it up
Then replace it with another file (renamed to the previous file's name)
so that the program that fetches these files plays the new song instead of the old one, but can be restored to the original song at any time. (the songs are downloaded from newgrounds and saved by their newgrounds audio portal ID)
I'm using Python 3.6.5
import os
import pathlib
from pathlib import Path
nspt = open ("NewSongsPath.txt", "rt")
nsp = Path (nspt.read())
spt = open("SongsPath.txt", "rt")
sp = (Path(spt.read()))
print("type the song ID:")
ID = input()
csp = str(path sp + "/" + ID + ".mp3") # this is the line throwing the error.
sr = open(csp , "rb")
sw = open(csp, "wb")
print (sr.read())
What is happening is that you are using the "+" character to concatenate 2 different types of data
Instead of using the error line:
csp = str(path sp + "/" + ID + ".mp3")
Try to use it this way:
csp = str(Path(sp))
fullpath = csp + "/" + ID + ".mp3"
Use the 'fullpath' variable to open file.
pathlib.Path joins paths using the division operator. No need to convert to a string and then concatenate, just use the Path object's __div__ operator
csp = sp/(ID + ".mp3")
You could also use augmented division to update sp itself, if you prefer.
sp /= ID + ".mp3"
In both cases, you still have a Path object which you can keep using through the rest of the script. There is no reason for your script to convert it to a string. You can either use the Path object in the open call, or better, use the open method on the Path object.
csp = sp / (ID + ".mp3")
sr = csp.open("rb")
sw = csp.open("wb")

How to check parameters for os.makedirs?

I use this code for create folder for users:
work_path = '/tmp/'
os.umask(0000)
for i in user:
if not os.path.exists(work_path + i):
try:
os.makedirs(work_path + i, 0777)
When I set work_path = '/tmp/' - my code work perfect.
But when I type for mistake work_path = '/tmp' I got not what expected )))
Question: how can I check my path have backslash, or maybe how can I create folders for another way ?
Use os.path.join:
Join one or more path components intelligently. The return value is the concatenation of path and any members of *paths with exactly one directory separator (os.sep) following each non-empty part except the last, meaning that the result will only end in a separator if the last part is empty. If a component is an absolute path, all previous components are thrown away and joining continues from the absolute path component.
os.makedirs(os.path.join(work_path,i))
So in your code join the path once then use the joined path:
for i in user:
pth = os.path.join(work_path, i)
if not os.path.exists(pth):
try:
os.makedirs(pth, 0777)
You can use just the expression
work_path[-1] == '/'
If it is true you have a backslash

How to copy an image with date in the new filename?

I'm looking for a way to copy an image file from a given source with Python.
I did read several stuff on the internet but what I found was always working just on one specific platform. I would like to know if there exists a functionality in Python that would make it possible to easily copy an image file ?
My target would be to have this in the end :
folder/image_title.jpg
copying the image
new_folder/new_image_title.jpg
with the *new_image_title* being the date of the day.
My code looks like this at the moment :
import shutil
import datetime
shutil.copy('folder/alpha.jpg', 'new_folder/'datetime.date()'.jpg')
But I get an error: SyntaxError: invalid syntax
Update:
You probably want a simple string for your second argument:
instead of this:
shutil.copy('folder/alpha.jpg', 'new_folder/'datetime.date()'.jpg')
try:
dest = new_folder + '/' + str(datetime.date(2012, 8, 19)) + '.jpg'
shutil.copy('folder/alpha.jpg', dest)
with:
new_folder = 'bla'
dest becomes:
'bla/2012-08-19.jpg'
tweak as needed to make the name unique (add time stamp?). Also note, it's usually better to use os.path.join() for creating new paths.
You are getting a SyntaxError because your string forming syntax is incorrect. Corrected, the code would look like this:
import shutil
import datetime
import os
DATE_FORMAT = '%Y-%m-%d'
filename = 'folder/alpha.jpg'
target_folder = 'new_folder'
ext = os.path.splitext(filename)[1]
shutil.copy(filename,
os.path.join(target_folder, '%s%s'
% (datetime.datetime.now().strftime(DATE_FORMAT), ext))
install exiftool
and run command in the photo path:
exiftool -d "./%Y-%m-%d" "-directory
I'm done with it, thanks to you :)
So here is my final version, in case it could help other people :
import shutil
import datetime
now = datetime.datetime.now()
date=str(now.year)+'-'+str(now.month)+'-'+str(now.day)
new_folder = "source/new_folder"
dest = new_folder + '/' + str(date) + '.jpg'
shutil.copy('source/alpha.jpg', dest)
One last thing : at the moment, the program just runs without saying anything. So does anyone knows how to print a message saying whether or not the copying did work ?

Build the full path filename in Python

I need to pass a file path name to a module. How do I build the file path from a directory name, base filename, and a file format string?
The directory may or may not exist at the time of call.
For example:
dir_name='/home/me/dev/my_reports'
base_filename='daily_report'
format = 'pdf'
I need to create a string '/home/me/dev/my_reports/daily_report.pdf'
Concatenating the pieces manually doesn't seem to be a good way. I tried os.path.join:
join(dir_name,base_filename,format)
but it gives
/home/me/dev/my_reports/daily_report/pdf
This works fine:
os.path.join(dir_name, base_filename + '.' + filename_suffix)
Keep in mind that os.path.join() exists only because different operating systems use different path separator characters. It smooths over that difference so cross-platform code doesn't have to be cluttered with special cases for each OS. There is no need to do this for file name "extensions" (see footnote) because they are always preceded by a dot character, on every OS.
If using a function anyway makes you feel better (and you like needlessly complicating your code), you can do this:
os.path.join(dir_name, '.'.join((base_filename, filename_suffix)))
If you prefer to keep your code clean, simply include the dot in the suffix:
suffix = '.pdf'
os.path.join(dir_name, base_filename + suffix)
That approach also happens to be compatible with the suffix conventions in pathlib, which was introduced in python 3.4 a few years after this question was asked. New code that doesn't require backward compatibility can do this:
suffix = '.pdf'
pathlib.PurePath(dir_name, base_filename + suffix)
You might be tempted to use the shorter Path() instead of PurePath() if you're only handling paths for the local OS. I would question that choice, given the cross-platform issues behind the original question.
Warning: Do not use pathlib's with_suffix() for this purpose. That method will corrupt base_filename if it ever contains a dot.
Footnote: Outside of Microsoft operating systems, there is no such thing as a file name "extension". Its presence on Windows comes from MS-DOS and FAT, which borrowed it from CP/M, which has been dead for decades. That dot-plus-three-letters that many of us are accustomed to seeing is just part of the file name on every other modern OS, where it has no built-in meaning.
If you are fortunate enough to be running Python 3.4+, you can use pathlib:
>>> from pathlib import Path
>>> dirname = '/home/reports'
>>> filename = 'daily'
>>> suffix = '.pdf'
>>> Path(dirname, filename).with_suffix(suffix)
PosixPath('/home/reports/daily.pdf')
Um, why not just:
>>> import os
>>> os.path.join(dir_name, base_filename + "." + format)
'/home/me/dev/my_reports/daily_report.pdf'
Is not it better to add the format in the base filename?
dir_name='/home/me/dev/my_reports/'
base_filename='daily_report.pdf'
os.path.join(dir_name, base_filename)
Just use os.path.join to join your path with the filename and extension. Use sys.argv to access arguments passed to the script when executing it:
#!/usr/bin/env python3
# coding: utf-8
# import netCDF4 as nc
import numpy as np
import numpy.ma as ma
import csv as csv
import os.path
import sys
basedir = '/data/reu_data/soil_moisture/'
suffix = 'nc'
def read_fid(filename):
fid = nc.MFDataset(filename,'r')
fid.close()
return fid
def read_var(file, varname):
fid = nc.Dataset(file, 'r')
out = fid.variables[varname][:]
fid.close()
return out
if __name__ == '__main__':
if len(sys.argv) < 2:
print('Please specify a year')
else:
filename = os.path.join(basedir, '.'.join((sys.argv[1], suffix)))
time = read_var(ncf, 'time')
lat = read_var(ncf, 'lat')
lon = read_var(ncf, 'lon')
soil = read_var(ncf, 'soilw')
Simply run the script like:
# on windows-based systems
python script.py year
# on unix-based systems
./script.py year
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
TEMPLATE_PATH = Path.joinpath(BASE_DIR,"templates")
print(TEMPLATE_PATH)
Adding code below for better understanding:
import os
def createfile(name, location, extension):
print(name, extension, location)
#starting creating a file with some dummy contents
path = os.path.join(location, name + '.' + extension)
f = open(path, "a")
f.write("Your contents!! or whatever you want to put inside this file.")
f.close()
print("File creation is successful!!")
def readfile(name, location, extension):
#open and read the file after the appending:
path = os.path.join(location, name + '.' + extension)
f = open(path, "r")
print(f.read())
#pass the parameters here
createfile('test','./','txt')
readfile('test','./','txt')

Categories

Resources