1

Hi everyone this is my first time here, and I am a beginner in Python. I am in the middle of writing a program that returns a txt document containing information about a stock (Watchlist Info.txt), based on the input of another txt document containing the company names (Watchlist).

To achieve this, I have written 3 functions, of which 2 functions reuters_ticker() and stock_price() are completed as shown below:

def reuters_ticker(desired_search):
        #from company name execute google search for and return reuters stock ticker

    try:
        from googlesearch import search
    except ImportError:
        print('No module named google found')

    query = desired_search + ' reuters'
    for j in search(query, tld="com.sg", num=1, stop=1, pause=2): 
        result = j
    ticker = re.search(r'\w+\.\w+$', result)
    return ticker.group() 

Stock Price:

def stock_price(company, doc=None):
    ticker = reuters_ticker(company)
    request = 'https://www.reuters.com/companies/' + ticker
    raw_main = pd.read_html(request)

    data1 = raw_main[0]
    data1.set_index(0, inplace=True)
    data1 = data1.transpose()

    data2 = raw_main[1]
    data2.set_index(0, inplace=True)
    data2 = data2.transpose()

    stock_info = pd.concat([data1,data2], axis=1)

    if doc == None:
        print(company + '\n')
        print('Previous Close: ' + str(stock_info['Previous Close'][1]))
        print('Forward PE: ' + str(stock_info['Forward P/E'][1]))
        print('Div Yield(%): ' + str(stock_info['Dividend (Yield %)'][1]))

    else:
        from datetime import date
        with open(doc, 'a') as output:
            output.write(date.today().strftime('%d/%m/%y') + '\t' + str(stock_info['Previous Close'][1]) + '\t' + str(stock_info['Forward P/E'][1]) + '\t' + '\t' + str(stock_info['Dividend (Yield %)'][1]) + '\n') 
        output.close()

The 3rd function, watchlist_report(), is where I am getting problems with writing the information in the format as desired.

def watchlist_report(watchlist):
    with open(watchlist, 'r') as companies, open('Watchlist Info.txt', 'a') as output:
        searches = companies.read()
        x = searches.split('\n')
        for i in x:
            output.write(i + ':\n')
            stock_price(i, doc='Watchlist Info.txt')
            output.write('\n')

When I run watchlist_report('Watchlist.txt'), where Watchlist.txt contains 'Apple' and 'Facebook' each on new lines, my output is this:

26/04/20    275.03  22.26       1.12

26/04/20    185.13  24.72       --

Apple:

Facebook:

Instead of what I want and would expect based on the code I have written in watchlist_report():


Apple:

26/04/20    275.03  22.26       1.12

Facebook:

26/04/20    185.13  24.72       --

Therefore, my questions are:

1) Why is my output formatted this way?

2) Which part of my code do I have to change to make the written output in my desired format?

Any other suggestions about how I can clean my code and any libraries I can use to make my code nicer are also appreciated!

Ganesh Satpute
  • 3,664
  • 6
  • 41
  • 78

1 Answers1

3

You handle two different file-handles - the file-handle inside your watchlist_report gets closed earlier so its being written first, before the outer functions file-handle gets closed, flushed and written.

Instead of creating a new open(..) in your function, pass the current file handle:

def watchlist_report(watchlist):
    with open(watchlist, 'r') as companies, open('Watchlist Info.txt', 'a') as output:
        searches = companies.read()
        x = searches.split('\n')
        for i in x:
            output.write(i + ':\n')
            stock_price(i, doc = output)  # pass the file handle
            output.write('\n')

Inside def stock_price(company, doc=None): use the provided filehandle:

def stock_price(company, output = None): # changed name here

    # [snip] - removed unrelated code for this answer for brevity sake

    if output is None:  # check for None using IS
        print( ... ) # print whatever you like here 
    else:
        from datetime import date 
        output.write( .... )  # write whatever you want it to write
        # output.close() # do not close, the outer function does this

Do not close the file handle in the inner function, the context handling with(..) of the outer function does that for you.


The main takeaway for file handling is that things you write(..) to your file are not neccessarily placed there immediately. The filehandler chooses when to actually persist data to your disk, the latests it does that is when it goes out of scope (of the context handler) or when its internal buffer reaches some threshold so it "thinks" it is now prudent to alter to data on your disc. See How often does python flush to a file? for more infos.

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
  • I see thank you for the answer! So to confirm my understanding, based on the previous wrongly formatted code I have written, watchlist_report() opens Watchlist Info.txt, but only writes the text when it is closed, whereas the inner function of stock_price() which also opens Watchlist Info.txt is closed immediately after executing, results in the writing of stock_price() first? –  Apr 26 '20 at 10:54
  • @ryan using a context handlign with `with open("bla.txt","a") as f: ...` will close the file as soon as you leave the indentation the context hander `with` creates. the `output.close()` you use in addition is superflous. so yes - the inner part opens, writes and closes a file, then returns to the outer and that gets closed (and written) at that time. hence the reversal of order. – Patrick Artner Apr 26 '20 at 10:56