3
\$\begingroup\$

The idea may sound stupid, but this is what I got to know that you should take a break at regular intervals to not to strain your eyes.

So the idea is to take break of 2 minutes for every 20 minutes of work and a break of 10 minutes for every one hour. People when working sometimes works continuously without monitoring the amount of time they spend on a single stretch. The reason for developing it in Python is to improve my coding skills.

#cat lock_sys.py 
import time
import subprocess

TIME = 20
BREAK1 = 2
BREAK2 = 10
COUNT = 3

def verify_pkg():

    #check if package is installed on the server
    check_pkg = subprocess.Popen(["apt", "-qq", "list", "gnome-screensaver"], stdout=subprocess.PIPE)
    pkg_avil = "installed" in check_pkg.communicate()[0]
   
    #if not installed, install the package
    if not pkg_avil:
       
        install_pkg = subprocess.Popen(["apt-get", "install", "-y", "gnome-screensaver"], stdout=subprocess.PIPE)
        check_pkg = "Setting up gnome-screensaver"    
        if check_pkg in install_pkg.communicate()[0]:
            return True

    elif pkg_avil:
        return True

def start_timer(timer):
    while timer:
        print(time.strftime("%Y-%m-%d %H:%M:%S"))
        time.sleep(60)
        timer -= 1
    return 0

def take_break(break_time):
    if verify_pkg(): 
        
        print("TAKE A BREAK OF {} minutes".format(break_time)) 
 
        #lock the screen 
        lock = subprocess.call(["/usr/bin/gnome-screensaver-command", "-l"])
        start_timer(break_time)        
  
        #unlock the screen
        unlock = subprocess.call(["/usr/bin/gnome-screensaver-command", "-d"])
        
          
if __name__ == "__main__":
   
    count = 1 
    while True:
        print("20 minute timer started with break {} minutes".format(BREAK1))
        start_timer(TIME)

        #count of 3 will make an hour. i.e 20*3=60 min
        if count == COUNT:
            print("HOUR timer started with break {} minutes".format(BREAK2))
            take_break(BREAK2)
            #intialize the count to 1 after the hourly break
            count = 1
        else:

            take_break(BREAK1)
            count += 1

Any improvements on this code are welcome.

\$\endgroup\$
1
  • \$\begingroup\$ I've been using Stretchly for years, perfect tool. \$\endgroup\$ Commented Sep 24 at 9:43

3 Answers 3

3
\$\begingroup\$

Documentation

The first line of code looks like an attempt at documentation:

#cat lock_sys.py 

The PEP 8 style guide recommends adding docstrings for the main code and functions. For example, you could summarize the purpose of the code:

"""
This code notifies you that you should take a break at
regular intervals to not to strain your eyes.

The idea is to take break of 2 minutes for every 20 minutes of work and a
break of 10 minutes for every one hour.  People sometimes work continuously
without monitoring the amount of time they spend on a single stretch.  
"""

For the functions, describe their purpose, their inputs types (if any) and what they return. For example:

def verify_pkg():
    """
    Check to see if the screensaver application is installed.
    If not, then install it.
    Return True if now installed, or False otherwise.
    """

Naming

It is good that you declare constants like these:

TIME = 20
COUNT = 3

However, these names are too generic.

MINUTES would be more specific than TIME. NUMBER_OF_BREAKS would be more specific than COUNT.

pkg_avil would be better as is_pkg_avail.

Simpler

This if/elif statement:

if not pkg_avil:
elif pkg_avil:

would be simpler as an if/else since pkg_avil is a boolean type.

But, the logic of the function can be further simplified as:

def verify_pkg():
    # Check if package is installed on the server
    check_pkg = subprocess.Popen(["apt", "-qq", "list", "gnome-screensaver"], stdout=subprocess.PIPE)
    pkg_avil = "installed" in check_pkg.communicate()[0]

    if pkg_avil:
        return True

    # If not installed, install the package
    install_pkg = subprocess.Popen(["apt-get", "install", "-y", "gnome-screensaver"], stdout=subprocess.PIPE)
    check_pkg = "Setting up gnome-screensaver"    
    if check_pkg in install_pkg.communicate()[0]:
        return True

    # The installation did not succeed
    return False
\$\endgroup\$
2
\$\begingroup\$

Return values

Consider this simplification of your code:

def verify_pkg():
    …
    if not pkg_avil:
        …
        if check_pkg in install_pkg.communicate()[0]:
            return True
    elif pkg_avil:
        return True

This function will return True, or it will return … what? Nothing at all?

Actually, every Python function always returns a value. If you don’t explicitly return one, None is returned, so your function returns either True or None, which is strange. You should explicitly return False instead.

Package not available?

If the package is installed, verify_pkg() attempts to install it. If it still isn’t available, it returns None (or False with the above change).

def take_break(break_time): starts off with if verify_pkg():, which as stated above returns a falsy value if the package isn’t available and can’t be installed. If that falsy value is returned, take_break() does nothing.

20 minutes later, it will again do nothing.

20 minutes after that, again nothing will happen.

While it appears your code is trying to be fault-tolerant, it doesn’t handle the problem at all. It doesn’t even bother printing out the TAKE A BREAK OF # minutes message. It doesn’t run the break timer, nor print out a message when the break is over.

Instead, when the code starts, it should verify the package is available, and install it if possible. If it is not available, the program should terminate with the message describing the problem.

Then, it need not call verify_pkg() ever again.

Type Hints

Type hints will go along way towards reminding future you want a function returns, and what it expects.

For example:

  • def verify_pkg() -> bool:def start_timer(timer: int) -> None:
  • def take_break(break_time: int) -> None:

Python will mostly ignore the type hints, but you can run a type-checker on the program, and it can flag issues where you get the types wrong.

For instance, verify_pkg() currently doesn’t return a bool, it returns None some of the time. That would be flagged a type-error

Calling start_timer(1.5) would actually run forever and never return! The type-checker would complain that you passed a float value where an integer is expected, potentially catching a bug.

Better naming

Does start_timer() start a timer? No. By the time the function returns, no timer has been started. Maybe break_timer() would be better.

The parameter timer is equally obscure. You aren’t passing in a timer object. You are passing in a during … specifically in minutes.

So, maybe this would be clearer:

def break_timer(minutes: int) -> None:

\$\endgroup\$
2
\$\begingroup\$

Testing whether gnome-screensaver is installed is quite platform-specific (["apt", "-qq", "list", "gnome-screensaver"]) and won't work on systems that use a different package manager. What we care about is whether /usr/bin/gnome-screensaver-command is executable, so simply test for that instead. It might even be a good idea to actually invoke the command with -q/--query to determine whether there's a running screensaver for it to talk to (simply being installed doesn't mean there's a running instance in this user's environment).

I'd say that attempting to install the package is a bad idea. As well as being platform-specific, it's going beyond user intention - for example, it might be an inconvenient or expensive time to start generating network traffic. And there's a good chance that the system's package indexes are out of date anyway. It's better to exit with an error message stating what's wrong, perhaps with advice on fixing it.

The program is somewhat inflexible in that it works only with the GNOME screen saver and not with any others (my Debian system lists at least half a dozen available screen savers). It wouldn't be hard to try a range of different commands until one works (a good idea to remember which one, as it's unlikely to change before we next invoke it).

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.