📜 ⬆️ ⬇️

GymPy - a log program for lovers of iron



Of the features: PyGTK (hildonize for Nokia N900), self-modifiable code, so as not to mess with config files.

By tradition, lyrical introduction.

Going to the gym for the past two years has been more of a social event for me than a focused workout and thoughtful pumping of the right muscle groups. It so happened that when two or three PhD students from different, but nearby areas of science gather in one place, and the natural aggravation of all three is added to the tongue — nothing can stop this stream of consciousness.
')
But by the will of fate, and, one might say, bad rock, our company fell apart. A catastrophic lack of time and the possibility of coordinating schedules on the one hand, and old injuries on the other, have led me to go to the gym for the last three months alone. And honestly, I don’t even regret it.

When the question arose, and it was necessary to make a decision - to give up this “bad” activity or, on the contrary, take it seriously, think over the training program and acquire theoretical knowledge of the subject, it was a combination of circumstances. Very much in time, my brother ( akusto ) showed a 5x5 training session , which he himself then used for a couple of weeks. She received first place among the many programs on bodybuilding.com . Briefly, it can be described as 4 days with 5 sets of 5 repetitions for all major muscle groups with a fixed rest time between exercises and sets. The last for me was very important. So how exactly exactly the specified training time gives some underlining and completeness to this action. Plus, the exercises were chosen from the best rated bodybuilding.com .

Strict time requirements and mandatory weight gain each week led to an obvious decision - to write a program that would inform you about the need to start the next exercise and keep the weight of the barbell / dumbbell, which could be increased as needed (according to the training condition, weight need to increase if you were able to complete all 5x5 repetitions).

It's time to open your favorite IDE and put in a couple of lines of python. Since the code turned out to be a bit long for a habr (~ 251 line), it is suggested to follow this link to get acquainted with the full sheet.

Now we will sort in parts.

Having connected all used modules (lines 7-14), we create a program class. This is done mainly only to ensure that functions (which are not yet in the code) have access and use a single namespace variable. Starting from the 19th line, these most common variables are initialized (to call them global will be a little wrong from the point of view of Computer Science). The variable self.exercise_list contains a list of exercises that starts on the day of the week. Each line stores the name of the exercise and the working weight in lbs (pounds; kilograms in the states have not yet taken root), followed by the "x5" symbols. They were put there not by chance. It is for these two symbols that I will determine that the preceding number is weight. Well, symbolically, this indicates that the "5x5" training program is used.

In free days of the week, for example on Wednesday (line 36), the variable contains only a line with the name of the day of the week. Only the name of this day of the week will be displayed if we enable the script on Wednesday.

Lines 57-68 set the variables that define the script execution parameters.

The following is the main functionality of the script, which we will discuss later.

From line 189, the main program execution cycle begins and a class object is created. Particular attention should be paid to the lines 198-201. In them we find the path to the pygym.srcfile script being executed and read the Python source code in pygym.src . This is done so that you can then change the source code and save it for later execution without bothering with storing the configuration file separately. That is, the code will change itself.

All subsequent lines are GTK and hildonize the description of the widgets in the main window, which we create in line 199 and show in 247th. Then the main GTK loop is executed.

Here is such a skeleton. But we have not figured out what he can do. Let's look at the functionality of the main program class.

  1. def create_labels ( self ) :
  2. self . labels = [ ]
  3. self . exlist = self . exercise_list [ self . weekday ]
  4. for ex in self . exlist . split ( ' \ n ' ) :
  5. self . labels . append ( gtk. Label ( ex ) )
  6. self . ex_vbox . pack_start ( self . labels [ - 1 ] , True , True , 0 )
  7. self . bold_label ( )
  8. self . ex_vbox . show_all ( )


The function will display a list of exercises as an array gtk.label . In line 3 of the list of all exercises of the week, we select the current day self.weekday . We split a multi-line variable with split into separate lines and add them to the vertical container self.ex_vbox . We start the balding function of highlighting (thickening) the active exercise (or rather, this is an exercise that can be edited at the current moment), and show the vertical container and all its new contents.

  1. def bold_label ( self ) :
  2. if self . active_ex ! = - 1 :
  3. self . labels [ self . active_ex ] . set_markup ( '<b>' + self . labels [ self . active_ex ] . get_text ( ) + '</ b>' )
  4. def debold_label ( self ) :
  5. self . labels [ self . active_ex ] . set_text ( self . labels [ self . active_ex ] . get_text ( ) )


