Repository: astropy/astropy

Issue:
BUG: crash when offsetting SkyCoord object out of angular bounds
The following example is inspired from `astropy/coordinates/tests/test_frame/test_spherical_offsets_by_broadcast`, with the crucial difference that I'm intentionally asking for a transformation that requires a wrap.

```python
import numpy as np
import astropy.units as u
from astropy.coordinates import SkyCoord

sc = SkyCoord(ra=np.array([123]), dec=np.array([90]), unit=u.deg)
sc.spherical_offsets_by(-2 * u.deg, 0 * u.deg)
```

traceback:
```python-traceback
Traceback (most recent call last):
  File "/Users/clm/dev/astropy-project/coordinated/astropy/untitled.py", line 6, in <module>
    sc.spherical_offsets_by(-2 * u.deg, 0 * u.deg)
  File "/Users/clm/dev/astropy-project/coordinated/astropy/astropy/coordinates/sky_coordinate.py", line 1242, in spherical_offsets_by
    SkyOffsetFrame(d_lon, d_lat, origin=self.frame).transform_to(self)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/clm/dev/astropy-project/coordinated/astropy/astropy/coordinates/builtin_frames/skyoffset.py", line 174, in __init__
    self._set_skyoffset_data_lon_wrap_angle(self.data)
  File "/Users/clm/dev/astropy-project/coordinated/astropy/astropy/coordinates/builtin_frames/skyoffset.py", line 179, in _set_skyoffset_data_lon_wrap_angle
    data.lon.wrap_angle = 180.0 * u.deg
    ^^^^^^^^^^^^^^^^^^^
  File "/Users/clm/dev/astropy-project/coordinated/astropy/astropy/coordinates/angles/core.py", line 733, in wrap_angle
    self._wrap_at(self.wrap_angle)
  File "/Users/clm/dev/astropy-project/coordinated/astropy/astropy/coordinates/angles/core.py", line 422, in _wrap_at
    self_angle -= wraps * a360
ValueError: output array is read-only
```

Discussion:
github-actions[bot]: Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.

  - [ ] Do the proposed changes actually accomplish desired goals?
  - [ ] Do the proposed changes follow the [Astropy coding guidelines](https://docs.astropy.org/en/latest/development/codeguide.html)?
  - [ ] Are tests added/updated as required? If so, do they follow the [Astropy testing guidelines](https://docs.astropy.org/en/latest/development/testguide.html)?
  - [ ] Are docs added/updated as required? If so, do they follow the [Astropy documentation guidelines](https://docs.astropy.org/en/latest/development/docguide.html#astropy-documentation-rules-and-guidelines)?
  - [ ] Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for [rebase](https://docs.astropy.org/en/latest/development/workflow/development_workflow.html#rebase-if-necessary) and [squash](https://docs.astropy.org/en/latest/development/workflow/development_workflow.html#squash-if-necessary).
  - [ ] Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the [bot](https://docs.astropy.org/en/latest/development/workflow/development_workflow.html#pre-commit).
  - [ ] Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  - [ ] Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  - [ ] At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) *before* merge.
github-actions[bot]: 👋 Thank you for your draft pull request! Do you know that you can use `[ci skip]` or `[skip ci]` in your commit messages to skip running continuous integration tests until you are ready?

Patch:
diff --git a/astropy/coordinates/baseframe.py b/astropy/coordinates/baseframe.py
index 06ab3ce982..b69e6d1316 100644
--- a/astropy/coordinates/baseframe.py
+++ b/astropy/coordinates/baseframe.py
@@ -346,7 +346,14 @@ class BaseCoordinateFrame(ShapedLikeNDArray):
 
         # Broadcast the data if necessary and set it
         if data is not None and data.shape != self._shape:
-            data = data._apply(np.broadcast_to, shape=self._shape, subok=True)
+            try:
+                # if broadcasting isn't strictly needed, avoid it
+                # see https://github.com/astropy/astropy/issues/16219
+                data = data.reshape(self._shape)
+            except Exception:
+                data = data._apply(np.broadcast_to, shape=self._shape, subok=True)
+                if copy:
+                    data = data.copy()
         self._data = data
         # Broadcast the attributes if necessary by getting them again
         # (we now know the shapes will be OK).
diff --git a/docs/changes/coordinates/16241.bugfix.rst b/docs/changes/coordinates/16241.bugfix.rst
new file mode 100644
index 0000000000..fe07d21d45
--- /dev/null
+++ b/docs/changes/coordinates/16241.bugfix.rst
@@ -0,0 +1,2 @@
+Fix a bug where ``SkyCoord.spherical_offsets_by`` would crash when a wrap
+was needed.
diff --git a/docs/coordinates/angles.rst b/docs/coordinates/angles.rst
index f049484e4e..528b845ff8 100644
--- a/docs/coordinates/angles.rst
+++ b/docs/coordinates/angles.rst
@@ -175,12 +175,6 @@ angles and wrapping to be within a single 360 degree slice. The
 :meth:`~astropy.coordinates.Angle.is_within_bounds` method returns a
 boolean indicating whether an angle or angles is within the specified bounds.
 
-.. Note::
-    While creating |Angle| instances from arrays with integral data types
-    is technically possible (for example with ``dtype=int``), it is very
-    limited in functionality and in particular wrapping is not supported for
-    such objects.
-
 
 Longitude and Latitude Objects
 ==============================


Test patch:
diff --git a/astropy/coordinates/tests/test_frames.py b/astropy/coordinates/tests/test_frames.py
index 3a9aa62ba4..c42d6f65b6 100644
--- a/astropy/coordinates/tests/test_frames.py
+++ b/astropy/coordinates/tests/test_frames.py
@@ -1690,3 +1690,14 @@ def test_spherical_offsets_by_broadcast():
     assert SkyCoord(
         ra=np.array([123, 134, 145]), dec=np.array([45, 56, 67]), unit=u.deg
     ).spherical_offsets_by(2 * u.deg, 2 * u.deg).shape == (3,)
+
+
+@pytest.mark.parametrize("shape", [(1,), (2,)])
+def test_spherical_offsets_with_wrap(shape):
+    # see https://github.com/astropy/astropy/issues/16219
+    sc = SkyCoord(ra=np.broadcast_to(123.0, shape), dec=90.0, unit=u.deg)
+    scop = sc.spherical_offsets_by(+2 * u.deg, 0 * u.deg)
+    assert scop.shape == shape
+
+    scom = sc.spherical_offsets_by(-2 * u.deg, 0 * u.deg)
+    assert scom.shape == shape