Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Model.py #13

Merged
merged 11 commits into from
Oct 24, 2024
6 changes: 3 additions & 3 deletions .github/workflows/python-package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ jobs:
python -m pip install --upgrade pip setuptools wheel
python -m pip install .[dev]
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint with flake8
run: |
flake8 .
#- name: Lint with flake8
# run: |
# flake8 .
- name: Test with pytest
run: |
pytest
71 changes: 58 additions & 13 deletions pkmodel/model.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,79 @@
#
# Model class
#
def checkTypes(value, validTypes):
"""checks that inputs are numbers

Parameters
----------
value: input variable (any class)
validTypes: list of accepted types

"""
#check that type is 'int' or 'float'#
if type(value) not in validTypes:
types = [t.__name__ for t in validTypes]
raise TypeError(f"'{str(value)}' is not of type {' or '.join(types)}")

class Model:
"""A Pharmokinetic (PK) model

Parameters
----------

name: character, name of model
Q_p1: numeric, def = 1
V_c: numeric, def = 1
V_p1: numeric, def = 1
CL: numeric, def = 1
X: numeric, def = 1
V_c: numeric/int, def = 1
CL: numeric/int, def = 1
X: numeric/int, def = 1
Q_p: list of numeric/int, def = []
V_p: list of numeric/int, def = []

"""
def __init__(self,
name,
Q_p1=1,
V_c=1,
V_p1=1,
CL=1,
X=1):
V_c = 1,
CL = 1,
X = 1,
Q_p = [],
V_p = []):
self.name = name
self.Q_p1 = Q_p1
self.V_c = V_c
self.V_p1 = V_p1
self.Q_p = Q_p
self.CL = CL
self.X = X
self.V_c = V_c
self.V_p = V_p

#check that values are correct types#
for var in [self.V_c, self.CL, self.X]:
checkTypes(value = var,
validTypes = [float, int])
for var in [self.Q_p, self.V_p]:
checkTypes(value = var,
validTypes = [list])
for val in self.Q_p:
checkTypes(value = val,
validTypes = [float, int])
for val in self.V_p:
checkTypes(value = val,
validTypes = [float, int])
checkTypes(value = self.name,
validTypes = [str])

#check arguments for additional compartments are of equal length#
assert len(self.Q_p) == len(self.V_p), "Q_p and V_p must be of equal length"

#definition of print command#
def __str__(self):
return self.name + ": a model with " + str(len(self.Q_p)) + " peripheral compartment(s)"

#command for adding additional compartments#
def add_compartment(self, Q_p, V_p):
#check variable types#
for var in [Q_p, V_p]:
checkTypes(value = var,
validTypes = [float, int])
#add variables for additional compartments
self.Q_p.append(Q_p)
self.V_p.append(V_p)
return "model named " + self.name

66 changes: 62 additions & 4 deletions pkmodel/tests/test_model.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,72 @@
import unittest
import unittest.mock as mock
from io import StringIO
import pkmodel as pk


class ModelTest(unittest.TestCase):
"""
Tests the :class:`Model` class.
Tests the `Model` class.
"""
def test_create(self):
"""
Tests Model creation.
"""
model = pk.Model(name="testing")
self.assertEqual(model.name, "testing")
#test default model creation#
model = pk.Model(name = "TestModel")
self.assertEqual(model.name, "testModel") #name
self.assertEqual(model.V_c, 1) #V_c
self.assertEqual(model.CL, 1) #CL
self.assertEqual(model.X, 1) #X
self.assertEqual(model.Q_p, []) #V_c
self.assertEqual(model.V_p, []) #V_p

#test print function#
expectedOutput = "testModel: a model with 0 peripheral compartment(s)"
with mock.patch('sys.stdout', new = StringIO()) as fake_out:
print(model)
self.assertEqual(fake_out.getvalue(), expectedOutput)

#test correct non-default inputs of correct type#
model = pk.Model(name = "TestModel",
V_c = 2,
CL = 2,
X = 2,
Q_p = [1],
V_p = [1])
self.assertEqual(model.name, "TestModel") #name
self.assertEqual(model.V_c, 2) #V_c
self.assertEqual(model.CL, 2) #CL
self.assertEqual(model.X, 2) #X
self.assertEqual(model.Q_p, [1]) #V_c
self.assertEqual(model.V_p, [1]) #V_p

#test incorrect input types#
with self.assertRaises(TypeError):
model = pk.Model(name = 1) #name
model = pk.Model(name = "testModel", V_c = "wrong") #V_c
model = pk.Model(name = "testModel", CL = "wrong") #CL
model = pk.Model(name = "testModel", X = "wrong") #X
model = pk.Model(name = "testModel", Q_p = "wrong") #Q_p
model = pk.Model(name = "testModel", Q_p = ["a"]) #Q_p values
model = pk.Model(name = "testModel", V_p = "wrong") #V_p
model = pk.Model(name = "testModel", V_p = ["a"]) #V_p values
#Q_p and V_p not equal length
expectedOutput = "Q_p and V_p must be of equal length"
with mock.patch('sys.stdout', new = StringIO()) as fake_out:
print(model)
self.assertEqual(fake_out.getvalue(), expectedOutput)

"""
Test addition of compartments.
"""
def test_add_compartment(self):
#initiate model#
model = pk.Model(name = "TestModel")
#test correct addition of compartment#
model.add_compartment(Q_p = 2, V_p = 2)
self.assertEqual(model.Q_p, [2])
self.assertEqual(model.V_p, [2])
#test incorrect variables inputs#
with self.assertRaises(TypeError):
model.add_compartment(Q_p = "a", V_p = 2) #Q_p
model.add_compartment(Q_p = 2, V_p = "a") #V_p
Loading