Forum Archive

Extracting the Date from the UI date and time spinner

KevinKarney

I am new to Python but have progressed as far as getting a complex algorithm coded, but I am now struggling with the UI interface. I have a button which when pressed should read the date from the date spinner.
The code for the button is...
def GetDate(sender):
thisdate = sender.superview['DatePicker']

But I cannot see how to get year, month, day from this date
H E L P

Best regards and thanks in advance
Kevin

dvader9

Kevin,

I have not used the date picker object yet, but based on the help files - for DatePicker objects and for datetime.datetime class -, I'm guessing the following syntax for your button action could be used:

def GetDate(sender):
  date = sender.superview['DatePicker1']
  # assuming that is the name of your DatePicker object
  # this returns a datetime.datetime object, see module datetime
  year = date.year
  month = date.month
  # etc... For day, hour, minute and so forth.

Dave

dvader9

Apologies for the lack of clarity in the code. This is my first time posting a code snippet in this forum, and I don't know why some of the carriage returns did not go through.

ccc

To post code to this forum, see: http://omz-forums.appspot.com/pythonista/post/5493027686580224

ccc
import ui

my_date = None 

def date_picker_action(sender):
    my_date = sender.date
    print(my_date)

view = ui.View()
date_picker = ui.DatePicker()
date_picker.action = date_picker_action
view.add_subview(date_picker)
view.present('sheet')
dvader9

@ccc thanks for the link to posting code on the forum. I've edited my response above, though the code you posted conveys the idea in a more complete example.

KevinKarney

Brilliant.
Thanks dvader9 and @ccc. I knew it would be easy!
Best wishes, Kevin

abushama

i need to extract and append in csv file???
MyScript

def calndr(sender):
  date = sender.superview['calender']
  # assuming that is the name of your DatePicker object
  # this returns a datetime.datetime object, see module datetime
  year = date.year
  month = date.month

  with open('newfile.csv',"a") as f:
            newfileWriter=csv.writer(f)
            newfileWriter.writerow([calndr()])
            tarDate=calndr(targetDate['calender'])
            f.close()
Phuket2

@abushama , I have never used the csv lib before. But I think the below should work. I basically copied it from the examples in the csv documentation.
There are other types of writers, but i came across the dict writer, which seems it would be a good choice anyway. link to csv docs

def calndr(sender):
    date = sender.superview['calender']
    # assuming that is the name of your DatePicker object
    # this returns a datetime.datetime object, see module datetime
    year = date.year
    month = date.month

    with open('newfile.csv', 'a') as csvfile:
        fieldnames = ['Year', 'Month']
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
        writer.writerow({'Year': year, 'Month': month})
ccc

@abushama Do you want to add new events to the end of the file or do you merely want to write over the existing file?

If the former then you will need to seek to the end of the file before writing: append_file.seek(0, 2)

#!/usr/bin/env python3

from string import ascii_lowercase

filename = 'file_seek.txt'

# write a letter at a time to the END of the file
for letter in ascii_lowercase:
    with open(filename, 'a') as append_file:
        append_file.seek(0, 2)
        append_file.write(letter)

with open(filename) as in_file:
    print(in_file.read())

When you do with open(filename) as fp: you do not need to .close() the file. That will be done automatically for you when the with context manager ends.

JonB

@abushama You seem to be calling calndr() from within calndr(). calndr() does not return a date.
Reread each line in your code and remind yourself what you are trying to achieve with each line...

abushama

@Phuket2
i think u got my point
but when i ran the code
this kide or error pop up

AttributeError: '_ui.DatePicker' object has no attribute 'year'
which is:-
year=date.year

abushama

@JonB
i did but am still straggling
how to extract time from calnder celnder and write it in csv file
that all what am trying😔

Phuket2

@abushama. One proble was you were setting the date to be the ui.DatePicker, not the attr date. You can see I changed it in your function (I missed that originally, I didn't run the code because you didn't post it all, so it was easy for me to miss that). Look, I just got it working in the way i thought you had tried to get it working.
Your calndr function looks likes it would make more sense for you to put it into the class as a method.
I am often torn about how to help. If I make too many changes it can be frustrating to the person and confuse them more. @JonB point about going over your code is very valid. The way you where calling your function again inside trying to write to the csv file was way off. So I would suggest to take what i have done and try to move your calndr function into the class. Then really look closely about what's happening when you are writing out your csv file.
You are not that far away. Just take your time and really look through it. Still here if you need more help.
EDIT please see the notes I added to the bottom of the post.

import ui
import csv

def calndr(sender):
    date = sender.superview['calender'].date
    # assuming that is the name of your DatePicker object
    # this returns a datetime.datetime object, see module datetime

    year = date.year
    month = date.month

    with open('newfile.csv', 'a') as csvfile:
        fieldnames = ['Year', 'Month']
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
        writer.writerow({'Year': year, 'Month': month})

class MyClass(ui.View):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.make_view()

    def make_view(self):
        dtp = ui.DatePicker(name='calender')

        btn = ui.Button(width=80,
                        height=32,
                        border_width=.5,
                        bg_color='white',
                        corner_radius=.5,
                        action=calndr)
        btn.title='Save'
        # just position the button
        btn.center = self.center
        btn.y = self.height - (btn.height * 2)

        # add the date picker & btn to the view
        self.add_subview(dtp)
        self.add_subview(btn)

if __name__ == '__main__':
    f = (0, 0, 300, 400)
    v = MyClass(frame = f)
    v.present(style='sheet', animated=False)

Btw, the csv writer has other methods, for example to write out the headers to you file. Of course you would only want to write the headers once. Oh, I should have mentioned, you should not really move your calndr function into the class the way it is. It really should be a method that just is passed you year and month and writes out the csv file. You really don't want the other objects around. If you make the method just to handle the csv file, you could for example reuse that code in other objects.

abushama

@Phuket2
thank u very much
i got this one too i would like to share
and advice my
i kw this not like ur prof one u did but this what i came with

import ui
import datetime
import csv


def calc(sender):
        v = sender.superview
        GontarHighPrice = v['txt1'].text
        GontarLowPrice = v['txt2'].text
        DollerRate =v ['txt3'].text

        Avg = (float(GontarHighPrice)+float(GontarLowPrice))/2
        TonInPounds=22.25*Avg
        SPound="{0:,.2f}".format(TonInPounds)
        v['txt4'].text=str(SPound)

        TonInDollars=TonInPounds/float(DollerRate)
        v['txt5'].text=str("{0:,.2f}".format(TonInDollars))
        #TID=v['txt5'].text

        ProtSudan=TonInDollars+150
        v['txt6'].text="{0:,.2f}".format(ProtSudan)
        #FOB=v['txt6'].text

        C_F= ProtSudan+50
        v['txt7'].text="{0:,.2f}".format(C_F)
        #CF=v['txt7'].text

        Amman= C_F+120
        v['txt8'].text="{0:,.2f}".format(Amman)
        Amm=v['txt8'].text

        with open('newfile1.csv', 'a') as csvfile1:
                    fieldnames = ['Amm']
                    writer = csv.DictWriter(csvfile1, fieldnames=fieldnames)
                    writer.writerow({'Amm': Amm})
                    csvfile1.close()

def calndr(sender):
        Mydate=sender.date
        day = Mydate.day
        month = Mydate.month
        year = Mydate.year

        with open('newfile1.csv', 'a') as csvfile1:
                fieldnames = ['Day', 'Month','Year']
                writer = csv.DictWriter(csvfile1, fieldnames=fieldnames)
                writer.writerow({'Day': day, 'Month': month,'Year': year})
                csvfile1.close()

        v = ui.load_view()
        v.present('sheet')
abushama

@Phuket2
As u notice that i got 2 open files to append
the data of
Amm and the date which i got from calender celnder

all i need is to make it one open file
which i can append in one csv file to covert to excel sheet

?????

Phuket2

