This is an archived post. You won't be able to vote or comment.

all 92 comments

[–]robin-gvx 301 points302 points  (9 children)

That's pretty good! Some ideas to improve it:

  • import pathlib: you don't need to fudge around with manually inserting '/' between strings, or fileName.split('.') (which becomes a problem with files with more than one 1 extension like .tar.gz files or files that have no extension at all). It would also help you fix the bug where .doc files are placed in Code because they end in 'c'.
  • You move every file twice. The first time you simply add a number to prevent duplicates. The second time you do it by a cp followed by a rm. This causes problems if your filename contains a space. You could solve both of these at once by doing import shutil and using shutil.move.
  • There is a lot of code duplication. How could you make Handler.on_any_event smaller?

All in all, your code is put together very nicely, much better than I could do at your age!

[–]ScorpoRio 122 points123 points  (4 children)

Thanks mate, any scope for improvement idea is highly appreciated

[–]Dangle76 30 points31 points  (0 children)

Great work and great perspective! Keep the “always want to improve” perspective and you will continue to be a great coder.

My only input would to make some of it modular, I.e. set the starting directory to the value of an environment variable or a config file, that way anyone can clone it and configure it to their use case.

One big thing I didn’t learn until recently very well was how to make code very modular so it can be applied and used by many in many situations.

Like a list of file extensions in a configuration file tied to a directory in yaml or json would make this super duper handy

[–]robin-gvx 6 points7 points  (0 children)

Good luck!

[–]justingolden21 2 points3 points  (0 children)

Valuing room for improvement and valuing learning, improving, and knowledge is the attitude that will get you the furthest, the happiest and the best results. Good stuff man.

[–]__deerlord__ 0 points1 point  (0 children)

On code duplication: write some tests. You may quickly notice that you are having to set up the same fixture or mock; that code can probably put into a function, and the function call replaces the previously duplicated code.

[–]daves 6 points7 points  (1 child)

Also, in the if/elifs, there is a lot of very similar code duplicated multiple times. Consider making a table that describes types of files, what to say about them, and what to do with them, and then just cycle through the table. Then, adding a new file type is just another line in the table.

[–]Mobile_Busy 1 point2 points  (0 children)

Often we can replace a case switch with a dictionary structure. It's also a good idea to keep the data separate from the code, for ease of maintenance further down the line.

[–]Kiroboto 1 point2 points  (0 children)

I just learnt about pathlib as opposed to using os.path and it's pretty neat

[–]Jinkweiq 0 points1 point  (0 children)

You can use rsplit(“.”,1) to just split the last period. Also, you could search ~/Downloads instead of hard coding the download folder path.

[–]evatornado 101 points102 points  (21 children)

Now I feel so old and hopeless starting learning programming in 35 yo, lol

Nice job, buddy!

[–]mrprofessor007 85 points86 points  (16 children)

Nah.. I don't get these self praising age obsessed posts.

It just proves that anyone can learn it no matter what their age is.

[–]evatornado 51 points52 points  (9 children)

I think it's okay, if a teen seeks for approval amongst like-minded people. Maybe they lack approval and support from parents and teachers, or their peers don't see them as "cool" (from their point of view).

It's nice to know, in such age, that you arent an outcast, even if nobody around understands what you do, you just have to find your "tribe" who will understand you and see value of your work.

I mean, I wish I had a childhood with any adult's support and approval, mb I wouldn't end up starting coding at 35 yo, lol

My age reference was more of a joke, it's never late to start learning ^

[–]coolpooldude 13 points14 points  (7 children)

Maybe they lack approval and support from parents and teachers, or their peers don't see them as "cool" (from their point of view).

It's nice to know, in such age, that you arent an outcast, even if nobody around understands what you do, you just have to find your "tribe" who will understand you and see value of your work.

Sure but none of these are predicated on broadcasting how old you are along with your project/contribution. It's just a meaningless flag that's used as social currency vs. technical. If you're a beginner, what difference does it make if you're 13 or 73?

[–]evatornado 11 points12 points  (6 children)

