Buggy python submission (verdict: Time Limit Exceeded):
#!/usr/bin/env python3
import sys
import heapq
import copy

inf = float('inf')

def findedge(E, vv):
    e = (min(vv), max(vv))
    if e in E:
        return e
    return None


def dijkstra(V, E, L, s, g):
    D = [0 if v == s else inf for v in V]

    prev = [None for v in V]
    Q = [(0, s)]
    heapq.heapify(Q)

    while len(Q) > 0:
        du, u = heapq.heappop(Q)
        # print('pop: ', u, du)
        for v in V:
            e = findedge(E, (u, v))
            if not e:
                continue
            alt = du + L[e]
            # print('edge: ', e)

            if D[v] > alt:
                D[v] = alt
                prev[v] = u
                heapq.heappush(Q, (D[v], v))
    
    # print(prev)
    return D[g]


def solve(N: int, M: int, a: "List[int]", b: "List[int]", c: "List[int]"):
    V = list(range(N))
    E = set()
    L = dict()
    
    for i in range(M):
        e = tuple(sorted([a[i], b[i]]))
        E.add(e)
        L[e] = c[i]

    count = 0
    E2 = copy.deepcopy(E)
    for e in E:
        if dijkstra(V, E2, L, e[0], e[1]) < L[e]:
            count += 1
            E2.remove(e)

    print(count)
    return


# Generated by 1.1.4 https://github.com/kyuridenamida/atcoder-tools  (tips: You use the default template now. You can remove this line by using your custom template)
def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    M = int(next(tokens))  # type: int
    a = [int()] * (M)  # type: "List[int]" 
    b = [int()] * (M)  # type: "List[int]" 
    c = [int()] * (M)  # type: "List[int]" 
    for i in range(M):
        a[i] = int(next(tokens))-1
        b[i] = int(next(tokens))-1
        c[i] = int(next(tokens))
    solve(N, M, a, b, c)

if __name__ == '__main__':
    main()


Fixed submission:
#!/usr/bin/env python3
import sys
import heapq
import copy
import itertools

inf = float('inf')

def path(u, v):
    return frozenset((u, v))


class Graph_dijkstra(object):
    def __init__(self, V: "List[int]", E: "Set[FrozenSet[int, int]]", L: "Dict[FrozenSet[int, int], int]"):
        self.V = V
        self.E = E
        self.L = L
        self.E_shortest = copy.deepcopy(E)
        self.adjacent = self.init_adjacent() # type: Dict[int: List[int]]
        self.shortest_path = self.init_shortest_path() # type: Dict[FrozenSet[int, int], int]
    
    def init_adjacent(self):
        ret = {v: [] for v in self.V}
        for e in self.E:
            el = list(e)
            ret[el[0]].append(el[1])
            ret[el[1]].append(el[0])
        return ret
    
    def init_shortest_path(self):
        ret = {path(s, g): inf for s, g in itertools.permutations(self.V, 2)}
        for v in self.V:
            ret[path(v, v)] = 0
        return ret
    
    def dijkstra(self, s: int, g: int):
        d = self.shortest_path[path(s, g)]
        if d < inf:
            return d

        D = {v: inf for v in self.V}
        D[s] = 0
        prev = {v: None for v in self.V}
        Q = [(0, s)]

        while len(Q) > 0:
            du, u = heapq.heappop(Q)
            for v in self.adjacent[u]:
                e = path(u, v)
                alt = du + self.L[e]
                if alt < D[v]:
                    D[v] = alt
                    prev[v] = u
                    heapq.heappush(Q, (D[v], v))

        for v in self.V:
            self.shortest_path[path(s, v)] = D[v]

        return self.shortest_path[path(s, g)]


def solve(N: int, M: int, a: "List[int]", b: "List[int]", c: "List[int]"):
    V = list(range(N))
    E = set()
    L = dict()
    
    for i in range(M):
        e = path(a[i], b[i])
        E.add(e)
        L[e] = c[i]

    G = Graph_dijkstra(V, E, L)
    count = 0
    for e in E:
        el = list(e)
        path_len = G.dijkstra(el[0], el[1])
        if path_len < L[e]:
            count += 1
    print(count)
    return


# Generated by 1.1.4 https://github.com/kyuridenamida/atcoder-tools  (tips: You use the default template now. You can remove this line by using your custom template)
def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    M = int(next(tokens))  # type: int
    a = [int()] * (M)  # type: "List[int]" 
    b = [int()] * (M)  # type: "List[int]" 
    c = [int()] * (M)  # type: "List[int]" 
    for i in range(M):
        a[i] = int(next(tokens))-1
        b[i] = int(next(tokens))-1
        c[i] = int(next(tokens))
    solve(N, M, a, b, c)

if __name__ == '__main__':
    main()