Everything is as it was written - the first function using markup adds bold tags to an active exercise; the second removes these tags.

  1. def pause ( self , pause_time, set_number = None ) :
  2. start_t = time . time ( )
  3. while ( time . time ( ) -start_t < pause_time ) :
  4. temp_t = time . time ( )
  5. while time . time ( ) -temp_t < 1 :
  6. while gtk. events_pending ( ) : gtk. main_iteration ( )
  7. time . sleep ( self . sleep_time )
  8. if set_number:
  9. self . status . set_text ( self . excercise . get_text ( ) + ' \ n % 03i seconds left before set #% i' % ( pause_time -
  10. time . time ( ) + start_t, set_number ) )
  11. else :
  12. self . status . set_text ( self . excercise . get_text ( ) + ' \ n % 03i seconds left' % ( pause_time - time . time ( ) + start_t ) )
  13. if pause_time > self. pause_rep and int ( pause_time- time . time ( ) + start_t ) == self . pre_ex :
  14. os . system ( 'dbus-send --print-reply --system --dest = com.nokia.mce / com / nokia / mce / request com.nokia.mce.request.req_vibrator_pattern_activate string: "PatternChatAndEmail"> / dev / null ' )
  15. if pause_time > self. pause_rep :
  16. os . system ( 'dbus-send --print-reply --system --dest = com.nokia.mce / com / nokia / mce / request com.nokia.mce.request.req_vibrator_pattern_activate string: "PatternChatAndEmail"> / dev / null ' )


One of the main functions of the program is waiting for a pause and vibration at the most inappropriate moment ... Line 6 is important. If you do not turn it on, the application will simply not respond to clicks and will not update the screen. This is just an instruction for GTK to check and process all messages and events of the application. On the 14th and 16th lines, an external program is called that sends a DBus message for a long vibration (about 1 second). This is a slightly dirty approach, since it would be possible to connect the DBus module and do it all inside the python, without causing any external applications. But it was just too lazy!

And finally, the most delicious - self-modifiable code.

  1. def weight_change ( self , button ) :
  2. if self . active_ex > 0 :
  3. ex = self . labels [ self . active_ex ] . get_text ( )
  4. lmatch = re . search ( "([0-9.] *) x5" , ex )
  5. if lmatch:
  6. if button. get_label ( ) == '+' :
  7. new_weight = self . weight_increment + float ( lmatch. group ( 1 ) )
  8. elif button. get_label ( ) == '-' :
  9. new_weight = - self . weight_increment + float ( lmatch. group ( 1 ) )
  10. if new_weight == int ( new_weight ) :
  11. new_weight = '% i' % new_weight
  12. else :
  13. new_weight = '% .1f' % new_weight
  14. new_text = ex [ : lmatch. start ( 1 ) ] + new_weight + ex [ lmatch. end ( 1 ) : ]
  15. self . labels [ self . active_ex ] . set_text ( new_text )
  16. self . bold_label ( )
  17. self . src = re . sub ( ex, new_text, self . src )
  18. self . write_source ( )
  19. elif self . active_ex == 0 :
  20. #if self.start.get_property ("visible"):
  21. for ex in self . labels :
  22. ex. destroy ( )
  23. if button. get_label ( ) == '+' :
  24. self . weekday = ( self . weekday + 1 ) % 7
  25. elif button. get_label ( ) == '-' :
  26. self . weekday = ( self . weekday - 1 ) % 7
  27. self . create_labels ( )
  28. else :
  29. hildon hildon_banner_show_information ( button,
  30. '0' , "Use 'v' or '^' buttons to choose an exercise" )
  31. def write_source ( self ) :
  32. # write the source code back
  33. f = open ( self . srcfile , 'w' )
  34. f. write ( self . src )
  35. f. close ( )


Here are two functions. One is called when you press the weight change buttons, the second saves the changed source code. In the 4th line there is a search for a regular expression of a number with the symbols "x5" at the end. Perhaps it is a bust to use RE for such a simple case. But I wanted to show how this can work in the general case for a code of any complexity. Having found the necessary numbers, we modify them according to the pressed button - we add / subtract from the current weight self.weight_increment . From the 10th to the 13th lines, we will convert the number to a whole without a dot or into a decimal with one decimal place (or after the dot ... I'm confused). And we already save the new value, replacing it in the old lines (14). We substitute this replacement into the source code of the program (17) and save it to a file (18 => 32). Lines 19-30 handle the day of the week change event. That is, the program can be viewed and even run on the execution of not only the current day, but also the programs of other days of the week.

Here, perhaps, that's all for today. Thank you for your attention, you had a PhD weight lifter Vadikus with you.

Source: https://habr.com/ru/post/107654/


All Articles