4

I'm trying to access variables that are contained in functions after an operation is performed in another Python script, but I don't want to run through the operations of the function, I just need access to the returned value of the variables gh and user.

I've tried different ways to do this such as setting the initial value of the variable to None in the main script, but the problem I run into is when I do an import of script1 into script2, it runs through the script and resets the variable in question to None again. In addition, I've tried to wrap them in a class with no luck.

Also, I've tried using if __name__ = '__main__': to run the functions, but I can't seem to figure out how to get the values out of the functions into script2 to use as global variables.

I've seen some answers here that may work such as returning the values of the function to another function for use??, but I I can't quite nail the syntax as the function doesn't seem to hold the value of the variable.

If I have asked this question incorrectly, please let me know how to improve it as I'm trying to ask "good" questions so I don't get banned. I'm still learning and I do ask a lot of questions here, but I've learned a lot by doing so.

script1.py:

#! /usr/bin/python

import github3
from github3 import login, GitHub, authorize
from getpass import getuser, getpass
import requests

import configparser

def getCreds():
    try:

        user = input('GitHub username: ')
    except KeyboardInterrupt:
        user = getuser()

    password = getpass('GitHub token for {0}: '.format(user))

    gh = login(user, password)


if __name__ == '__main__':

    getCreds()
    exec(open("next_file.py").read())

script2.py

import os
import github3
from github3 import login, GitHub, authorize
from getpass import getuser, getpass
import requests
import csv
import configparser
import sys
import script1
import codecs

gh = script1.gh
user = script1.user

def one_commit_one_file_change_pr():

    #open csv file and create header rows
    with open('c:\\commit_filechange.csv', 'w+') as f:
        csv_writer = csv.writer(f)
        csv_writer.writerow(['Login', 'Title', 'Commits', 'Changed Files','Deletions', 'Additions'])

    for pr in result:
        data = pr.as_dict()
        changes = (gh.repository(user, repo).pull_request(data['number'])).as_dict()    

        if changes['commits'] == 1 and changes['changed_files'] == 1:
        #keep print to console statement for testing purposes
        #print changes['user']['login']


            with open('c:\\commit_filechange.csv', 'a+') as f:
                csv_writer = csv.writer(f)

                csv_writer.writerow([changes['user']['login'], changes['title'], changes['commits'], changes['changed_files']])

one_commit_one_file_change_pr()
wgwz
  • 2,642
  • 2
  • 23
  • 35
DBS
  • 1,107
  • 1
  • 12
  • 24

2 Answers2

2

Here is a solution which I believe is common practice. Set up a file called global_var.py (or something like it) and store global variables there. (See this post by @systemizer) Here is a simplified version of what will work with your code:

script1.py

if __name__=='__main__':
    user = raw_input('GitHub username: ')
    with open('global_var.py','w') as f:
        f.write("user = '%s'" % user)
password = 'blah'
gh = '<login(user, password)>'

script2.py

from script1 import gh
from global_var import user
print user
print gh
Community
  • 1
  • 1
