How can I stop screen tearing in Pygame?

I have a 2019 13-inch MacBook Pro with a 60Hz refresh rate. I have used clock.tick(30) and other combinations but it still would jitter. Is there a way to stop that? Here's my code

import pygame
import random
import time


pygame.init()


FPS = 30
win = pygame.display.set_mode((300, 600))

bg = pygame.Surface((800, 600))
bg.fill((169, 169, 169))


class Bird:

    def __init__(self, width, height):
        self.x = 100
        self.y = 100
        self.height = height
        self.width = width
        self.object = pygame.Surface((width, height))
        self.object.fill((55, 123, 44))
        self.tick_count = 0
        self.vel = 0

    def move(self):
        self.tick_count += 1
        d = self.vel * self.tick_count + 1.5*self.tick_count**2

        if d >= 16:
            d = 16

        self.y = self.y + d

    def jump(self):
        self.vel = -10.5
        self.tick_count = 0

    def draw(self, win):
        win.blit(self.object, (self.x, self.y))


class Pipe:

    gap = 200
    vel = 5
    obj = pygame.Surface((50, 500))
    obj.fill((30, 30, 30))

    def __init__(self, x):
        self.x = x
        self.height = 0
        self.width = 50
        self.top = 0
        self.bottom = 0
        self.p_top = pygame.transform.flip(self.obj, False, True)
        self.p_bottom = self.obj
        self.passed = False
        self.set_height()

    def set_height(self):
        self.height = random.randrange(50, 300)
        self.top = self.height - self.p_top.get_height()
        self.bottom = self.height + self.gap

    def move(self):
        self.x -= self.vel

    def draw(self, win):
        win.blit(self.p_top, (self.x, self.top))
        win.blit(self.p_bottom, (self.x, self.bottom))

    def collided(self, bird):
        bird_rect = pygame.Rect((bird.x, bird.y), (bird.width, bird.height))

        t_rect = pygame.Rect((self.x, 0), (self.width, self.height))
        b_rect = pygame.Rect((self.x, self.bottom),
                             (self.width, 600 - self.bottom))

        if bird_rect.colliderect(t_rect) or bird_rect.colliderect(b_rect):
            return True
        return False


def update(win, bird, pipes):
    win.blit(bg, (0, 0))

    bird.draw(win)
    for pipe in pipes:
        pipe.draw(win)
    pygame.display.flip()


def main():
    clock = pygame.time.Clock()
    bird = Bird(50, 50)
    pipes = [Pipe(600)]
    run = True
    while run:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
            elif event.type == pygame. KEYDOWN and event.key == pygame.K_SPACE:
                bird.jump()
            elif event.type == pygame. KEYDOWN and event.key == pygame.K_RETURN:
                run = False

        add_pipe = False
        rem = []
        for pipe in pipes:
            if pipe.collided(bird):
                run = False
                main()

            if pipe.x + pipe.width < 0:
                rem.append(pipe)

            if not pipe.passed and pipe.x < bird.x:
                pipe.passed = True
                add_pipe = True

            pipe.move()

        if add_pipe:
            pipes.append(Pipe(400))

        for r in rem:
            pipes.remove(r)

        bird.move()

        if bird.y > 800:
            run = False
            main()

        update(win, bird, pipes)
        clock.tick(30)

    quit()


main()