Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development #80

Merged
merged 7 commits into from
Dec 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ Currently in early alpha release, fuller features, proper install/packaging and

Excitedly welcoming contributors!


### Installation

Currently to use the application, you must clone or download the project from here on github. See [releases](https://github.com/toonarmycaptain/dionysus/releases) for a `zip` or `tar.gz`.
Expand All @@ -19,4 +18,5 @@ For development you will also need `pip install -r requirements_dev.txt`.
Either click on `app_main.py` in the project folder, or navigate to the folder and run `python -m app_main` on the command line.

#### Versioning
As much as possible this project will follow [Semantic Versioning](https://semver.org/).
As much as possible this project will follow [Semantic Versioning](https://semver.org/).

34 changes: 34 additions & 0 deletions dionysus_app/UI_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
UI functions: user interface functions used throughout the application.
"""

import tkinter as tk
from tkinter import filedialog

HUNDRED_NEWLINES = '\n'*100


Expand Down Expand Up @@ -64,3 +67,34 @@ def scrub_candidate_filename(dirty_string: str):
if c.isalnum()
or c in allowed_special_characters]).rstrip()
return cleaned_string


def select_file_dialogue(title_str=None, filetypes=None):
"""
Prompts user to select a file. Calls tkinter filedialog.askopenfilename
with title (if provided), and filetype argument (if provided) eg '*.png'.

filetypes is a list of tuples with 2 values, a label and a pattern
eg for png and all files: [('.png', '*.png'), ("all files", "*.*")]

Returns None instead of empty string if no file is selected.

:param title_str: str
:param filetypes: list
:return: str
"""
root = tk.Tk()
root.withdraw()

default_filetypes = [("all files", "*.*")]
if not filetypes:
filetypes = default_filetypes
filename = filedialog.askopenfilename(title=title_str, filetype=filetypes)

if filename == '':
return None
return filename


if __name__ == '__main__':
pass
3 changes: 2 additions & 1 deletion dionysus_app/chart_generator/take_chart_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ def take_score_data(class_name: str):

student_score = take_score_entry(student_name)
# add avatar to list of avatars for score
student_scores[student_score] = student_scores.get(student_score, []) + [avatar_path]
if student_score:
student_scores[student_score] = student_scores.get(student_score, []) + [avatar_path]

print('\n') # Newline between entering last score and 'Please enter a chart name/title: '

Expand Down
64 changes: 43 additions & 21 deletions dionysus_app/class_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

from dionysus_app.class_registry_functions import classlist_exists, register_class
from dionysus_app.data_folder import DataFolder, CLASSLIST_DATA_FILE_TYPE
from dionysus_app.file_functions import convert_to_json, load_from_json
from dionysus_app.UI_functions import clean_for_filename, input_is_essentially_blank
from dionysus_app.file_functions import convert_to_json, load_from_json, copy_file
from dionysus_app.UI_functions import clean_for_filename, input_is_essentially_blank, select_file_dialogue


CLASSLIST_DATA_PATH = DataFolder.generate_rel_path(DataFolder.CLASS_DATA.value)
Expand Down Expand Up @@ -83,16 +83,16 @@ def setup_class_data_storage(classlist_name):

def create_classlist_data(class_name: str):

class_data = compose_classlist_dialogue()
class_data = compose_classlist_dialogue(class_name)

class_data_feedback(class_name, class_data)
write_classlist_to_file(class_name, class_data)
time.sleep(2) # Pause for user to look over feedback.


def compose_classlist_dialogue():
def compose_classlist_dialogue(class_name):
while True:
class_data = take_class_data_input()
class_data = take_class_data_input(class_name)

if not class_data: # Test for empty class.
cancelled = blank_class_dialogue()
Expand All @@ -105,7 +105,7 @@ def compose_classlist_dialogue():
return class_data


def take_class_data_input():
def take_class_data_input(class_name):
"""
Take student names, avatars, return dictionary of data.

Expand All @@ -116,7 +116,7 @@ def take_class_data_input():
student_name = take_student_name_input(class_data)
if student_name.upper() == 'END':
break
avatar_filename = take_student_avatar(student_name)
avatar_filename = take_student_avatar(class_name, student_name)
class_data[student_name] = [avatar_filename]
return class_data

Expand All @@ -140,31 +140,53 @@ def take_student_name_input(class_data):
return student_name


def take_student_avatar(student_name):
def take_student_avatar(class_name, student_name):
"""
Prompts user for path to avatar file.

:param class_name: str
:param student_name: str
:return: str or None
"""
print(f'Load avatar image for {student_name}:')
while True:
avatar_file = input('Please paste complete filepath and name \n'
'eg C:\\my_folder\\my_avatar.jpg or N/None to skip: ')
if avatar_file.upper() == 'NONE' or avatar_file.upper() == 'N':
return None
if avatar_file_exists(avatar_file):
break
# else:
print('Supplied filepath cannot be found.')
avatar_file = select_avatar_file_dialogue()

if avatar_file is None:
return None

cleaned_student_name = clean_for_filename(student_name)
avatar_filename = f'{cleaned_student_name}.png'
target_avatar_filename = f'{cleaned_student_name}.png'

# TODO: process_student_avatar()
# TODO: convert to png or whatever, copy image file to class_data avatar folder with student name as filename
return avatar_filename
# TODO: convert to png, copy image file to class_data avatar folder with student name as filename
copy_avatar_to_app_data(class_name, avatar_file, target_avatar_filename)

return target_avatar_filename


def select_avatar_file_dialogue():
"""
Prompts user to select an avatar file. Only displays PNG files.
:return: str or None
"""
dialogue_box_title = 'Select .png format avatar:'
filetypes = [('.png files', '*.png'), ("all files", "*.*")]

filename = select_file_dialogue(dialogue_box_title, filetypes)

return filename


def copy_avatar_to_app_data(classlist_name, avatar_filename, save_filename):
"""
Copies given avatar image to classlist_name/avatars/ with given save_filename.

:param classlist_name: str
:param avatar_filename: str or Path
:param save_filename: str or Path
:return: None
"""
save_avatar_path = CLASSLIST_DATA_PATH.joinpath(classlist_name, 'avatars', save_filename)
copy_file(avatar_filename, save_avatar_path)


def avatar_file_exists(avatar_file):
Expand Down
20 changes: 20 additions & 0 deletions dionysus_app/file_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

import json

from shutil import copyfile


def convert_to_json(data_to_convert):
"""
Expand All @@ -28,4 +30,22 @@ def load_from_json(data_to_convert: str):
return converted_data


def copy_file(origin_fullpath: str, destination_fullpath: str):
"""
Takes two filepaths, copying the origin file to the destination path and filename.

Converts non-string object to string in case of Path object argument.



:param origin_fullpath: str or Path
:param destination_fullpath: str or Path
:return: None
"""
origin_fullpath = str(origin_fullpath)
destination_fullpath = str(destination_fullpath)

copyfile(origin_fullpath, destination_fullpath)


# use Path.rename(new_name) to rename a class.