Uppercase the names of multiple files in a directory in Python - python

I'm working on a small project that requires that I use Python to uppercase all the names of files in a certain directory "ex: input: Brandy.jpg , output: BRANDY.jpg".
The thing is I've never done on multiple files before, what I've done was the following:
universe = os.listdir('parallel_universe/')
universe = [os.path.splitext(x)[0].upper() for x in universe]
But what I've done capitalized the names in the list only but not the files in the directory itself, the output was like the following:
['ADAM SANDLER','ANGELINA JULIE','ARIANA GRANDE','BEN AFFLECK','BEN STILLER','BILL GATES', 'BRAD PITT','BRITNEY SPEARS','BRUCE LEE','CAMERON DIAZ','DWAYNE JOHNSON','ELON MUSK','ELTON JOHN','JACK BLACK','JACKIE CHAN','JAMIE FOXX','JASON SEGEL', 'JASON STATHAM']
What am I missing here? And since I don't have much experience in Python, I'd love if your answers include explanations for each step, and thanks in advance.

Right now, you are converting the strings to uppercase, but that's it. There is no actual renaming being done. In order to rename, you need to use os.rename
If you were to wrap your code with os.rename, it should solve your problem, like so:
[os.rename("parallel_universe/" + x, "parallel_universe/" + os.path.splitext(x)[0].upper() + os.path.splitext(x)[1]) for x in universe]
I have removed the assignment universe= because this line no longer returns a list and you will instead get a bunch on None objects.
Docs for os.rename: https://docs.python.org/3/library/os.html#os.rename

Related

Easiest way to append non-directory component to Python Path?

Several SO questions ask how to append a directory to a pathlib.Path object. That's not this question.
I would like to use a Path object a prefix for a series of files in a single directory, like this:
2022-01-candidates.csv
2022-01-resumes.zip
2022-02-candidates.csv
2022-02-resumes.zip
Ideally, I would construct Path objects for the 2022-01 and 2022-02 components, and then append -candidates.csv and -resumes.zip to each.
Unfortunately, Path appears to only understand appending subdirectores, not extensions to existing path names.
The only workaround that I see is something like p.parent / (p.name + "-candidates.csv"). Although that's not so bad, it's clumsy and this pattern is common for me. I wonder whether I'm missing a more streamlined method. (For example, why isn't there a + concatenation operator?)
Path.with_suffix() requires that the suffix start with a dot, so that doesn't work.
As you mentioned, using the division operator always creates a sub-directory, and with_suffix is only for extensions. You could use with_path to edit the filename:
import pathlib
path = pathlib.Path("2022-01")
path.with_name(f"{path.name}-candidates.csv")

Renaming files with different Names depending upon different match cases in Python