@abushama, I am not really sure what your final result is suppose to look like. But if you look below there is a function that will take a dict and write it out to the csv file. So that function is only concerned with your csv file, not how to get the data. If you call the function over and over it will be ok, because we only write the headers out once.

import csv
import os

def write_to_csv(filename, data_dict):

    fexists = os.path.exists(filename) # We set a var to see if the file exists 

    fieldnames = list(my_data_dict.keys()) # get a list of the keys to use as the header
    with open(filename, 'a') as csvfile:
            #fieldnames = ['Day', 'Month','Year']
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

            # only write the header one time to the file
            if not fexists:
                writer.writeheader()

            writer.writerow(data_dict)
            #svfile1.close()  # you dont need this.  Look up Context Managers

if __name__ == '__main__':
    filename = 'my_csv.csv'

    # you would collect your data and put it in a dict.
    my_data_dict = dict(
        Day = 1,
        Month = 12,
        Year = 2017,
        Amm = 2.5   
    )

    write_to_csv(filename , my_data_dict)

    # just print the file to the console, make sure its what we wanted
    with open(filename) as f:
        for line in f:
            print(line, end='') 
abushama

@Phuket2
am trying to post a screenshot of my UI but i dont know how??
may u send my ur email plz?

ccc

Posting images to this forum works like this: https://guides.github.com/features/mastering-markdown/#examples

Phuket2

@abushama, I had already done this before I seen @ccc post. But this also should help

ccc

Perhaps the missing magic in this thread is seek() which lets you open a file in 'a' mode and then seek to the beginning of that file (append_file.seek(0, 0)) so that you can read() its contents and then seek to the end of the file (append_file.seek(0, 2)) and then write() new content to the end of the file.

Phuket2

@ccc, I am a little baffled. I was going to suggest he could call the function twice with different files names then have another small function to combine the files or create a 3rd file. Whatever is needed.
Maybe should have done this without using csv to help for clarity the fact its only a comma separated file with some headings if required. The csv writer in this case would only help with imbedded quotes in strings etc...In this simple case.
The dict writer is nice though.
We will see what @abushama comes back with.

JonB

It seems to me, he wants a function which gathers the entire UI state, not just the sender, and write that to csv.

i.e there should be a utility function which gets the date, as well as everything else he wants in the file, and writes the csv. Then both callbacks call the exact same function.

Phuket2

@abushama, how are you going? Did you get a solution? I think i read too quickly, I see what @JonB is saying now.
The functions that have been written should show you the way how to achieve what you want. Let us know if you got what you wanted working or not

abushama


this is my UI simple project
i hope this give u a quite view

abushama

@JonB
exatly..i input
the first three cells
GontarHighPrice
GontarLowPrice
and the doller rate
then i tunning the calnder celnder to the certin date and press calculate botton
this action will calculte other cells in the UI and in the same time will save this all this data + the date in one csv


what i got so far in the code above all the data and the date
but not in one order

Phuket2

@abushama , as far as I can see the below should do want you want, if not pretty close to it. I am not saying its the prettiest way to do it. But its very procedural. Hopefully its easy to follow. There are always many solutions to a given problem. I have tried to do it as I imagine you are doing it. I mean by loading the form. I assume in the designer for the button you are setting the action to call.
For the below to work you need to set your calc button's action to calc_button_action and you have to set the my_screen_fn to the name of your view you made in the Designer.

import ui
from os.path import exists 
import csv

_csv_filename = 'myoutput.csv'

def calc_button_action(sender):
    '''
        Here your calc button will call 3 functions.
        1. do_calculations, so you calculate and put the values in your fields
        2. collect_data, will collect all the data from your view and return it as a dict
        3. write_to_csv, you pass your dict you collected the data into and it will be written
        to the csv file.  The file name is at the top of the file.  You could ask for the name
        of the file for example.
    '''

    # v is set to your view, so you can access the other objects on you view now and
    # pass your view to other functions!
    v = sender.superview

    do_calculations(v)
    data_dict = collect_data(v)
    write_to_csv(_csv_filename, data_dict)

