strstr implementation with python and sets
As someone trying to pivot from physics to Computer Science, I think this solution is good, many CS graduates might not come up with a better solution first up.
Let's get some optimizations unrelated to cyclomatic complexity out of the way.
You added the pattern to a set. The lookup is constant O(1), I don't see a need to do that and you can save on a high constant.
Let's take a closer look at
    for index in range(len_text-len_pattern+1):
        if text[index:index+len_pattern] in lookup:

specifically text[index:index+len_pattern], this creates a copy of the string for the range index:len_pattern.  This is an implementation detail of Python, one can just as easily imagine an optimization that does not create a copy.
This question and its response might help explain this better.
You might be able to optimize away the object creation, again this unrelated to cyclomatic complexity.
premature optimization is evil - the intent above is more of a code review. Addressing you question below.

The runtime complexity of the loop is the equivalent of creating a copy of the pattern times the len of text
if m is len(text) and n is len(pattern) the for loop is O(n*m) in every iteration.
Typically in questions like these, there is an insight that is not always obvious that drives the solution resulting in a lower cyclomatic complexity. In this instance it is that the algorithm can be implemented in a single pass O(n) by keeping track of indexes across both the text and the pattern
def strstr(text, pattern):
     
    t = 0
    len_text = len(text)
    len_pattern = len(pattern)
    i = 0
    for i in range(len_text + 1):
        if (t == len_pattern or i == len_text):
            break
        if (text[i] == pattern[t]):
            t += 1
        elif (text[i] == pattern[0]):
            t = 1
        else:
            t = 0

    if (t &lt; len_pattern):
        return -1
    else:
        return i - t
    
def tests():
    &quot;&quot;&quot;Sample Tests.&quot;&quot;&quot;
    samples = [(&quot;CodesignalIsAwesome&quot;, &quot;IA&quot;, -1),
               (&quot;CodesignalIsAwesome&quot;, &quot;IsA&quot;, 10),
               (&quot;a&quot;, &quot;a&quot;, 0),
               (&quot;a&quot;, &quot;A&quot;, -1),
               (&quot;sst&quot;, &quot;st&quot;, 1),
               (&quot;lrnkbldxguzgcseccinlizyogwqzlifxcthdgmanjztlt&quot;, &quot;an&quot;, 38),
               (&quot;abcd&quot; * 300000 + &quot;abcde&quot;, &quot;abcde&quot;, 1200000),]
    for text, pattern, answer in samples:
        actual = strstr(text, pattern)
        if actual != answer:
            print(f&quot;FAILED : pattern: {pattern}, actual: {actual}, expected: {answer}&quot;)
        else:
            print(f&quot;SUCCESS: pattern: {pattern}, actual: {actual} matched expected&quot;)

I added an additional text case to demonstrate the runtime, testing this with time module in python, the clock time of the implementation is a few milli seconds compared to the clock time of the O(n*m) algorithm which on my machine is aboue 21 seconds.