Skip to content

Commit

Permalink
First Release (#3)
Browse files Browse the repository at this point in the history
* 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
aditmodhvadia authored Apr 27, 2020
1 parent 96ec8c9 commit 407a8ed
Show file tree
Hide file tree
Showing 36 changed files with 698 additions and 3 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/pythonapp.yml
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ MANIFEST
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
# Unit tests / coverage reports
htmlcov/
.tox/
.nox/
Expand Down Expand Up @@ -127,3 +127,4 @@ dmypy.json

# Pyre type checker
.pyre/
/.pypirc
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/dictionaries/aditm.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/python-stopwatch.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include pythonstopwatch/assets/*.png
32 changes: 30 additions & 2 deletions README.md
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
```
2 changes: 2 additions & 0 deletions getting-started.md
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
1 change: 1 addition & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python -m pip install -e .
Empty file added pythonstopwatch/__init__.py
Empty file.
107 changes: 107 additions & 0 deletions pythonstopwatch/__main__.py
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()
Empty file.
Binary file added pythonstopwatch/assets/lap_split.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added pythonstopwatch/assets/pause.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added pythonstopwatch/assets/play.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added pythonstopwatch/assets/reset_enabled.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions pythonstopwatch/constants/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Constants for the project"""
4 changes: 4 additions & 0 deletions pythonstopwatch/constants/colors.py
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'
4 changes: 4 additions & 0 deletions pythonstopwatch/constants/strings.py
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'
30 changes: 30 additions & 0 deletions pythonstopwatch/docs/Project Report.md
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.


1 change: 1 addition & 0 deletions pythonstopwatch/logger/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Logger for project"""
21 changes: 21 additions & 0 deletions pythonstopwatch/logger/history_logger.py
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")
6 changes: 6 additions & 0 deletions pythonstopwatch/logger/stop_watch_history.txt
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
Loading

0 comments on commit 407a8ed

Please sign in to comment.