-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
* Initial Commit after project creation. * - complete basic setup * - complete basic setup (#1) * Create pythonapp.yml * Update pythonapp.yml * Update pythonapp.yml * Update pythonapp.yml * Feature/basic gui (#2) * - complete project setup and structure - add unit tests - complete project - lap feature remains * - project complete * - add test case * - add Project Report.md * - add getting-started.md * - update getting-started.md * - update README.md * Update pythonapp.yml * - update test_stop_watch.py * - update test_stop_watch.py * - update test_stop_watch.py * - update test_stop_watch.py
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# This workflow will install Python dependencies, run tests and lint with a single version of Python | ||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions | ||
|
||
name: Python application | ||
|
||
on: | ||
push: | ||
branches: [ master, develop ] | ||
pull_request: | ||
branches: [ master, develop ] | ||
|
||
jobs: | ||
build: | ||
|
||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Set up Python 3.8 | ||
uses: actions/setup-python@v1 | ||
with: | ||
python-version: 3.8 | ||
- name: Install dependencies | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install -r requirements.txt | ||
- name: Lint with flake8 | ||
run: | | ||
pip install flake8 | ||
# stop the build if there are Python syntax errors or undefined names | ||
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics | ||
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide | ||
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics | ||
- name: Test | ||
run: | | ||
python -m unittest discover -s tests |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include pythonstopwatch/assets/*.png |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,30 @@ | ||
# fenway-savings | ||
A Python command line program for a banking system. | ||
# python-stopwatch | ||
A Python GUI for stopwatch. | ||
|
||
## Installation | ||
Clone the repository: | ||
```commandline | ||
git clone https://github.com/aditmodhvadia/python-stopwatch.git | ||
``` | ||
Go inside the repository: | ||
```commandline | ||
cd python-stopwatch | ||
``` | ||
Install using this command: | ||
```shell script | ||
pip3 install -e . | ||
``` | ||
##Run the programme by entering the following in console/terminal anywhere | ||
```commandline | ||
pstopwatch | ||
``` | ||
|
||
## To Run unit tests | ||
```commandline | ||
python -m unittest discover -s tests | ||
``` | ||
|
||
## To bundle the project | ||
```commandline | ||
python3 setup.py sdist bdist_wheel | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
This is not the instruction file, please find the complete instructions in [Project Report.md](../python-stopwatch/pythonstopwatch/docs/Project Report.md). | ||
Location /python-stopwatch/pythonstopwatch/docs/Project Report.md |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
python -m pip install -e . |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
"""Main file for application""" | ||
import os | ||
from tkinter import ACTIVE, DISABLED, Tk, Frame, BOTTOM, Label, PhotoImage, Button, TOP | ||
from pythonstopwatch.stopwatch import StopWatch | ||
from pythonstopwatch.constants.colors import TEXT_COLOR, BG_COLOR | ||
from pythonstopwatch.constants.strings import COPYRIGHT_TEXT, PROJECT_TITLE | ||
|
||
|
||
def start_pressed(stop_watch, start_button, reset_button, lap_button, play_img, pause_img): | ||
""" | ||
Start button pressed, set state of reset button to be ACTIVE | ||
If stopwatch is running then call stop and, change image | ||
else call start and change image | ||
:param stop_watch: Stop Watch | ||
:param start_button: Start Button | ||
:param reset_button: Reset Button | ||
:param lap_button: Lap Button | ||
:param play_img: Play/Start Image | ||
:param pause_img: Pause/Stop Image | ||
""" | ||
reset_button['state'] = ACTIVE | ||
if stop_watch.is_running(): | ||
stop_watch.stop() | ||
start_button['image'] = play_img | ||
lap_button['state'] = DISABLED | ||
else: | ||
stop_watch.start() | ||
start_button['image'] = pause_img | ||
lap_button['state'] = ACTIVE | ||
|
||
|
||
def reset_pressed(stop_watch: StopWatch, stop_button, reset_button, lap_button, play_image): | ||
""" | ||
Reset the stopwatch | ||
:param stop_watch: Start Button | ||
:param stop_button: Stop Button | ||
:param reset_button: Reset Button | ||
:param lap_button: Lap Button | ||
:param play_image: Play/Start Image | ||
""" | ||
stop_watch.reset() | ||
stop_button['image'] = play_image | ||
reset_button['state'] = DISABLED | ||
lap_button['state'] = DISABLED | ||
|
||
|
||
def lap_pressed(stop_watch): | ||
""" | ||
Record a Lap/Split time event | ||
:param stop_watch: Stop Watch | ||
""" | ||
stop_watch.lap_time() | ||
|
||
|
||
def main(): | ||
""" | ||
Main function. starting point of application | ||
""" | ||
root = Tk() # blank window | ||
root.title(PROJECT_TITLE) | ||
root['bg'] = BG_COLOR | ||
root.geometry("900x600") # give size to the window | ||
root.resizable(False, False) | ||
top_frame = Frame(root) | ||
stop_watch = StopWatch(root, bg=BG_COLOR) # pass root to this | ||
bottom_frame = Frame(root) | ||
top_frame.pack() | ||
bottom_frame.pack(side=BOTTOM) | ||
# only for aesthetics | ||
copyright_label = Label(bottom_frame, text=COPYRIGHT_TEXT, bg=BG_COLOR, fg=TEXT_COLOR) | ||
stop_watch.pack(side=TOP) | ||
copyright_label.pack(side=BOTTOM) | ||
|
||
# load images | ||
root_dir = os.path.dirname(os.path.abspath(__file__)) | ||
play_image = PhotoImage(file=os.path.join(root_dir + os.sep + 'assets' + os.sep + 'play.png')) | ||
pause_image = PhotoImage(file=os.path.join(root_dir + os.sep + 'assets' + os.sep + 'pause.png')) | ||
reset_image = PhotoImage(file=os.path.join(root_dir + os.sep + | ||
'assets' + os.sep + 'reset_enabled.png')) | ||
lap_image = PhotoImage(file=os.path.join(root_dir + os.sep | ||
+ 'assets' + os.sep + 'lap_split.png')) | ||
|
||
sub_sample_size = 7 | ||
play_image = play_image.subsample(sub_sample_size) | ||
pause_image = pause_image.subsample(sub_sample_size) | ||
reset_image = reset_image.subsample(sub_sample_size) | ||
|
||
start_button = Button(root, command=lambda: start_pressed(stop_watch, | ||
start_button, reset_button, lap_button, play_image, | ||
pause_image), | ||
bg=BG_COLOR, image=play_image, border=0, highlightthickness=0) | ||
lap_button = Button(root, | ||
command=lambda: lap_pressed(stop_watch), | ||
state=DISABLED, bg=BG_COLOR, image=lap_image, border=0, highlightthickness=0) | ||
reset_button = Button(root, | ||
command=lambda: reset_pressed(stop_watch, start_button, reset_button, lap_button, play_image), | ||
bg=BG_COLOR, image=reset_image, state=DISABLED, border=0, | ||
highlightthickness=0) | ||
|
||
lap_button.place(x=325, y=450) | ||
start_button.place(x=425, y=450) | ||
reset_button.place(x=525, y=450) | ||
root.mainloop() | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Constants for the project""" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
"""Constant color values for the project""" | ||
|
||
TEXT_COLOR = 'white' | ||
BG_COLOR = 'black' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
"""Constant string values for the project""" | ||
|
||
PROJECT_TITLE = 'Python Stopwatch' | ||
COPYRIGHT_TEXT = '©Adit Modhvadia 2020 All Rights Reserved' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Python Stopwatch (MET CS521 Information Structures with Python) | ||
|
||
##Introduction | ||
This is a python GUI project for a stopwatch using TKinter UI. It is a complete project with class definitions, unit tests and packaging. | ||
The project has a [stopwatch.py](../stopwatch.py) class which contains all the logic related to it. It also includes the LapTime class to store lap timings. | ||
|
||
The starting point of the project is the [__main__.py](../__main__.py) file which loads the project and sets up the main GUI. | ||
The project also contains unit tests for various methods/classes of the project which can be found inside [test_stop_watch.py](../../tests/test_stop_watch.py) and [test_string_time_utils.py](../../tests/test_string_time_utils.py) | ||
|
||
The project uses [history_logger.py](../logger/history_logger.py) to log the stop watch data after user hits reset. It is stored in [stop_watch_history.txt](../logger/stop_watch_history.txt) | ||
##How to run the project | ||
Instructions on how to run the project can be found in the [README.md](../../README.md) file in the project root folder. | ||
|
||
##Requirements | ||
The complete project runs using the standard library modules. The requirements for the project are mentioned in [requirements.txt](../../requirements.txt) | ||
They are part of the standard library and are not really used to run the project. They are used to package and distribute the project. | ||
|
||
##Features | ||
- The project takes inspiration from the Alarms & Clock application of Windows 10. | ||
- This project was built to solve the issue of keeping track/history of previous stopwatch runs and analyse/use the data as per the needs of the user. | ||
- When start is hit, it starts the stopwatch and shows with milliseconds precision, only after hitting start one can hit reset or lap time. | ||
- The project is built on pythonic ideals and it is built to be maintainable, scalable and testable. It is based on OOP design and uses inheritance as well. | ||
|
||
- The classes use assert to make sure the behavior is expected and it throws an error to bring it to notice of the developer that what they are doing might be wrong. | ||
- All the project assets are bundled and packaged with the project when shared inside assets folder | ||
- Files only import and required names from the modules. | ||
- All project constants including [colors.py](../constants/colors.py) and [strings.py](../constants/strings.py) are kept in a separate package and used as a single source of access for scalability and maintainability. | ||
- The project has a score of 9.69/10.0 pylint. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Logger for project""" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
"""Logs history of the stop watch""" | ||
import os | ||
|
||
LOG_FILE_NAME = "stop_watch_history.txt" | ||
|
||
|
||
def append_to_log(data: str): | ||
""" | ||
Append given data to log file | ||
:param data: given data | ||
""" | ||
root_dir = os.path.dirname(os.path.abspath(__file__)) | ||
|
||
try: | ||
log_file = open(os.path.join(root_dir + os.sep + LOG_FILE_NAME), "a") # open in append mode | ||
log_file.write(data) | ||
log_file.close() | ||
except FileNotFoundError: | ||
print("Error occurred, File not found") | ||
finally: | ||
print("Written to logs") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Stop watch: End Time:00:00:00.20 | ||
Lap/Split times | ||
Stop watch: End Time:00:00:00.00 | ||
Lap/Split times | ||
Stop watch: End Time:00:00:00.00 | ||
Lap/Split times |