Executing an external python file with certain arguments or parameters

I am writing a PIN code system whereby a particular PIN is assigned to a solenoid lock and a series of actions should follow any correct PIN entry.

There are three files:

File1: stores the PIN numbers only (pin.py). For example:

locker_one_PIN = "2931"

File2: This file has a function that takes user PIN input and checks it against the existing PINs. When a correct PIN is entered, it triggers one of the if statements within File2 for the GUI, printing and solenoid control.

Along with the File2 “if” statements being triggered, I would like to run File3, from File2 with certain parameters (triggering the the relevant option to reset the PIN that was entered).

While I have tried many options including sys.arg (and failed), I am now trying to use “param” as was suggested to me and it seems I still don’t understand it.

Example from a particular File2 “if” statement, I am declaring the following

param = "pin_1_reset"

And then trying to use subprocess from the same “if” statement with the desired option:

subprocess.Popen(['python', 'File3.py', param]) 

File3 : This resets the PIN numbers upon a correct PIN being entered in File2. The reset function is as follows

file_path = path/to/the/pin.py
rand_pin = random.randint(1111, 9999)

def replacepin (file_path, search_text, rand_pin):

    with fileinput.input(file_path, inplace=True) as file:
        for line in file:
            new_line = line.replace(search_text, str(rand_pin))
            print(new_line, end="")
            
pin_1_reset =rand_pin = random.randint(1111, 9999)
replacepin (file_path, locker_one_PIN, str(rand_pin))


pin_2_reset =rand_pin = random.randint(1111, 9999)
replacepin (file_path, locker_two_PIN, str(rand_pin))
            

I realise I likely have failed spectacularly to understand how this should work but it is working, however it is resetting all three PINs at once, when I only want one at a time.

I presume I can’t create “if” statements in File3 because I am simply running the file with a certain parameter (or trying).

I know there are other ways to do this and I am looking for the simplest option. As mentioned, I tried sys.arg but also failed getting all sorts of list, tuple, and range errors.

I would be happy with whatever might work and would like to understand how it is working.

Hello,

what appears to be missing from your script is a conditional statement and a break keyword statement. In your function for loop, you keep reading line after line and replacing the search_text with str(rand_pin). Add some code that reads each line, and if and only if the search_text is equal to the pin that you are searching for (don’t do it for all instances), then replace it with the str(rand_pin) value. If found, after replacing the pin number, then execute a break keyword statement to immediately exit the function. No need to continue reading additional lines after it has found the pin number that it was looking for. Make sense?

There is something that I overlooked. If you have your pin numbers saved in a .py, why are you opening a file as if in text mode as you are currently doing with the with context manager? You import .py files at the top of your files as shown in the example below.

For the pin.py file, store your pin numbers in a dictionary as it makes it easy to iterate through the values as well as to reference them via a key such that they have a key - value pair.

For your pins.py, create it like this (as an example):

# Store pin numbers in a dictionary (access them via a key)
pin_numbers = {'locker_one_PIN': 12536,
               'locker_two_PIN': 85742,
               'locker_three_PIN': 63952,
               'locker_four_PIN': 35274,
               'locker_five_PIN': 14289}

# Needed so that the changes can be modified externally via another file
def change_pin(key, value):

    pin_numbers[key] = value

    # for testing purposes only to verify changes; can remove in final code
    for key in pin_numbers:
        print(key, pin_numbers[key])

For your file3, you may use something like this (as an example) to change the pin number:

import random
import pins


test_pin = 35274  # Pin to be replaced from the file for testing

replacement_pin = random.randint(11111, 99999)  # New pin to replace old one

def replace_pin(replace_pin, rand_pin):

    for pin_nums in pins.pin_numbers.keys():

        if pins.pin_numbers[pin_nums] == replace_pin:

            pins.change_pin(pin_nums, rand_pin)


# call function to replace pin number with new one
replace_pin(test_pin, replacement_pin)