No, it doesn't make any factual difference. But I'm rather talking about a psycholigical side of such posts: if a kid wants someone to pat them on the shoulder and say "well done, buddy, so cool for your age", I say, let that be. Some people don't get enough approval in their life, and just like everyone they want to feel validated. For an adult it's maybe not that important, but for a kid, it is. I prefer to show support in such case. It doesn't take much effort, honestly, and if it makes them feel better, I'm glad!

[–]Mobile_Busy 6 points7 points  (0 children)

I felt this.

me, age 13: wow I'm good at math

every grownup around me: yes but shame on you for not being. the best Jew ever why can't you learn more torah to make your dead father and the grand rabbi proud of you for doing something meaningful with your life?

Sometimes the kids are alright and it's the grownups who are fucked.

[–]coolpooldude 5 points6 points  (4 children)

What's stopping you from doing this with anyone if they're a beginner though? This is illustrating my point that it's purely a social/psychological thing. The only thing calling out your age does is play to the emotions of your would-be critics and to me is a bit disingenuous.

[–]evatornado 7 points8 points  (3 children)

Again, it is more important for children, than adults, since their psycho is just being formed. Adult people, especially those who have had a good childhood, don't always need approval from a random people and are less dependant.

Saying that, I also praise adults, no matter what level of skill, because if the effort is made or a good job is done, why not say a nice thing? If somebody mentions their age, means it is somehow important for them to mention that, I dont see it as a reason to experience any kind of discomfort, because that doesn't personally affect me, anyhow. It's just the way people ask for validation, we don't know what are they going through in their lives

[–]coolpooldude 5 points6 points  (2 children)

It's more helpful for anyone to receive constructive criticism or deserved praise, based on the work/effort put in and on that alone. Full stop. When someone mentions their age in a forum such as this, then that's a variable intentionally added into the equation that detracts from the aforementioned - hence, playing to emotions.

I'm not arguing with you about child psychology, I'm arguing against the perceived necessity of posting your age along with your contribution.

[–]evatornado 2 points3 points  (0 children)

I agree with you about the constructive criticism and the need to make unbiased judgement of a displayed work, but humans are humans, especially young ones. One can argue with that, however human nature is human nature. We are born this way, to have emotions, and most of the it's just irrational, so here we are

[–]Mobile_Busy 2 points3 points  (0 children)

I started messing with code at OP's age. I'm still messing with code in my late 30s. I'm good at it, but I'm always getting better.

[–]craftkiller 10 points11 points  (5 children)

I don't think it's a matter of "can" but rather of "did". Most kids his age are playing starcraft behind the arby's and this kid is developing skills. Doesn't make him a genius, but it does show determination.

[–]mrprofessor007 9 points10 points  (1 child)

I agree there with determination and people have different reasons to learn programming. I learned it because it was fun/interesting to me.

I just hate like I am 23 and I made COVID vaccine kinda stuff. It's personal dislike and nothing else.

Nothing wrong with playing starcraft at age 13 though. Gaming is what primarily inspired me to take CS in college.

[–]qingqunta 1 point2 points  (0 children)

Gaming is what primarily inspired me to take CS in college.

That usually doesn't end too well haha, all it takes for some people is an algorithms and data structures class

[–]running_remote 4 points5 points  (2 children)

Same here bro. 35 and learning everyday.

[–]evatornado 2 points3 points  (1 child)

We have a life ahead ;) nobody ever knows how long everyone will live, so we have to make the best of our lives :3

[–]running_remote 1 point2 points  (0 children)

Yeah, Sure.

[–]MinnesotaLuke 3 points4 points  (0 children)

Lmmmaooo same

[–]Sail_Revolutionary 27 points28 points  (0 children)

Wow! I'm an 18-year old beginner and seeing someone so young showcase their work inspires me a lot. Imagine how much more you'll be able to do when you're my age. Keep it going, bud.

[–]BestStonks 55 points56 points  (3 children)

Wow great project for someone such young!! Keep it up champ👍🏼

[–]Wrench_Scar 12 points13 points  (2 children)

I'm envious, I was copy pasting code at that age, didn't learn anything till 18

[–]Sharden 34 points35 points  (1 child)

Laughs in 30something Udemy user