I'm a newbie at python, I'm trying to write a python code to rename multiple files with different names depending upon different match cases, here's my code
for i, file in enumerate(os.listdir(inputpath)):
if(match(".*"716262_2.*$"),file):
dstgco="Test1"+"DateHere"+".xls"
gnupgCommandOp=gnupgCommand(os.rename(os.path.join(inputpath,file),os.path.join(inputpath,dstgco)))
returnCode = call(gnupgCommandop)
if(match(".*"270811_2.*$"),file):
dstgmo="Test2"+"DateHere"+".xls"
gnupgCommandOp=gnupgCommand(os.rename(os.path.join(inputpath,file),os.path.join(inputpath,dstgmo)))
returnCode = call(gnupgCommandop)
currently what is happening is only one file is getting renamed which is Test2 DateHere with str object is not a callable error, my requirement is to rename files present at the location depending on the different match cases, I'm writing incorrect for loop or if statements?
things I have tried :
used incremental count
used glob
used only os.listdir and not enumerate
seems like it is matching the first statement and breaking on the next retrieval, may be I wrote If statements wrong
I can't debug this since I'm calling this code from an internal tool using a bat file.
can someone please help me out with this, I know only a single gnupgCommandOp should be used, is my syntax is wrong? is what would be a better way to achieve this?

One-line "for" loop using list comprehension

Someone has challenged me to create a program that sorts their pictures into folders based on the month they were taken, and I want to do it in one line (I know, it's inefficient and unreadable, but I still want to do it because one-liners are cool)
I needed a for loop to accomplish this, but the only way I know of to use a for loop in one line is list comprehension, so that's what I did, but it creates an empty list, and doesn't print anything from the list or anything.
What I'm doing is renaming the file to be the month created + original filename (ex: bacon.jpg --> May\bacon.jpg)
Here is my code (Python 3.7.3):
import time
import os.path
[os.rename(str(os.fspath(f)), str(time.ctime(os.path.getctime(str(os.fspath(f))))).split()[1] + '\\' + str(os.fspath(f))) for f in os.listdir() if f.endswith('.jpg')]
and the more readable, non-list-comprehension version:
import time
import os.path
for f in os.listdir():
fn = str(os.fspath(f))
dateCreated = str(time.ctime(os.path.getctime(fn)))
monthCreated = dateCreated.split()[1]
os.rename(fn, monthCreated + '\\' + fn)
Is list comprehension a bad way to do it? Also, is there a reason why, if I print the list it's [] instead of [None, None, None, None, None, (continuing "None"s for every image moved)]?
Please note: I understand that it's inefficient and bad practice. If I were doing this for purposes other than just for fun to see if I could do it, I would obviously not try to do it in one line.
This is bad in two immediate respects:
You're using a list comprehension when you're not actually interested in constructing a list -- you ignore the object you just constructed.
Your construction has an ugly side effect in the OS.
Your purpose appears to be renaming a sequence of files, not constructing a list. The Python facility you want is, I believe, the map function. Write a function to change one file name, and then use map on a list of file names -- or tuples of old, new file names -- to run through the sequence of desired changes.
Is list comprehension a bad way to do it?
YES. But if you want to do it in one line, it is either that or using ";". For instance:
for x in range(5): print(x);print(x+2)
And, by the way, just renaming a file including a slash will not create a folder. You have to use os.mkdir('foldername').
In the end, if you really want to do that, I would just recommend doing it normally in many lines and then separating it with semicolons in a single line.

Python - sorting incremented files

I have many folders that contains several versionned files. Here are example files:
Cat_Setup_v01.mb
Cat_Setup_v18.mb
The version number has a two characters padding. This way, I can easily sort files using:
listFiles = glob.glob( myPath + "*.m*") # Retrieve files in my folder
listFiles.sort()
Unfortunately, I have some files with more than a hundred versions. Thus, my sorting method is broken with v1XX as they are sorted between v09 and v10.
Is there an efficient way I can sort my files in the right way without having to rename them all and change their padding?
sorted(versionNumber, key=int) combined with some split string operations could be an interesting trail but I'm affraid it will be too cumbersome.
I don't know Python much and as it seems to be an interesting language with a lot of possibilities, I'm pretty sure there is a more efficient way.
Cheers
Regular Expression may help you.
import re
file=["Cat_Setup_v91.mb", "Cat_Setup_v01.mb", "Cat_Setup_v119.mb"]
print sorted(file, key=lambda x: int(re.findall("(?<=v)\d+", x)[0]))
give the output:
['Cat_Setup_v01.mb', 'Cat_Setup_v91.mb', 'Cat_Setup_v119.mb']
Updated: change "(?<=v)\w*" to "(?<=v)\d+" according to #Rawing comment

Getting just the current directory without the full path in python

I apologize if this is a question that has already been resolved. I want to get the current directory when running a Python script or within Python. The following will return the full path including the current directory:
os.getcwd()
I can also get the path all the way up to the current directory:
os.path.dirname(os.getcwd())
Using os.path.split will return the same thing as the above, plus the current folder, but then I end up with an object I want:
(thing_I_dont_want, thing_I_want) = os.path.split(os.getcwd())
Is there a way I can get just the thing I want, the current folder, without creating any objects I don't want around? Alternately, is there something I can put in place of the variable thing_I_dont_wantthat will prevent it from being created (e.g. (*, thing_I_want))?
Thanks!
Like this:
os.path.split(os.getcwd())[1]
Although os.path.split returns a tuple, you don't need to unpack it. You can simply select the item that you need and ignore the one that you don't need.
Use os.path.split:
>>> os.path.split(os.getcwd())
('/home/user', 'py')
>>> os.path.split(os.getcwd())[-1]
'py'
help on os.path.split:
>>> print os.path.split.__doc__
Split a pathname. Returns tuple "(head, tail)" where "tail" is
everything after the final slash. Either part may be empty.
You could try this, though it's not safe (as all the given solutions) if the pathname ends with a / for some reason:
os.path.basename(os.getcwd())
The standard pythonic way of denoting that "this is a thing I don't want" is to call it _ - as in:
_, thing_I_want = os.path.split(os.getcwd())
Note that this doesn't do anything special. The object is being created inside os.split(), and it's still being returned and given the name _ - but this does make it clear to people reading your code that you don't care about that particular element.
As well as being a signal to other people, most IDEs and code validators will understand that the variable called _ is to be ignored, and they won't do things like warn you about it never being used.

Categories

Resources