Matrix rotation algorithm - follow-up
List comprehensions

Whenever you see a list initialization to [],
later filled in by .append(...) calls in a loop,
consider rewriting with a list comprehension.
For example:


matrix = []
for row in range(M):
    matrix.append(list(map(int, input().split())))



Can be rewritten on a single line:

matrix = [list(map(int, input().split())) for _ in range(M)]


Note that I renamed row to _,
this is a common convention when then loop variable is unused.

Another example of that is this list comprehension later in your code:


ring = [[] for layer in range(layers)]



Like earlier, rename layer to _:

ring = [[] for _ in range(layers)]


Integer division with //

Instead of this:


layers = int(min(N, M)/2)



Another, a more natural way to achieve the same effect using integer division with //:

layers = min(N, M) // 2


Coding style

The body of this for-loop is overindented:


# rotate each layer
for level in range(layers):
        r = rotations % len(ring[level])
        ring[level] = ring[level][r:] + ring[level][:r]



Possibly it's a result of the copy-pasting?
Either way,
a PEP8 checker would catch this.
It's recommended to use four spaces for an indent level,
and to use only spaces and never tabs for indenting code.

Reducing duplicated code

The current implementation works like this:


put each layer into ring
rotate the values in each layer in ring
overwrite the layers in the matrix from ring


Step 1 and 3 have very similar code, as you yourself noticed.
One way to reduce that is to implement shifting in-place,
without using the additional storage ring,
by doing something like this (\$k\$ is the number of rotations):


save the first \$k\$ items in a list
overwrite the \$i\$-th values by the \$(i+k)\$-th values. The last \$k\$ values will come from the values we saved in the previous step.


Easier said than done? Yes. Calculating the \$(i + k)\$-th position will be tricky.

I'd say your original implementation with the similar lines is fine:
it's easy to understand, and it passed the tests anyway.