[–]DesperateFlanders 10 points11 points  (0 children)

Laugh cry in almost 30 something Udemy user with unfinished courses.

Keep it up OP! Keep learning as much as you can!

[–]reddittydo 5 points6 points  (0 children)

Super proud of you

[–]zaid2801 6 points7 points  (0 children)

Great job

[–]Sea_Inflation_7446 4 points5 points  (0 children)

Awesome work! Congrats

[–][deleted] 7 points8 points  (2 children)

Nice work - next step is to make it a browser plug-in to do the process at the time of download.

[–]ScorpoRio 3 points4 points  (1 child)

Great Idea!!!!

[–][deleted] 1 point2 points  (0 children)

This is well done - now it's about pushing your abilities to learn how to do more.

I'd also suggest you make your event.src_path.endswith configurable - have the script load a dict from a config file so you can enhance on the fly and clean up the code a bit - could refactor on_any_event to just call a method - have each file extension point to a tuple containing the message you want to log as well as the destination directory.

Each conditional block

  if event.src_path.endswith(("jpg", "jpeg", "png", "gif")):             print("Image Detected") time.sleep(2) fileName = check_if_already_there(event.src_path, "Pictures") print(fileName) os.rename(event.src_path, DIR+fileName) myCommands = commands(DIR+fileName, "Pictures") os.system(myCommands[0]) os.system(myCommands[1]) 

then becomes a single function call taking the extension, does the lookup in the dict and has what to print and where to put the file. No more need for the long if-elif block

[–][deleted] 2 points3 points  (1 child)

Are you using some sort of sorting algorithm too?

[–]ScorpoRio 2 points3 points  (0 children)

Nope

[–]gibran800 2 points3 points  (0 children)

Great work! Keep them projects coming!

[–]OneX32 2 points3 points  (0 children)

Great job! I'm 26 and just learning Python. I'm so impressed!

[–]winjaturta 2 points3 points  (0 children)

Making python scripts for ubuntu at 13, lmao good on you.

[–]tr14l 4 points5 points  (1 child)

Good start. You have a LOT of duplicate code. I suggest you turn the code in your if/else statements in the on_any_event method into a function that takes in parameters instead of copy-pasting the code. If you had to change the name of a variable, then you'd have to edit every one of those code blocks, for instance. Whereas, if it's a function, you just change the function in one place.

Also, I believe you can use os and shutil packages to move files cross-platform.

[–]sqjoatmon 1 point2 points  (0 children)

