title: ModuleNotFoundError: No module named 'src'. Python 3 error
body: <p>I'm facing the dreaded <code>ModuleNotFoundError: No module named 'src'</code> error. I've done quite some extensive reading into this problem and see that this is a common problem. I can't seem to wrap my head around this.</p>
  
  <p>You can pull my repo at <a href="https://github.com/mustafahoda/data-structures-and-algos" rel="nofollow noreferrer">https://github.com/mustafahoda/data-structures-and-algos</a></p>
  
  <p>Here is what my current project directory looks like.</p>
  
  <ul>
  <li>I'm using pipenv and running commands from after entering the env shell.</li>
  <li>I'm using python 3</li>
  </ul>
  
  <pre><code>DSandAlgoBenchmarkSuite
    src
     |---CommonProblems
     |---DataStructures
     |---SortingAlgorithms
       |--sorting_algos.py
  
    test
     |---test_bubble_sort_1.py
  
    .gitignore
    .benchmarks
    .pytest_cache
    Pipfile
    Pipfile.lock
    test.py
    test_bubble_sort_2.py
  </code></pre>
  
  <p>I have two files that I'd like to run:</p>
  
  <ol>
  <li>test/test_bubble_sort_1.py </li>
  <li>test_bubble_sort_2.py</li>
  </ol>
  
  <p>Contents of each file.</p>
  
  <pre class="lang-py prettyprint-override"><code># test/test_bubble_sort_1.py 
  from src.SortingAlgorithms import sorting_algos
  
  import pytest
  </code></pre>
  
  <pre class="lang-py prettyprint-override"><code># test_bubble_sort_2.py
  from src.SortingAlgorithms import sorting_algos
  
  import pytest
  
  </code></pre>
  
  <pre class="lang-py prettyprint-override"><code># src/SortingAlgorithms/sorting_algos.py
  # ---------BUBBLE SORT-------------
  def bubble_sort(A: list) -&gt; list:
  
      sorted = len(A)
  
      for i in range(len(A)):
  
          L = 0
          R = 1
  
          while R != len(A) :
  
              # if L &gt; R, then swap
              if A[L] &gt; A[R]:
                  temp = A[L]
                  A[L] = A[R]
                  A[R] = temp
  
              L = L + 1
              R = R + 1
  
      return A
  
  
  # -----------------INSERTION SORT----------------------
  def shift_items_to_right(B, start, stop):
      for i in range(stop, start, -1):
          B[i] = B[i - 1]
  
      return B
  
  
  def insertion_sort(A : list) -&gt; list:
      sorted = 0
  
      while sorted != len(A):
  
          hole = 0
  
          for i in A[:sorted + 1]:
              value = A[sorted]
  
              if value &lt; A[hole]:
                  # move all items to the right from the hole onwards
                  shift_items_to_right(A, hole, sorted)
  
                  # store the value in the hole
                  A[hole] = value
  
              else:
                  hole = hole + 1
  
          sorted = sorted + 1
  
      return A
  
  # ---------------------MERGE SORT--------------------------------------
  def merge(A: list, B: list) -&gt; list:
      ptr_A = 0
      ptr_B = 0
  
      C = []
  
      while ptr_A &lt;= len(A) - 1 and ptr_B &lt;= len(B) - 1:
  
          if A[ptr_A] &gt;= B[ptr_B]:
              C.append(B[ptr_B])
              ptr_B = ptr_B + 1
          else:
              C.append(A[ptr_A])
              ptr_A = ptr_A + 1
  
  
      if ptr_A == len(A):
          for i in B[ptr_B:]:
              C.append(i)
      else:
          for i in A[ptr_A:]:
              C.append(i)
  
      return C
  
  def merge_sort(A: list) -&gt; list:
      print("A: %s" % A)
      if len(A) == 1:
          return A
  
      # STEP 1: Divide
  
      mid = len(A) // 2
      L = A[:mid]
      R = A[mid:]
  
      if L is not None:
          L = merge_sort(L)
  
  
      if R is not None:
          R = merge_sort(R)
  
  
      merged = merge(L, R)
  
      print("Merged: %s" % merged)
      return merged
  
  
  # ---------------------QUICK SORT--------------------------------------
  def quicksort(A: list) -&gt; list:
      return _quicksort(A, 0, len(A) - 1)
  
  def _quicksort(A: list, start: int, end: int) -&gt; list:
  
  
      if start &gt;= end:
          return A
  
      print("A before partition: %s" % A)
      pIndex = partition(A, start, end)
      print("A after partition: %s" % A)
      print("_____________________________")
  
  
  
      _quicksort(A, start, pIndex - 1)
      _quicksort(A, pIndex, end)
  
      return A
  
  def partition(A, start: int, end: int):
  
      # set_trace()
  
      pivot = A[end]
  
      i = start
      pIndex = start
  
      # set_trace()
  
      while i &lt; end:
  
          # set_trace()
  
          if pivot &gt;= A[i]:
  
              # implement swap between pIndex and A[i]
  
              temp = A[i]
              A[i] = A[pIndex]
              A[pIndex] = temp
  
              pIndex = pIndex + 1
  
          i = i + 1
  
      # once we reach the element before the pivot, we swap pivot into pIndex
      temp = A[pIndex]
      A[pIndex] = pivot
      A[end] = temp
  
      # set_trace()
      print(A)
      return pIndex
  
  
  # ---------------------SELECTION SORT-------------------------------------
  
  def find_min_not_in_place(A: list, visited) -&gt; int:
  
      for i in A:
          if visited[i] == False:
              min = i
              break
  
      for i in A[1:]:
          # set_trace()
          if i &lt; min and visited[i] == False:
              # set_trace()
  
              min = i
              # visited[min] = True
  
  
      return min
  
  
  def selection_sort_not_in_place(A: list) -&gt; list:
  
      B = []
  
      # construct a dictionary that will keep track of visited numbers
      visited = dict()
      for i in A:
          visited[i] = False
  
  
      # keep repeating the process until theere are no values in dictionary with False
      while False in visited.values():
          for i in A:
  
              min = find_min_not_in_place(A, visited)
              # set_trace()
              B.append(min)
              visited[min] = True
              print(B)
  
      return B
  
  def find_min_in_place(A: list, sorted_index: int) -&gt; int:
      min_index = sorted_index
      min = A[sorted_index]
  
      # for i in A[sorted_index:]:
      for i in range(sorted_index, len(A)):
          if A[i] &lt; min:
              min = A[i]
              min_index = i
  
  
      return (min, min_index)
  
  
  
  def selection_sort_in_place(A: list) -&gt; list:
  
      sorted = 0
  
      while sorted != len(A):
  
          # min, min_index = find_min_in_place(A[sorted + 1:])
          min, min_index = find_min_in_place(A, sorted)
  
          # implement swapping
          temp = A[sorted]
          A[sorted] = min
          A[min_index] = temp
  
          sorted = sorted + 1
  
      return A
  </code></pre>
  
  <p>Ideally, I want pytest-benchmark suite to work but I've isolated the problem to being an import error. </p>
  
  <p>When I run test_bubble_sort_2.py from the main project directory, it works fine!</p>
  
  <p>However, when I run test/test_bubble_sort_1.py from the main project directory, it doesn't work and throws the exception: <code>ModuleNotFoundError: No module named 'src'</code></p>
  
  <p>I'd like to run <code>test/test_bubble_sort_1.py</code> in order to maintain the project structure and access the functions from my <code>sorting_algos.py</code> file so I can benchmark them.</p>