-
Notifications
You must be signed in to change notification settings - Fork 17
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
Implementing DataBase and Personalization #92
base: master
Are you sure you want to change the base?
Conversation
Fixed a bunch of bugs Added some docstrings and comments Needs to add more docstrings and comments and clean the code
Added the Default Button
Added more docstrings fixed them and added gitignore for PersonDB.db
I have a question about if i should add more things or leave it as is, |
Hey @etiontdn I am so sorry it is taking me some time to give you proper feedback on this. I hope I will have time to do so tomorrow. Thank you for being patient. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, I have added a few comments to the first part of the code, did not have time to go through the entire thing tonight. I will continue tomorrow :)
again, as their names say they select and change the information in the database | ||
""" | ||
import sqlite3 | ||
class DataBaser(object): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we change the name to Database? Is there a specific reason for the r? I think it could cause some confusion in the future, cause most people will probably try to spell it without the r?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it could, but the name databaser is more beautiful 😄
The name is derived from words like driver "someone that drives or do all things needed to drive a car"
So databaser does all database things needed by the program.
But yes it can be changed for better understanding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uuh, I like the idea, and I always enjoy playing with words, but I think for making it easy for people to use in the future, just calling it database might be the better way to go
|
||
Attributes: | ||
cdb: is the Connector to the DataBase,it creates a new file if it | ||
doesnt exists as well |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can make this description a bit more clear. You write as well, but I am a little unsure about what it will be as well as? Is this function both for if there is no user already, and if a user exists, or only for new users?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It creates a New file if the .db file doesnt exist
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, but the variable itself is only the connection right, and then you use that connection to create a new file - or did I misunderstand? Maybe the description of the variable can just be something like "the connection to the database" And then in the location where the file is actually created, we will comment it there. Would that make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sqlite3 database connector automatically creates a db file if there isn't one. but if comments can help to better understanding it can be added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the wording can be something like:
cdb: the Connector to the DataBase. Will create a new database file if it doesn't exist already.
creates a Table, if it exists uses try and except so error doesnt raise | ||
""" | ||
self.cdb = sqlite3.connect('PersonDB.db') | ||
try: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good with a comment on the try line, e.g. "try to establish a new person" or something more descriptive
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't creates a new person it creates a table so it maybe could be
try: #try to create a new table
And
except: #if the table already exists don't raise error so the program isn't interrupted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I like those suggestions, it makes it very clear what the code does :)
DAYSGOAL INT NOT NULL, | ||
MOTIVATION TEXT NOT NULL);''') | ||
self.cdb.commit() | ||
except sqlite3.OperationalError: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens to the program if an operational error occurs, and this step is passed? Will the program still be able to continue? If not, maybe we need to terminate or something here? I don't know a lot about working with databases. What kind of things could go wrong, to have us end up within the except state do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The operational error occurs if you try to create a table with the same name of one that was already created.
When it passes it wont create a new one it just doesnt let the error interrupt the program.
#Default Values: | ||
primary_color = "#0000FF" | ||
secondary_color = "#008000" | ||
motivational_phrase = "Put Motivational phrases Here" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible for this to just be an empty string? Right now it displays this placeholder text on the canvas when the user haven't set their motivational phrase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I just wanted to show to the user that he can put a motivational phrase there, but I think it came empty
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we have to figure out how to best let the user know that they have that option, but the text makes it seem like the user can click it and add text (at least, they might think they can), so I think we need to think a bit more about how we can do it best. For now, let us just not display it, until they set a personal one :)
def check_if_user_exists(self, person_name): | ||
"""Check if User exists in The DataBase | ||
Args: | ||
person_name: The Name of the person that will be searched in the DB |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the docstring of functions that return something, we also include:
returns:
[description of what it returns, e.g. "true if the user exists in the database, false if not"]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It only returns true because if the user name doesn't exists it creates a new one, I didn't set a return docstring but it could be added for better understanding
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I think we should split this up into two different functions. Could we make a function that simply just checks if a user exists, and returns true if it does, and false if it does not. And then another function which creates a user? In the create-user-function we can then first check if the user exists (by calling the first function), and then only if false is returned (if user does not exist) will the function create a user. The second function doesn't need to return anything. We will need a function that can truly just check if a user exists and return true/false for some other parts of the program, so I think splitting them up would be really useful. What do you think?
Args: | ||
person_name: The Name of the person that will be searched in the DB | ||
""" | ||
x = "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we can find a more descriptive name for this variable, which will make the code easier for others to read? For example, username or name_holder
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
person_name: The Name of the person that will be searched in the DB | ||
""" | ||
x = "" | ||
c = self.cdb.execute("SELECT * FROM PERSON\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest that we call c cursor instead. I think it will make it easier for others to read. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it could be changed for better understanding.
x = "" | ||
c = self.cdb.execute("SELECT * FROM PERSON\ | ||
where NAME='%s'" % person_name) | ||
for row in c: #For row in c(cursor) x = row[0](NAME if select *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have much experience with database, so I am not sure if I understand this correctly, but what is the function of the loop? If you can go directly to row[0] as it looks like you are doing within the for-loop, would it maybe be possible to do it without a loop? Maybe I completely misunderstood something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C selects part of the table where Name is equal person name.
Row is a row from the table where the first item is NAME so when row[0] is called it returns the name.
I'm not exactly sure if the cursor returns a dictionary or a list I will give it a try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, it seems to me that you can just go directly to calling the row, without looping. Maybe you'll have to do something like c.row[0] or something like that. Let me know what you find out, and I can try and look into it more myself too, if you want some help :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the little bit of looking at SQLite that I've had time to do tonight, I found this line in some code, and it seems like it is doing the same as what you want but without the for-loop. Maybe something like this could be done in our code too?
row = cursor.fetchone()
There are also fetchall and fetchmany, but since we are only interested in getting one line, I think fetchone should do the job.
Hey @etiontdn I am sorry that it has taken me so long to get back to you, it has been some crazy week with finals and other stuff I had to fix. I really like how it looks when I run the program with your additions! I have started reviewing your code and giving some feedback, I didn't get all the way through, it is taking me some time, as I don't have much experience with databases. I will continue tomorrow, to look at the rest of the code. Let me know if you have any thoughts or questions about my comments:) |
Thanks for the feedback, I will try to answer your comments but I can't make the changes right now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hey, I have added some more comments, you can take a look at them when you have time. I had hoped to finish the review tonight, but it is getting late, and it is taking me some time to work through this, as I am new to both database and ttk. The last thing I haven't gone through yet is the user.py file, I will take a look and give my feedback on it as soon as possible :) Let me know if you have any questions or anything you would like to talk more about in the comments I have given you so far. :)
def check_if_user_exists(self, person_name): | ||
"""Check if User exists in The DataBase | ||
Args: | ||
person_name: The Name of the person that will be searched in the DB |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I think we should split this up into two different functions. Could we make a function that simply just checks if a user exists, and returns true if it does, and false if it does not. And then another function which creates a user? In the create-user-function we can then first check if the user exists (by calling the first function), and then only if false is returned (if user does not exist) will the function create a user. The second function doesn't need to return anything. We will need a function that can truly just check if a user exists and return true/false for some other parts of the program, so I think splitting them up would be really useful. What do you think?
x = "" | ||
c = self.cdb.execute("SELECT * FROM PERSON\ | ||
where NAME='%s'" % person_name) | ||
for row in c: #For row in c(cursor) x = row[0](NAME if select *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, it seems to me that you can just go directly to calling the row, without looping. Maybe you'll have to do something like c.row[0] or something like that. Let me know what you find out, and I can try and look into it more myself too, if you want some help :)
where NAME='%s'" % person_name) | ||
for row in c: #For row in c(cursor) x = row[0](NAME if select *) | ||
x = row[0] | ||
if x == "": #If x = ""(nothing) means no user with that name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great with the comment here. I think we can make it even more readable for humans, by saying something like "If no user with the name exists yet, create a new user with the name" or something like that :) I try to avoid writing any code like things in the comments (things like = and variable names), to make them more human-friendly. I know there are many different commenting styles, so no worries if you are used to doing it another way. I will make suggestions in places where I think we can avoid putting code in comments, but please let me know if you have questions or comments about the comment-styles of the project :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright I think it is more human readable like that as well but I'm too biased towards math operators but I think these comments can be more readable
if x == "": #If x = ""(nothing) means no user with that name | ||
self.new_person(person_name) #Creates a new person | ||
|
||
return True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please see my comment for line 70 :)
""" | ||
Get the number of days of the person with person_name | ||
Args: | ||
person_name: Name of the Person to get his number of days |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just two comments about docstring style. You are doing a really awesome job of adding one-line summaries to the docstrings, those are always the hardest ones for me to write, but yours are really good. Just remember to add a blank line after your summary line (the first line of the docstring) before any other lines (this is just part of the standard format, and means that if we are gonna pull all our docstrings out for documentation at some point in the future, a computer will be able to parse them automatically)
Also, for functions that return something, we need to include something like this:
returns:
number of days the user has completed
That way, other contributors get a quick overview about what the function does, which arguments it takes, and what it returns
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of saying "his number of days" it would be great if we could say "their number of days", so that the code is gender neutral :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I will try to add a short return description in the docstrings.
And I will change words for better gender neutrality.
defaults_button.grid(row=1, column=0, sticky="WE") | ||
apply_button = ttk.Button(self.root, | ||
text="Apply",command=self.apply_values) | ||
apply_button.grid(row=1, column=1, sticky="WE") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't worked with ttk, so I am excited to learn more about it. Would you mind explaining what the sticky keyword does? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes the widget take all the space he can from the sides:
wens that are respectively west, east, north and south.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool, thanks :)
self.secondary = Tk.IntVar() | ||
self.primary.set(colorslist[self.user.get_color_primary()]) | ||
self.secondary.set(colorslist[self.user.get_color_secondary()]) | ||
c=0 #amount of columns |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In these lines (479-481) I would suggest changing the variable names. It will take up a bit more space to write them every time, but it makes it easier to read, and then we don't need to add that comments that explain what the variable is, because the name will do it automatically. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I will try to make better variable names.
c=0 #amount of columns | ||
r=1 #row number | ||
v=0 #the number value | ||
for color in colors: #a for loop that creates the buttons |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
awesome that added a comment here! :)
variable=self.primary, value=v).grid(row=r, column=c) | ||
v = v + 1 | ||
c = c + 1 | ||
c = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to make sure I understand the code (sorry, it is getting late at night here, my brain is not so sharp anymore), would you mind explaining why the values are reset here, and why some are set to 0 and some are set to 3? I am sure it is probably obvious, but I appreciate the help keeping track of everything:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make different columns and rows for the grid, I think I need to change var names there as well.
v = 0 | ||
self.secondary_label = ttk.Label(self.colors_tab, text="Secondary Color") | ||
self.secondary_label.grid(row=2, column=4) | ||
for color in colors: #another for loop instead of copy&paste |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this comment is good at explaining your choice, but since the code will constantly keep changing when people are adding more and more stuff, as time passes, it may become a little unclear what this references to. I think it might be better to just explain what the for-loop does, is that ok with you? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright.
I think I miss clicked something. |
@etiontdn I am not sure I understand your last comment, what makes you think you misclicked something? |
I think it is fixed now. I don't have a computer available right now, so I'm using my phone and I miss clicked a button. |
@@ -16,7 +16,7 @@ | |||
any other part of the program, but is included in order to accomodate | |||
their inclusion in the future (see https://github.com/lineaba/prog-o-meter/issues/33). | |||
""" | |||
|
|||
from database import DataBaser as DBser |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you change the name of the database object, remember to also change it here :)
I started looking through the user.py changes in your pull request, and I am wondering if there is still a use for this module, since a lot of the functions are created in your database file, and it seems like the user.py functions are more wrappers around the database functions. So I am wondering if we can possibly use the database functions directly, rather than the user functions, I think that would be easier to track for a beginner. |
@lineaba If the
If you do something like that, then inside the User class you can have something like
Obviously those aren't the only two options, but they are the first two ways that come to mind. Personally, I think something like #2 is an easy way to work. Sorry, but I'm not going to be able to really devote much time to this issue. I still think that you are going to want to think about having a User of the system, and a Database object for controlling the saving/retrieving of data. What I would recommend is thinking very specifically about how you want to interact with the different parts of the program, and decide how to organize things depending on what you think is a convenient and easy-to-understand way of working with the different entities in the program. |
Thank you @garroadran, I appreciate your input, and both ideas look interesting. I understand that you don't have time to help, but if you got a moment, I just have one question about your second code example. @etiontdn I will be looking more into SQLite (and maybe try to see if I can find some code examples to learn from) so I can better help find the best solutions for us. I am sorry it will take a while before I can give some useful feedback :) |
I have not been active for some time, i don't understood what changes to do from the latest discussion but i will start making the other changes. |
Hey etion, I have not been very active either, my apologies. What time zone
are you on? I was thinking it might be easier for us to Skype to talk about
how to handle the database than to message back an forward. I have looked
into databases, and think I have a suggestion about how we could do it, but
I would like to hear your thoughts.
If skyping doesn't work, we can just keep messaging, but let me know. I am
on the Westcoast of America (GMT-7)
…On Thu, Jul 5, 2018, 15:35 etiontdn ***@***.***> wrote:
I have not been active for some time, i don't understood what changes to
do from the latest discussion but i will start making the other changes.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#92 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AfZFL_cPlOW3g57cpzMaUF-dHteI85eXks5uDpSmgaJpZM4USYWG>
.
|
What issue are you solving? (Give #issuenumber)
#31 and #36
How do you solve it? (please write this so a human can understand it - bulletpoints are okay)
If there is something specific in your solution, that you would like the reviewer to give feedback on, tell us here:
If this is your first pull request to the prog-o-meter project, we would really appreciate it if you would fill out this Google form.
This lets us know more about our contributors, and what we can do to make it easier and nicer to contribute to the prog-o-meter project.
Please submit your answer here and put an 'x' in the box below.