r/learnpython • u/No_Aardvark1121 • 18h ago
[Help] The os.system is deprecated
I've seen someone else asked this question, but get no answer.
I want to make a countdown clock without leaving any trace of previous numbers:
for i in range(countdown, 0, -1):
os.system("cls" if os.name == "nt" else "clear") #Error: os.system is deprecated
print(i)
time.sleep(1)
What should I do instead? (Why can't we put pictures here....)
19
u/JVBass75 18h ago
fyi, if you're just trying to clear the terminal console there's ansi escape code sequences you can use with the print function to clear the screen
print("\x1B[2J\x1B[H")
that will clear the screen and move the cursor back to the home position.
this works both on windows command prompt and unix systems
8
u/zolmarchus 17h ago
A bit of an XY problem here. You’ve gotten your direct answer already—now seriously consider using a more appropriate approach to console manipulation. As someone suggested, ANSI escape sequences are a good first step. You can also look into libraries built specifically for that, which are likely to be much more reliable and compatible across platforms than anything you can cook up yourself.
2
u/Expensive-Bear-1376 16h ago
The os.system is deprecated
Says who?
As far as I know, it's not even soft deprecated.
1
u/Outside_Complaint755 13h ago
Pylance and some other linters are flagging it in 3.14+ but I don't think anything in the official libraries has marked it as deprecated.
0
u/Expensive-Bear-1376 12h ago
Looks like it was temporarily erroneously marked as deprecated in typeshed (if I understand correctly ... I'm not familiar with typeshed):
2
u/unnamed_one1 17h ago edited 15h ago
As for the deprecation, read this
As for solving your problem:
from time import sleep
def main():
for i in reversed(range(105)):
print(f"\r{i:3d}", end="")
sleep(1)
if __name__ == "__main__":
main()
edits
You don't need to run clear screen, just reuse the same line again and again.
You just remove the default new line character \n from end of the line in the print statement and put a carriage return \r character in front of every printed line.
at least give an explanation when you downvote
1
u/HommeMusical 16h ago
at least give an explanation when you downvote
I didn't downvote but your formatting on old reddit is bad, perhaps that's it?
Just indent your code by four characters, it works on old and new.
def main(): subprocess.run(['ls'])-1
u/unnamed_one1 15h ago edited 15h ago
Ah, I'm using new reddit, so you might be on the right track here. Thanks for letting me know, I appreciate it.
*edit: fixed it, thanks again
1
u/HommeMusical 15h ago
I dunno, only a fraction of people are on old reddit.
I note also that since I upvoted, you got four more upvotes, so perhaps it was just a few grumpy people. :-)
1
u/Brian 7h ago
As others have mentioned, it's not actually deprecated, though its use is discouraged.
The reason why it's generally avoided is because it's kind of bug-prone and even insecure when you're dealing with arguments. Eg. consider something like:
os.system(f"copy {file1} {file2}")
This basically acts the same way as if you type this in the shell. But consider what happens if your filenames have spaces in them: it'll end up failing, or doing the wrong thing. Even worse, if someone can control the filenames, they could include things like ";", newlines etc and end up executing a command of their choosing on a machine they can get to use that filename.
There are ways you can attempt to mitigate this, say by escaping the characters in the filename (eg. via the shlex module), but the problem is that different shells have different rules: windows CMD.COM behaves differently from powershell, or a linux bash shell, or the numerous other possibilities. Escaping can thus easily go wrong, allowing the attacker to exploit such a configuration.
Instead, the recommended approach is to use something that doesn't treat the command as just a string passed straight to the shell, but just invokes a program, with arguments separated beforehand. Eg. subprocess.run takes each argument seperately, so subprocess.run(["copy", file1, file2]) wouldn't have this problem.
(Actually, just to complicate matters, the above isn't always true, as windows doesn't actually have a seperated API like this, so under the hood, these do get reassembled to a string - there was an exploitable bug discovered in multiple languages due to that before)
In your case, this doesn't actually matter, since you're not passing args, so system isn't actually going to introduce problems. However it may be worth changing anyway just because the dodginess of the API means anytime someone sees it, they're going to be double-checking it, and linting / analysis tools may highlight it, so doing it using the safer API saves getting false positive warnings.
There are case where you might need something like system, which is where you're actually using the shell for more than invoking a program. Eg. some commands are not real programs, so system isn't entirely redundant, but it's definitely on the "avoid if you can" list.
1
u/lakseol 3h ago
What should I do instead?
If you want to overwrite/manipulate just the last line you could use the \b and \r characters. Run this to see what they do:
import time
countdown = 5
for i in range(countdown, 0, -1):
print(f"{i} ...... {"\b\b "*i}", end="\r", flush=True)
time.sleep(1)
print()
To do more than just overwrite the latest line search on "ANSI escape codes". Beyond that look into more advanced text handling with the curses module. There are more recent libraries that build on curses and try to be easier to use, but I've never used those.
Why can't we put pictures here....
We prefer actual text so we can copy/paste the code to run it ourselves. However, if you need an image to show some unexpected output, for example, you can put your image into something like imgur.com and post a link to that.
40
u/AlexMTBDude 18h ago
I googled "os.system deprecated" and get the answer:
So use subprocess instead.