Test this script out and see if it applies to your application.

Hello,

Thanks indeed for your effort here. I am sure this code is far better and more efficient than mine and perhaps a good thing to implement when I get better at this. Right now though I know what my code is doing so far but it would take me a bit to understand what yours is, even if I could implement it. I tried, but would have to make changes to the files because things that were there, are no longer.

For example, in my File2, the function that checks the entered PINs against the existing ones, imports the PIN numbers from File1:

from pin import locker_one_PIN, locker_two_PIN, locker_three_PIN

Now that this isn’t there in the FIle1, I had to try change my “if” statements in File2 and I could not figure out how to differentiate the locker_one_PIN, locker_two_PIN, locker_three_PIN from each other for each “if” statement.

Leaving the syntax as

if  pin == locker_one_PIN:

doesn’t work anymore and there is a knock-on effect for other parts of the code.

I also don’t understand how I am meant to run File3 to differentiate for each PIN. Maybe it would come to me later but trying to implement a change like this affects the rest of the code and would slow me down even more due to my limited knowledge.

Someone who actually knows what they are doing could implement your code in a snap I am sure. I would surely like to build better code later on but for now, familiar seems the best course of action.

My code was working well but only I don’t know how to execute File3 so that it only runs one of the options rather than running all of them and resetting all pin numbers.

Watching File1 in VS Code and running File3, I see them changing without issue only that all of them are changing, rather than just one. Maybe your code was the fix for this but I could not be sure as it seems beyond my knowledge.

I know it should be possible say running File3 with arguments which I don’t understand how to implement this (and tried for hours, days already) but got all sorts of errors. This is why I tried using

param = "pin_1_reset"

and

subprocess.Popen(['python', 'File3.py', param]) 

but I got this wrong also.

By importing the file pins.py by way of this command: import pins, you get access to all of its objects (variable names, functions, etc.). To get access to any object within the pins.py file, you would just need to qualify it (i.e., prefix any object) with the file name and using dot notation. For example, if you had this variable assignment: var1 = 30 inside the pins.py file that you imported, to get its value, you would use pins.var1.

If you are not already familiar with dictionaries, I would advise you to do so as they are very useful. Each item in a dictionary is stored as a key-value pair inside curly brackets. Each key-value pair is separated by a colon and each subsequent key-value pair is separated by a comma. The following example demonstrates a dictionary storing four items. You can access each item by including the dictionary name and passing in the key inside the brackets. Both the key and the value can be a string, and an integer. The value may also be more complex objects including function names, variables, lists, nested dictionaries, etc.. By using dictionaries, for some particular applications, there may be no need for if / else conditional selection statements since the selection is performed by way of the key inside the brackets (and may very well simplify your code by making it less verbose).

In the following example, we wish to access the second item for printing. To access this value, we provide the dictionary name along with the corresponding key enclosed in brackets. In this case, it is the number 2.

items = {1: 'one', 2: 'two', 3: 'three', 4: 'four'} # dictionary with four items
print(item[2])  # prints the value 'two'

Referring back to the function from my previous post, this line:

for pin_nums in pins.pin_numbers.keys():

we iterate through every key value in the dictionary. Note that we make use of dot notation. We first use the name of the imported file (pins) along with the dot, then the name of the dictionary (we want access to the dictionary object). Finally, we use the built-in keyword keys() to call the function that allows us access to all of the dictionary’s keys (the names of the pin numbers, not their values - we can access the values via the keys).

Next, this using this line, we check if any value in the dictionary matches the pin number passed in:

if pins.pin_numbers[pin_nums] == replace_pin:

If there is a match (statement is True), then the following indented statement is executed - we call the function located in the pins file to change the value.

There is no need to use the following line; get rid of it (this is more of an advanced feature and besides that, it has no use for this particular application as you are not running a process - you’d be making things waaaayyy more complicated than they need to be):

subprocess.Popen(['python', 'File3.py', param])