I came up with my custom solution which replicates Unity 9-slice sprite technique.
The following method uses 9-slice parameters as well as the desired size and draw method.
Rendering modes
To make this method as close to Unity as possible I created two modes:
SLICED
- Draw corners of the sprite and scale the content and edges
TILED
- Draw corners of the sprite and tile edges and content
The following example uses this test asset to demonstrate rendering differences: 
import pygame
from pygame.locals import *
from enum import Enum
pygame.init()
clock = pygame.time.Clock()
fps = 60
# Set up the drawing window
screen = pygame.display.set_mode([300, 300])
pygame.display.set_caption('Sprite Slicing Example')
# load test sprite
sprite = pygame.image.load('res/test.png')
# define draw mode enums
DrawMode = Enum('DrawMode', ['SLICED', 'TILED'])
# 9-slice a sprite to the desired size
def slice_sprite(sprite, left, right, top, bottom, width, height, draw_mode=DrawMode.TILED):
# get the size of the sprite
sprite_width = sprite.get_width()
sprite_height = sprite.get_height()
# create a new surface to draw the sliced sprite on
sliced_sprite = pygame.Surface((width, height))
# draw the top left side of the sprite
sliced_sprite.blit(sprite, (0, 0), (0, 0, left, top))
# draw the top right side of the sprite
sliced_sprite.blit(sprite, (width - right, 0),
(sprite_width - right, 0, right, top))
# draw the bottom left side of the sprite
sliced_sprite.blit(sprite, (0, height - bottom),
(0, sprite_height - bottom, left, bottom))
# draw the bottom right side of the sprite
sliced_sprite.blit(sprite, (width - right, height - bottom),
(sprite_width - right, sprite_height - bottom, right, bottom))
match draw_mode:
case DrawMode.SLICED:
# scale top and bottom sides of the sprite
sliced_sprite.blit(pygame.transform.scale(sprite.subsurface(
left, 0, sprite_width - left - right, top), (width - left - right, top)), (left, 0))
sliced_sprite.blit(pygame.transform.scale(sprite.subsurface(left, sprite_height - bottom,
sprite_width - left - right, bottom), (width - left - right, bottom)), (left, height - bottom))
# scale the center of the sprite
sliced_sprite.blit(pygame.transform.scale(sprite.subsurface(left, top, sprite_width - left - right,
sprite_height - top - bottom), (width - left - right, height - top - bottom)), (left, top))
# scale left and right sides of the sprite
sliced_sprite.blit(pygame.transform.scale(sprite.subsurface(
0, top, left, sprite_height - top - bottom), (left, height - top - bottom)), (0, top))
sliced_sprite.blit(pygame.transform.scale(sprite.subsurface(sprite_width - right, top, right,
sprite_height - top - bottom), (right, height - top - bottom)), (width - right, top))
case DrawMode.TILED:
# tile the center of the sprite
for x in range(left, width - right, sprite_width - left - right):
for y in range(top, height - bottom, sprite_height - top - bottom):
sliced_sprite.blit(sprite.subsurface(
left, top, sprite_width - left - right, sprite_height - top - bottom), (x, y))
# tile top and bottom sides of the sprite
for x in range(left, width - right, sprite_width - left - right):
sliced_sprite.blit(sprite.subsurface(
left, 0, sprite_width - left - right, top), (x, 0))
sliced_sprite.blit(sprite.subsurface(
left, sprite_height - bottom, sprite_width - left - right, bottom), (x, height - bottom))
# tile left and right sides of the sprite
for y in range(top, height - bottom, sprite_height - top - bottom):
sliced_sprite.blit(sprite.subsurface(
0, top, left, sprite_height - top - bottom), (0, y))
sliced_sprite.blit(sprite.subsurface(
sprite_width - right, top, right, sprite_height - top - bottom), (width - right, y))
# draw the corners of the sprite
sliced_sprite.blit(sprite.subsurface(0, 0, left, top), (0, 0))
sliced_sprite.blit(sprite.subsurface(
sprite_width - right, 0, right, top), (width - right, 0))
sliced_sprite.blit(sprite.subsurface(
0, sprite_height - bottom, left, bottom), (0, height - bottom))
sliced_sprite.blit(sprite.subsurface(
sprite_width - right, sprite_height - bottom, right, bottom), (width - right, height - bottom))
return sliced_sprite
run = True
while run:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# Draw the sprite
screen.blit(slice_sprite(sprite, 8, 8, 8, 8, 100, 100), (100, 100))
# Flip the display
pygame.display.flip()
pygame.quit()
The resulting sprite with SLICED rendering:

The same sprite with TILED rendering:

Other examples
Asset: 
slice_sprite(bubble, 4, 9, 4, 6, 100, 50, draw_mode=DrawMode.TILED)

Asset: 
slice_sprite(bar, 8, 8, 8, 8, 30, 200, draw_mode=DrawMode.SLICED)

slice_sprite(bar, 8, 8, 8, 8, 200, 50, draw_mode=DrawMode.SLICED)
