0

Let's say I have a python function and dictionary as follows:

d = {"a": 1, "b": 2, "c": 3}
def foo(input):
    return d[input]

Is there a way when I push my code to GitHub (presumably with some sort of continuous integration) to check that all calls of foo only use one of the keys of d as the input argument, and if there is a call with an invalid argument, to flag it or raise an alert?

For example:

foo("a") # no flag
foo("d") # flag/alert

I know how I would raise an exception or ValueError at runtime, but I'm looking for a CI solution to include in our GitHub workflow. Right now we are using Travis-CI for our custom tests and the standard CodeQL tests provided by LGTM. I looked into using custom CodeQL via LGTM, but I couldn't quite figure it out. I'd be fine implementing it in either of those continuous integrations or implementing a third.

William Gearty
  • 166
  • 1
  • 8
  • Sounds like you'd want proper function parameter annotations and a checker for those. – AKX Sep 09 '20 at 17:09
  • Hmm...I didn't know you could do parameter annotations beyond type? Especially in python 2.7? – William Gearty Sep 10 '20 at 18:15
  • 1
    Well, you shouldn't use Python 2.7 anyway, since it's been EOL for 9 months now. But yes, there's a PEP for typed dicts: https://www.python.org/dev/peps/pep-0589/ – AKX Sep 10 '20 at 19:31
  • Correct me if I'm wrong, but isn't that PEP describing setting annotations for the keys and values of a dictionary, not for the arguments of a function? – William Gearty Sep 11 '20 at 01:16
  • Hmm...upon further searching, maybe a Literal type annotation would work? Except you can't do Literal[dict.keys()]... – William Gearty Sep 11 '20 at 02:06

1 Answers1

0

we are in your wrkDir where your pythonFunction.py is, where your foo(input), d dict is inside. In that wrkDir create file tests.py:

import unittest

class TestPythonFunction(unittest.TestCase):
    # define here all required cases
    ALL_DICT_REQUIREMENTS_ =(
        ('a', 1), 
        ('b', 2), 
        ('c', 3)
    )

    
    def test_dictFoo(self):
        # pythonFunction reflects to your pythonFunction.py
        from pythonFunction import foo
        # test all required patterns
        for pattern in TestPythonFunction.ALL_DICT_REQUIREMENTS_:
            key = pattern[0]
            value = pattern[1]
            self.assertIs(foo(key), value)
        # test function is raising error if key doesn't exists
        with self.assertRaises((KeyError)):
            foo('nonsenseKey')
    

if __name__ == '__main__':
    unittest.main()
    

In wrkDir run

python tests.py

expexted output:

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

The tests.py exit code is 0 (all tests succeeded), or none 0 if some test failed, so you can control your CI task accordingly,

python tests.py && git push || echo "Bad, check tests for error"
harry hartmann
  • 351
  • 1
  • 9
  • You're... basically describing unit tests here. If OP already uses Travis, they probably know what tests are. – AKX Sep 09 '20 at 17:10
  • 'CI solution to include in our GitHub workflow' - that's what does it describe, isn't? – harry hartmann Sep 09 '20 at 17:14
  • We already have code in our function to give a warning if the function is called with an "invalid" argument (I excluded that in my example above), which is thrown at runtime. This unit test would certainly be an effective way to check that that works. What I'm looking for is a way to proactively detect code (before it hits our django server) that is written and pushed to GitHub that uses a new/invalid argument without also including the argument in the dictionary as a key:value pair. – William Gearty Sep 09 '20 at 21:30
  • How do you define invalid argument if you don't know your dict.keys()? – harry hartmann Sep 10 '20 at 01:28
  • I don't want (in this case) to check if the argument is invalid when the function is called. I want to check if a function call is invalid when it is written and pushed to GitHub (so in this case, more similar to lgtm/codeql checks than travis unit tests). Basically, I want to make sure that someone has added a corresponding item to dict if they then add a function call with a new (not preexisting in dict) argument. – William Gearty Sep 10 '20 at 18:03