def do_calculations(v):
    '''
        in here, just do your calculations and update
        your fields with the calculated data
    '''
    # so to access the date in the ui.DatePicker, lets say its name is cal
    the_date = v['cal'].date

    # you can access all your objects as above.

    v['txt9'].text = str(10 * 2) # whatever you calculate


def collect_data(v):
    '''
        in here you are only intrested in collecting your data from the view
        again, you have the view so you can access your fields.
        I have used a dict here to collect the information.
        I think if you are using py 3.6, your dict will keep its order as you add your items
    '''

    # I have only filled in a few fields here. But you would add everything from your view
    # you wanted written out to the csv.  Add the items in the order you want them written 
    # to the csv file.
    d = dict(
            Year = v['cal'].date.year,
            Month = v['cal'].date.month,
            Day = v['cal'].date.day,
            HighPrice = v['txt9'].text,
            )
    return d

def write_to_csv(filename, data_dict):
    '''
        This function is only concerned with writing your dict to the csv file.  
    '''
    fexists=exists(filename) # We set a var to see if the file exists

    fieldnames = list(data_dict.keys()) # get a list of the keys to use as the header
    with open(filename, 'a') as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
        # only write the header one time to the file
        if not fexists:
            writer.writeheader()

        writer.writerow(data_dict)


if __name__ == '__main__':
    my_screen_fn = 'someview.pyui'
    v = ui.load_view(my_screen_fn)
    v.present(style='sheet', animated=False)
abushama

@Phuket2
thank you very much
frist thing u taught how to
combin funtions in my UI which i do not know before.
2)ur code is so clear to get the idea simply


as u side am not using 3.6 python so the output of dic are not orginize as i put in my code
so any idea..?

Phuket2

@abushama , ok here is a version that is using lists. I thought it should be a simple change to use OrderDict, but I had a problem to get it to work. So i used a list instead :(

import ui
from os.path import exists 
import csv

_csv_filename = 'myoutputV2.csv'

def calc_button_action(sender):
    '''
        Here your calc button will call 3 functions.
        1. do_calculations, so you calculate and put the values in your fields
        2. collect_data, will collect all the data from your view and return it as a list
        3. write_to_csv, you pass your list you collected the data into and it will be written
        to the csv file.  The file name is at the top of the file.  You could ask for the name
        of the file for example.
    '''

    # v is set to your view, so you can access the other objects on you view now and
    # pass your view to other functions!
    v = sender.superview

    do_calculations(v)
    data_list = collect_data(v)
    write_to_csv(_csv_filename, data_list , ['Year', 'Month', 'Day', 'HighPrice'])

def do_calculations(v):
    '''
        in here, just do your calculations and update
        your fields with the calculated data
    '''
    # so to access the date in the ui.DatePicker, lets say its name is cal
    the_date = v['cal'].date

    # you can access all your objects as above.

    v['txt9'].text = str(10 * 2) # whatever you calculate


def collect_data(v):
    '''
        in here you are only intrested in collecting your data from the view
        again, you have the view so you can access your fields.
        Using a list now! not a dict
    '''
    lst = []
    # I have only filled in a few fields here. But you would add everything from your view
    # you wanted written out to the csv.  Add the items in the order you want them written 
    # to the csv file.
    lst.append(v['cal'].date.year)
    lst.append(v['cal'].date.month)
    lst.append(v['cal'].date.day)
    lst.append(v['txt9'].text)

    return lst

def write_to_csv(filename, data_list, field_name_list=None):
    '''
        This function is only concerned with writing your list to the csv file.  
    '''
    fexists=exists(filename) # We set a var to see if the file exists


    with open(filename, 'a') as csvfile:
        csvwriter = csv.writer(csvfile, delimiter=',',
                            quotechar='|', quoting=csv.QUOTE_MINIMAL)

        if not fexists and field_name_list != None:
            csvwriter.writerow(field_name_list)

        csvwriter.writerow(data_list)   

if __name__ == '__main__':
    my_screen_fn = 'someview.pyui'
    v = ui.load_view(my_screen_fn)
    v.present(style='sheet', animated=False)
abushama

@Phuket2
what about the header of the list??
#fieldnames = list(data_dict.keys()) # get a list of the keys to use as the header
as long we use list we skip an important figer whish the header of the cells
my Quation is can we cobine the two methods
(dict )for header and( list )for appending the value?
like dict is outer method and inside this dict sublist to store order data??

abushama

@Phuket2
i tried in both sides lists inside dict & and dicts inside one list
but i got invalid sentax 🤔😒
any idea..

ccc

Can we get a GitHub repo here so that @abushama can post the original code and we can set in pull requests for targeted fixes? EDIT: added fields for readability

from collections import namedtuple

fields = ('year', 'month', 'day', 'text')
note = namedtuple('note', fields)

notes = [note(2017, 8, 11, 'yesterday'),
         note(2017, 8, 12, 'today'),
         note(2017, 8, 13, 'tomorrow')]

fmt = '{:<10} {:<10} {:<10} {}'
print(fmt.format(*fields))
for n in notes:
    print(fmt.format(*n))

"""
year       month      day        text
2017       8          11         yesterday
2017       8          12         today
2017       8          13         tomorrow
"""
Phuket2

@ccc, I made a repo here. I am not sure I did it in a smart way or not. I tried to give it a bit of structure in case have to help someone else, including myself :) in the future.
@ccc, I have looked for this, a permission to let anyone do what they want to the repo without having to invite them. So they can push, pull merge etc...It seems something like that would make sense for a repo like this.
Anyway, any thoughts to make the structure of the repo better would be appreciated. Even if i have to start again, that's ok. I did create the repo in github, web. But i was able to clone it, and push the pyui to it from Pythonista using StaSh. That's a big step for me. I am still not using ssh keys yet. I will get to that next