wgwz
  • 2,642
  • 2
  • 23
  • 35
  • @skywalker...thanks for the reply, but the problem I run into (as I've tried this) is it runs through the prompt for user input for username and password again, whereas I just need access to the value returned to the variables without walking through the rest of the function again. – DBS Oct 11 '15 at 23:12
  • Well just declare the variables at the bottom of script1 then, and not in the if name = main section. See edit – wgwz Oct 11 '15 at 23:18
  • @skywalker...I made the edit your suggested, but I get the same result. When the import is performed from script1 in script2, it runs through the code, and finds `gh,user = getCreds()` and then runs the function in its totality, including prompting for username and password, whereas all I want are the values returned to `gh` and `user`. I hope that makes sense. – DBS Oct 11 '15 at 23:35
  • I see the problem now, depending on your application maybe you are better off setting that as an environment variable. I'm not sure how to solve this problem though. What is your purpose? There may be a better way to get a user name rather than using `input()`. – wgwz Oct 11 '15 at 23:48
  • I'm trying to get the username and pswd to use for authentication to github using the github3 library. I also use the username to pass to the repository object of the github3 library. I found this post, http://stackoverflow.com/questions/14051916/python-how-to-make-a-local-variable-inside-a-function-global that discusses returning variable values to other functions. This looks like it would work, but I can't get the syntax right. I get `TypeError: other_function() missing 1 required positional argument: 'parameter'` – DBS Oct 12 '15 at 00:16
  • I tried adding the code block I used in the link (to return a variable from one function to another), but the formatting looks horrible in the comment section as I can't find a way to include a code block like you can when asking a question. – DBS Oct 12 '15 at 00:18
  • Is it for a web application? Why do you need to use `input`? In general I think it is considered better practice to avoid using `raw_input`'s in programs. If it is a web-app a form is the better practice. If it is a command-line application you are better off not asking but passing the user-name into an authentication function. Just my two cents – wgwz Oct 12 '15 at 00:19
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/91991/discussion-between-skywalker-and-dbs). – wgwz Oct 12 '15 at 00:26
  • No, it's not a web application. I need input because from the command line, I would like the user to enter their user name and pswd and use that for authentication as well as building the repo structure (username\repo-name.) – DBS Oct 12 '15 at 00:27
  • Correct me if I understand it wrong , you want to have the getCredential (getting raw input of user/pwd combo) operation performed only once and reuse the credential later at some other script , right ? – Sanju Oct 12 '15 at 02:53
1

This answer is purely based on my assumption that you want get the user credentials only once and want to re-use it "n" number of times later in other scripts. Here is how I would do it ,


Update1

Your problem also has to do with how you want to organize and run your scripts, the below examples work if you have bundled your scripts in to python package and run them

For. eg

enter image description here

but if you are planning to run individual scripts separately , then you have no other option but to invoke the login prompt for each script unless you plan to completely remove asking for user credentials and use the pre-configured data from a file.

script1

from github3 import login
USER_CREDS = None   # Store raw input credentials here ,not recomended
GIT_USERS = {}     # global dict to store multiple users with username as key

def getCredentials():
    global USER_CREDS
    if USER_CREDS:
        print "returning user credentials"
        return USER_CREDS
    print "gettting user credentials"
    user = raw_input("Enter Username")
    pwd = raw_input("Enter Password")

    USER_CREDS = (user, pwd)

    return USER_CREDS


def do_login():
    global GIT_USERS
    user, pwd = getCredentials()
    if not GIT_USERS.get(user, None):
        gh = login(user, password=pwd)
        GIT_USERS[user] = gh
    return GIT_USERS[user]

in other scripts

from script1 import do_login

# the first time do_login() is called it asks for user credentials
print do_login()
# the next times it just returns the previously collected one
print do_login()

Example 2

script 3

from script1 import do_login
creds = do_login()  

script 4

from script3 import creds
from script1 import do_login
print creds
print do_login() # No input prompt would be provided
Sanju
  • 1,974
  • 1
  • 18
  • 33
  • @Sanju...your are correct, but I would like to run `do_login` once in script1 to gather the creds and then the value held in `gh` and `user` to other scripts without getting prompted for them again. If I run `do_login()` in other scripts, I get the prompt located in `getCredentials()`. I believe the best way to do this is gather the creds and store them in an encrypted file of some nature and read them out from there. The token is the security sensitive piece. – DBS Oct 12 '15 at 05:09
  • 1
    I now see, how you might be using it , if you are running the scripts seperatly , yes the prompt would be shown every time. I have added another example of possible usage , as in script3 , you can invoke the do_login () once and import the creds in all other places where you require login credentials, in this way , you can actually avoid for multiple prompts . but the better way would be the credentials securely stored in a file and access it . – Sanju Oct 12 '15 at 05:36
  • @Sanju...I saw the update with bundling the scripts in a python package. The scripts will not be run individually. The idea to is have the main script loop through and call all the validation scripts located in a separate directory. `exec(open("next_file.py").read())` will turn into a loop to read through each file in the separate directory. I haven't used python packages so I will need to research how to use them and then try your suggestion. – DBS Oct 12 '15 at 19:35