Buggy python submission (verdict: Runtime Error):
import math
import collections

def getGreatestCommonDivisor(x, y):
    if x < y:
        x, y = y, x
    if y == 0:
        return x
    return getGreatestCommonDivisor(y, x % y)


N = int(input())
fishes = []
for _ in range(N):
    fishes.append([int(s) for s in input().split()])

# fishes = [
#           (3, 2),
# (3, 2),
# (-1 ,1),
# (2 ,-1),
# (-3 ,-9),
# (-8 ,12),
# (7 ,7),
# (8, 1),
# (8 ,2),
# (8, 4),
# ]

slopeCount = collections.defaultdict(int)
for x, y in fishes:
    gcl = getGreatestCommonDivisor(abs(x), abs(y))
    x //= gcl
    y //= gcl
    if x < 0:
        x = -x
        y = -y
    slopeCount[(x, y)] += 1

# print(slopeCount)

reversedPairs = dict()
independentCount = 0
for slope, count in slopeCount.items():
    x, y = slope
    rx, ry = (y, -x) if y >= 0 else (-y, x)
    if (x, y) in reversedPairs or (rx, ry) in reversedPairs:
        continue
    if (rx, ry) not in slopeCount:
        independentCount += count
        continue
    reversedPairs[(x, y)] = (count, slopeCount[(rx, ry)])
    

# print(reversedPairs, independentCount)

M = 1000000007
def subsetNum(count):
    r = 1
    for _ in range(count):
        r *= 2
        r %= M
    return r

result = subsetNum(independentCount)
if len(reversedPairs) == 0:
    result -= 1
    result %= M
    print(result)
else:
    for c1, c2 in reversedPairs.values():
        result *= (subsetNum(c1) - 1 + subsetNum(c2) - 1 + 1)
        result %= M
    result -= 1
    result %= M
    print(result)

Fixed submission:
import collections

def getGreatestCommonDivisor(x, y):
    if x < y:
        x, y = y, x
    if y == 0:
        return x
    return getGreatestCommonDivisor(y, x % y)


N = int(input())
fishes = []
for _ in range(N):
    fishes.append([int(s) for s in input().split()])

# fishes = [
#           (3, 2),
# (3, 2),
# (-1 ,1),
# (2 ,-1),
# (-3 ,-9),
# (-8 ,12),
# (7 ,7),
# (8, 1),
# (8 ,2),
# (8, 4),
# ]

# fishes = [
#           (3, 0),
#           (0, 1),
#           (0, 0),
#           (0, 0),
# ]


slopeCount = collections.defaultdict(int)
for x, y in fishes:
    if x == 0 and y == 0:
        pass
    elif x == 0:
        y = 1
    elif y == 0:
        x = 1
    else:
        gcl = getGreatestCommonDivisor(abs(x), abs(y))
        x //= gcl
        y //= gcl
    if x < 0:
        x = -x
        y = -y
    slopeCount[(x, y)] += 1

# print(slopeCount)

reversedPairs = dict()
independentCount = 0
zeroCount = 0
for slope, count in slopeCount.items():
    x, y = slope
    if (x, y) == (0, 0):
        zeroCount += count
        continue
    if x == 0:
        rx, ry = 1, 0
    elif y == 0:
        rx, ry = 0, 1
    else:
        rx, ry = (y, -x) if y >= 0 else (-y, x)
    if (x, y) in reversedPairs or (rx, ry) in reversedPairs:
        continue
    if (rx, ry) not in slopeCount:
        independentCount += count
        continue
    reversedPairs[(x, y)] = (count, slopeCount[(rx, ry)])
    

# print(reversedPairs, independentCount)

M = 1000000007
def subsetNum(count):
    r = 1
    for _ in range(count):
        r *= 2
        r %= M
    return r

result = subsetNum(independentCount)
for c1, c2 in reversedPairs.values():
    result *= (subsetNum(c1) - 1 + subsetNum(c2) - 1 + 1)
    result %= M
if zeroCount > 0:
    result += zeroCount
result -= 1
result %= M
print(result)