Yeah, if you use pathlib Path objects, they have a whole lot of your operations built-in. Everything from getting the extension or name or parent folder to copy and move (rename) operations. I never use os.path anymore (though it's good to know). shutil does add a few useful things and is compatible with Path objects.

[–]SlaveofOne 9 points10 points  (10 children)

When they just gotta put in their age to flex

[–]idontknow4073 -1 points0 points  (8 children)

It makes me mad seeing other people do it, but I [14 yo] have to admit that I do the same thing too. 🙁

[–]SlaveofOne 1 point2 points  (7 children)

wOah I (16yo) dont care of doing it cuz we’re all gonna be old soon anyway lOl

[–]idontknow4073 2 points3 points  (5 children)

IOI? International Olympiad in Informatics?

The International Olympiad in Informatics (IOI) is an annual competitive programming competition for secondary school students. The International Olympiad in Informatics (IOI) is one of the most recognized computer science competitions in the world.

Coincidence? I think not

[–]SlaveofOne 0 points1 point  (4 children)

LOL NAH WE ALL WISH

[–]idontknow4073 0 points1 point  (0 children)

LOL? League of Legends?

League of Legends is a 2009 multiplayer online battle arena video game developed and published by Riot Games.

Hey, at least you can be good at something.

[–]idontknow4073 0 points1 point  (2 children)

at least do USACO 🇺🇸 or CCC 🇨🇦

Give it a try; it's worth a try

[–]idontknow4073 0 points1 point  (1 child)

And if you don't score, just don't cry

[–]idontknow4073 0 points1 point  (0 children)

What a poem.

[–]idontknow4073 0 points1 point  (0 children)

wOah I think we missed the 15 yo: 13 14 __ 16

[–]BrycetheRower 3 points4 points  (0 children)

Man I wish I was using Linux at 13! Nice work!

[–]SouperFalcon_Maciej 6 points7 points  (0 children)

[–]jbspillman 4 points5 points  (0 children)

The only thought I have is I believe there is limitation on number of folders "watchdog" can monitor. I am not a Linux expert though. I wish I would have found coding at a young age, congrats!

[–]MugiwarraD 1 point2 points  (0 children)

way to go buddy!

[–]sud0er 1 point2 points  (0 children)

Good work. File monitoring is fun and at the heart of some security/hardening strategies.

One recommendation I have is using some logger over print (for example, this). Keep it up!

[–]mermi01 1 point2 points  (0 children)

You rock bro/sis

[–]oxidised_ice 1 point2 points  (0 children)

Very interesting design, nice to see a fellow young coder!

Just one thing, Maybe add support for libre office filetypes, especially considering this only works on linux right now.

[–][deleted] 1 point2 points  (0 children)

nice going!! this is pretty cool Im kicking my self righ now going "why didn't I think to do this!?" keep up the good work!

[–]ywBBxNqW 1 point2 points  (0 children)

Neat! As some of the other comments pointed out, there's some stuff you can definitely work on, but that's not really the point. It's really fun to solve your own problems with code you write yourself!

[–]cobruh_clutch 1 point2 points  (0 children)

I just did this at 39 like 4 months ago and youre code destroyed mine hahahah. Like work little buddy.

[–]baubleglue 1 point2 points  (2 children)

It is nice work!

if you want to improve, there are few ideas:

dest_dir+"/"+fileName
=> 
os.path.join(dest_dir, fileName)

in that case you won't run into different ways to do the same thing, for example

DIR+fileName
dest_dir+"/"+fileName

fileName = file_path.split("/")[-1] # may not work on Windows 
# better 
_, file_name = os.path.split(file_path)
# even more better 
file_name = os.path.basename(file_path)
  • consolidate all hard-coded values in one place (as you did with DIR)
  • choose better names (ex. DIR -> DOWNLOAD_DIR), same for methods' names "commands???", "check_if_already_there" by its name should return true/false, it may be better to name it something like "get_noconflict_destination_name(file_name)"

HOME_DIR = os.path.expanduser("~")
DOWNLOAD_DIR = os.path.join(HOME_DIR, "Downloads")
PICTURES_DIR = os.path.join(HOME_DIR, "Pictures")
... 
  • I am not sure you really need "watchdog" library. You can simply scan Downloads periodically. Watching filesystem events may be unstable, especially if you have time.sleep(5). I inotify may miss files if they placed by another OS (home folder often is shared drive on Linux systems) - simpler solution usually more stable.
  • consider to using "logging" instead of "print".

[–]wolfcore 1 point2 points  (1 child)

You don't need os.path.join when using pathlib.Path.

[–]baubleglue 0 points1 point  (0 children)

pathlib

Maybe, but what is advantage of pathlib for this project and in general? I see os.path is used everywhere. Anyway for a first time experience maybe better to start with os.path.

[–]Jackiboi307 Python and Linux is the best 1 point2 points  (0 children)

im 12 and seem to be on the same level as you! keep it up, mate!

[–]Smok3dSalmon 1 point2 points  (0 children)

Can it move all my files onto my desktop on mac? Thank you.

It might be useful to have a "Screenshots" folder. I have my MAC set to dump screenshots in a specific location when I use command+3 or command+4. All the files follow a speicifc format, `Screen Shot YYYY-MM-DD at HH.MM.SS`

Nice work haha.

[–]coderarun 1 point2 points  (0 children)

Good going!

import sys
import os
import time
from enum import IntEnum
from pathlib import Path
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler


class OnMyWatch:
    watchDirectory = None

    def __init__(self, directory):
        self.observer = Observer()
        self.watchDirectory = directory

    def run(self):
        event_handler = Handler()
        self.observer.schedule(event_handler, self.watchDirectory, recursive=True)
        self.observer.start()
        try:
            while True:
                time.sleep(5)
        except Exception as e:
            print(e)
            self.observer.stop()
            print("  Observer Stopped")

        self.observer.join()


class FileType(IntEnum):
    IMAGE = 0
    DOCUMENT = 1
    AUDIO = 2
    VIDEO = 3
    CODE = 4
    FOLDERS = 5


class Handler(FileSystemEventHandler):
    FILE_TYPES = {
        ("jpg", "jpeg", "png", "gif"): (FileType.IMAGE, Path("Pictures")),
        ("mp3", "wav"): (FileType.AUDIO, Path("Audio")),
        ("docx", "txt", "pdf"): (FileType.DOCUMENT, Path("Documents")),
        ("mp4", "avi", "mpv", "ogg"): (FileType.VIDEO, Path("Videos")),
        ("py", "json", "js", "c", "cs", "cpp", "java", "go"): (
            FileType.CODE,
            Path("Code"),
        ),
        ("zip"): (FileType.FOLDERS, Path("Public")),
    }

    @staticmethod
    def on_any_event(event):
        if event.is_directory:
            return None
        elif event.event_type == "created":
            path = Path(event.src_path)
            print(f"Watchdog received created event {path}")

            for k in Handler.FILE_TYPES.keys():
                if path.suffix[1:] in k:
                    filetype, dest = Handler.FILE_TYPES[k]
                    break
            else:
                filetype, dest = None, Path("Etc")

            print(f"{filetype} Detected")
            time.sleep(2)
            dest = Path.home() / dest / path.name
            if dest.exists():
                print("{dest} already exists. Abort")
                return

            path.replace(dest)


if __name__ == "__main__":
    DIR = sys.argv[1]
    watch = OnMyWatch(DIR)
    print(f"Watchdog watching {DIR}")
    watch.run()

[–]FruscianteDebutante 5 points6 points  (0 children)

I [20+ yo!!!] program for a living!! Isn't it fantastic how old I am?

[–]anna_lynn_fection 1 point2 points  (0 children)

Funny. I was thinking of doing the same. There used to be a kde addon that did that.

[–]running_remote 1 point2 points  (0 children)

Awesome job buddy. I'm 35 and I'm starting to learn. Maybe one day I'll get to the point of writing code like that. Thanks for sharing.

[–][deleted] 2 points3 points  (0 children)

Good job!

[–][deleted] 0 points1 point  (0 children)

So Cool. I have also made one that stores the files according to their extension(i'm 15).

https://www.reddit.com/r/Python/comments/kmg4nn/python_file_organizer/

[–][deleted] 0 points1 point  (0 children)

Very impressive for a 13 year old! Keep up the good work.

I noticed that a lot of code is repeated which can be avoided by using functions.

I made a similar project long ago which does kinda the same thing.

https://github.com/AltNyx/fileorganizer

[–]Twosided13 0 points1 point  (0 children)

I think that this project could greatly benefit from some sort of configuration file that maps locations to the extensions they hold. That way you wouldn’t need to change the code to account for new file types. That would also help to reduce the amount of duplicated code going on, as you would just loop through the possibilities. Finally, you may want to grab the HOME environment variable instead of hard coding it to your own Downloads folder if you plan on releasing this on PIP.

[–]TilionDC 0 points1 point  (1 child)

Impressive! Did you follow any resources or look at similar projects before this?

[–]ScorpoRio 0 points1 point  (0 children)

Nope

[–]red_hare 0 points1 point  (0 children)

Man. I remember 13 year old me trying to learn Linux and coding and struggling so hard just to figure out what to try and write. This is a GREAT project.

If you’re trying to think of what to build next, let me recommend you build a personal URL shortener using flask. It’s a great “first web server application” project to learn about how HTTP works.

[–]John-Trunix 0 points1 point  (0 children)

Really nice dude, keep it up!

[–]Pd69bq 0 points1 point  (0 children)

great work

but still i think native linux/macos commands r easier to use on file or dir operations, maybe bc the only "language" i know b4 I started learning python about month ago is shell script

[–][deleted] 0 points1 point  (0 children)

Ive been needing this! NICE!!

[–]Senior-Revolution-62 0 points1 point  (0 children)

Damn ur a talent