woodenzen / zkdb

Zettelkasten Stats Dashboard
4 stars 2 forks source link

Code refactoring into functions #1

Open woodenzen opened 3 years ago

woodenzen commented 3 years ago

The code is too verbose and whats some reusable functions to condense and speed up execution.

flengyel commented 3 years ago

What version of python are you using? Python 3.x would be better than 2.7+, which is no longer supported. To generalize the repetitive code we may want to pass a function to an argument. Later a class can be defined to hold the variables, which are now global.

woodenzen commented 3 years ago

I'm using python 3.9.7.

I get that to deal with repetitive code one wants to create a function then use it in an argument. But how is this related to classes? I guess I'll see when we get there.

flengyel commented 3 years ago

Python 3.9.7 is great.

Classes can enter the picture depending on how the code is factored. There are a fews ways to handle the looping code.

  1. Factor the functions directly, no classes initially. The 10 day gap function has one additional line after the UUID comparison that the other gap functions don't have. There are (at least two) alternatives. 1.a. That additional line could be passed as a function, and defaulted to a function that returns without doing anything (for example).
    1.b. Add an argument for the tencountfiles, which is an empty list, default the parameter to None, test for None and if not None then do the append.

  2. Another way is to define a class that defines constants and variables. The class will rename the common nonlocal variables at the beginning from varname to self.varname within the class. The common function would appear as a member function that 2.a. works the same as 1.a; or 2.b. works the same as 1.b; or 2.c will have a subclass that handles the additional file concatenation, with a countfiles list that does not appear in the superclass.

There are variations. I'm inclined to go with 1.b at least for now, though subclassing and introducing the new behavior has something to be said for it. I think we should proceed in more intelligible steps.

woodenzen commented 3 years ago

Did you see @pryley's code for extracting the path to the currently selected zettelkasten directory for the plist file? It is nice in that it doesn't depend on the user to type the path which is error-prone and it changes dynamically when a second archive is active. He provided the code as an issue so I'll have to import it. It does test perfectly and @pryley is a trusted friend like you. There are some parts of the code which I'm unclear on. This is a class that is full of functions. Is it more pythonic to put these classes and functions in a separate file, then call them in the main code?

flengyel commented 3 years ago

Did you see @pryley https://github.com/pryley's code for extracting the path to the currently selected zettelkasten directory for the plist file?

Yes, I did.

It is nice in that it doesn't depend on the user to type the path which is error-prone and it changes dynamically when a second archive is active. He provided the code as an issue so I'll have to import it.
This is a class that is full of functions. Is it more pythonic to put these classes and functions in a separate file, then call them in the main code?

Yes. Using a separate file would be preferable. Use an import statement to load the class, create an instance and call the member functions...

Add the file to the repository, then I'll resync.

woodenzen commented 3 years ago

I've added archive _path.py to the repository.

flengyel commented 3 years ago

Synced. Start by importing the class TheArchive. Every member function of (the) TheArchive class annotated with @staticmethod, so there is no object of type TheArchive to instantiate. In this case, it's enough to import the class. The path() member function will become available to you. Add another line at the top (I'm not keeping up!) of zkdashboard.py as follows

from archive_path import TheArchive

You'll have to rename the file. I suggest replacing the dash with an underscore. Python expects module names to be lowercase alpha or underscore. Importing from archive-path.py will generate an exception. https://pretagteam.com/question/why-are-underscores-better-than-hyphens-for-file-names

Now see if it runs. The test function at the end of archive-path.py should come after

if __name__ == "__main__":

(a standard conditional "guard" statement) or it will run when the TheArchive class is loaded in zkdashboard,py. I'll fix that and generate a pull request.

In zkdashboard.py, use TheArchive.path() to set the path. It won't run on my system "because Windows," to use an Internet locution. I have a 2007 iMac I could try it on. Wish me luck. After hearing about the M1 chip, which is giving the competition in Silicon Valley ulcers, geysers of earwax and excessive navel lint—significant developments since the pandemic hasn't been a bonanza for personal hygiene—I might spring for a new toy.

Finally, credit @pryley, the developer of the code, if the author isn't mentioned.

woodenzen commented 3 years ago

It runs great. I change the name from archive-path to archive_path. I got a complaint from python about the "-". Fixed now.

I'm not sure what is meant by

The test function at the end of archive-path.py should come after

if name == "main":

(a standard conditional "guard" statement) or it will run when the TheArchive class is loaded in zkdashboard,py. I'll fix that and generate a pull request.

I left the end of achive_path.py like.

path = TheArchive.path()
# sys.stdout.write(path)

This has been merged to master.

flengyel commented 3 years ago

I'm going to add the if __main__ == "__name__": and indent. This is so the write statement only runs standalone, instead of when the code is imported. You'll still want to see the output the code can generate as a test when it isn't imported.

flengyel commented 3 years ago

An explanation: https://stackoverflow.com/questions/419163/what-does-if-name-main-do

pryley commented 3 years ago

I'm going to add the if __main__ == "__name__": and indent. This is so the write statement only runs standalone, instead of when the code is imported. You'll still want to see the output the code can generate as a test when it isn't imported.

I included the two lines at the end of the file to demonstrate how to use it, so you could also just remove them.

  1. TheArchive.plist() gets the content of the The Archive's plist settings file.

  2. TheArchive.setting(key) gets a specific setting from The Archive's plist settings file.

  3. TheArchive.path() gets the archiveURL setting from the plist file (TheArchive.setting('archiveURL')) and then removes the file:// prefix and unquotes any escaped characters.