Side Note to @omz : Is there a thread id that you suppress in the forum's display? This would be handy for something like this when making a repo to work with someone on a forum problem....Just a though (btw, i just mean a single id for a thread, at the first message).

Phuket2

@abushama , I am not sure why you are getting an error. I copied the code straight from the post and pasted it into a new file and it worked. Well, some extra text is copied in that I had to delete, but that should be fairly obvious. But it works under 2.7 and 3.6.
But please when you get invalid syntax, or an error, copy it and paste it into your post. I know some of these things can be confusing when you are first getting started. But it should not take long before you start to get the hang of it. I would hold off on @ccc suggested code for the moment, even though it maybe better. Focus on get the list version going first. Once that's up and running correctly, can upgrade it and more Pythonetic.

@abushama, the latest version of the code (list version as above) and the test pyui file is in a repo here. If you don't know about Github and repos, lets not get into that here on this post. I barely can use them.

But anyway, please look at the list version of the code closely. Make sure you haven't changed it accidentally or copied extra info from the post (look at the very top of you file).
If you still get the error, please copy the error and paste it in a post. If you do get it working, please let us know!

Determined to get you going with this :)

ccc

I would hold off on @ccc suggested code

Always good advise. ;-) I edited my code above to make it easier to understand.

abushama

@Phuket2
it works👍🏽
thank you

abushama

@ccc
thank you
ur code is helpful
and the advice ander process

Phuket2

@abushama here is version using namedtuples as @ccc pointed out. It's worth to look at if you don't know about namedtuples.As @ccc would say, they are your friend :) Don't worry if you have moved on about this topic. It was good for me to do it, I am trying to get my python code to be more compliant and pass the style checks and pyflakes test. So just take a look if you are interested.

abushama

dear fellowz
i am really getting avery good informationz from both of u
and i explore ur pagez u r far step over in this pythonista app which am very lucky that my simple project get ur attention and both of u willing to help me to do it in right way.
as i said before am still KG1 In pythonista😂 so now adays am trying to learn how to store this data that i come up with not in CSV file but in SQLite file so i can manpulate in the future.
and if i face any challngez first thing i will do to knock ur doors both of u asking for ur help😂
so thank u very much once again and best wishz in ur projects