Closed khanna7 closed 2 years ago
Typically I don't use the command line argument parsing when running unit tests. Instead I'll have the test params file hardcoded in the unit test itself. Pretty much just calling this in the unit test rather than your load_params
:
params_list = parameters.init_params(args.parameters_file, args.parameters)
substituting args.parameters_file
with the test params file, and args.parameters
with an empty string.
Thanks @ncollier! I modified the test code as below:
from statistics import mean as mean
import unittest
import numpy as np
import pandas as pd
import sys
import os
from repast4py import parameters
from pycadre import cadre_model
import pycadre.load_params
class TestPerson(unittest.TestCase):
params_list = parameters.init_params('/Users/adityakhanna/Google Drive/My Drive/code/cadre/python/myparams/model_params.yaml', '')
TEST_N = 1000
TEST_NSTEPS = 250
def test_age_assignment(self):
ages = []
MIN_AGE = TestPerson.params_list['MIN_AGE']
MAX_AGE = TestPerson.params_list['MAX_AGE']
mean_age_target = (MIN_AGE+MAX_AGE)/2
#print("Min age:", TestPerson.MIN_AGE)
model = cadre_model.Model(n=TestPerson.TEST_N, verbose=False, comm=None)
model.run(MAXTIME=0)
for person in model.my_persons:
ages.append(person.age)
for age in ages:
self.assertTrue(age >= MIN_AGE)
self.assertTrue(age <= MAX_AGE)
if TestPerson.TEST_N >= 1000:
# only try this if n is sufficiently large, or test fails
self.assertAlmostEqual(np.mean(ages), mean_age_target, delta=1)
When I do
python -m unittest mytests.test_person.TestPerson.test_age_assignment
I now get:
adityakhanna@adityakhanna python % python -m unittest mytests.test_person.TestPerson.test_age_assignment
E
======================================================================
ERROR: test_age_assignment (mytests.test_person.TestPerson)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Volumes/GoogleDrive/My Drive/code/cadre/python/mytests/test_person.py", line 27, in test_age_assignment
model = cadre_model.Model(n=TestPerson.TEST_N, verbose=False, comm=None)
File "/Volumes/GoogleDrive/My Drive/code/cadre/python/pycadre/cadre_model.py", line 18, in __init__
person = cadre_person.Person(name = i)
File "/Volumes/GoogleDrive/My Drive/code/cadre/python/pycadre/cadre_person.py", line 12, in __init__
MIN_AGE = load_params.params_list['MIN_AGE']
TypeError: 'NoneType' object is not subscriptable
----------------------------------------------------------------------
Ran 1 test in 0.009s
FAILED (errors=1)
Is there something wrong in how I am running the model to test data generated from it? Or is it something else?
I don't think you need to reference load_params
anymore. After you've called repast4py's init_params, you can use repast4py.parameters.params
to get a reference to the parameters dictionary.
I see. So my references to load_params
in the model
class should be updated with references to repast4py.parameters.params
?
Yeah, you could just shorten it to parameters
with a from repast4py import parameters
, and then you can use parameters
in the modules with that import.
Ah, sorry, I am not able to get this to work. Perhaps because I have a separate module in which the parameters are parsed: https://github.com/khanna7/cadre/blob/master/python/pycadre/load_params.py, which I read into main like so:
...
import pycadre.load_params
...
def main():
size = MPI.COMM_WORLD.Get_size()
rank = MPI.COMM_WORLD.Get_rank()
params_list = pycadre.load_params.load_params()
STOP_AT = params_list['STOP_AT']
N = params_list['N_AGENTS']
model = cadre_model.Model(n=N, verbose=True, comm=MPI.COMM_WORLD)
model.run(MAXTIME=STOP_AT, params=params_list)
if __name__ == "__main__":
main()
The model runs without a problem, but when I run the tests file, where the test data are explicitly read in, with
python -m unittest mytests.test_person.TestPerson.test_age_assignment
I get:
adityakhanna@adityakhanna python % python -m unittest mytests.test_person.TestPerson.test_age_assignment
E
======================================================================
ERROR: test_age_assignment (mytests.test_person.TestPerson)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Volumes/GoogleDrive/My Drive/code/cadre/python/mytests/test_person.py", line 29, in test_age_assignment
model = cadre_model.Model(n=TestPerson.TEST_N, verbose=False, comm=None)
File "/Volumes/GoogleDrive/My Drive/code/cadre/python/pycadre/cadre_model.py", line 21, in __init__
person = cadre_person.Person(name = i)
File "/Volumes/GoogleDrive/My Drive/code/cadre/python/pycadre/cadre_person.py", line 12, in __init__
MIN_AGE = load_params.params_list['MIN_AGE']
TypeError: 'NoneType' object is not subscriptable
----------------------------------------------------------------------
Ran 1 test in 0.010s
FAILED (errors=1)
If you look in the stack trace:
File "/Volumes/GoogleDrive/My Drive/code/cadre/python/pycadre/cadre_person.py", line 12, in __init__
MIN_AGE = load_params.params_list['MIN_AGE']
TypeError: 'NoneType' object is not subscriptable
You'll see that load_params.params_list['MIN_AGE']
is throwing a TypeError: 'NoneType' object is not subscriptable
. Subscriptable means that you can use square brackets on it -- so, it's indicating that load_params.params_list
is None. And that makes sense because in the test you never call load_params
so params_list
never gets set.
All that said, I think you can remove load_params and replace it with repast4py.parameters.init_parameters
.
Thanks @ncollier and @dsheeler! This seems resolved.
https://github.com/khanna7/cadre/blob/59de95877aa12dd6afdc706b30509f6ac9ea4710/python/mytests/test_person.py#L1
How should I run the tests now that the parameters are being parsed through repast4py? Previously I just did:
If I try the same command now, I get the following errors: