docs: def find_stars(self, data, mask=None):
          """
          Find stars in an astronomical image.
  
          Parameters
          ----------
          data : 2D array_like
              The 2D image array.
  
          mask : 2D bool array, optional
              A boolean mask with the same shape as ``data``, where a
              `True` value indicates the corresponding element of ``data``
              is masked.  Masked pixels are ignored when searching for
              stars.
  
          Returns
          -------
          table : `~astropy.table.Table` or `None`
              A table of found stars with the following parameters:
  
              * ``id``: unique object identification number.
              * ``xcentroid, ycentroid``: object centroid.
              * ``sharpness``: object sharpness.
              * ``roundness1``: object roundness based on symmetry.
              * ``roundness2``: object roundness based on marginal Gaussian
                fits.
              * ``npix``: the total number of pixels in the Gaussian kernel
                array.
              * ``sky``: the input ``sky`` parameter.
              * ``peak``: the peak, sky-subtracted, pixel value of the object.
              * ``flux``: the object flux calculated as the peak density in
                the convolved image divided by the detection threshold.  This
                derivation matches that of `DAOFIND`_ if ``sky`` is 0.0.
              * ``mag``: the object instrumental magnitude calculated as
                ``-2.5 * log10(flux)``.  The derivation matches that of
                `DAOFIND`_ if ``sky`` is 0.0.
  
              `None` is returned if no stars are found.
  
          """
  
          star_cutouts = _find_stars(data, self.kernel, self.threshold_eff,
                                     mask=mask,
                                     exclude_border=self.exclude_border)
  
          if star_cutouts is None:
              warnings.warn('No sources were found.', NoDetectionsWarning)
              return None
  
          self._star_cutouts = star_cutouts
  
          star_props = []
          for star_cutout in star_cutouts:
              props = _DAOFind_Properties(star_cutout, self.kernel, self.sky)
  
              if np.isnan(props.dx_hx).any() or np.isnan(props.dy_hy).any():
                  continue
  
              if (props.sharpness <= self.sharplo or
                      props.sharpness >= self.sharphi):
                  continue
  
              if (props.roundness1 <= self.roundlo or
                      props.roundness1 >= self.roundhi):
                  continue
  
              if (props.roundness2 <= self.roundlo or
                      props.roundness2 >= self.roundhi):
                  continue
  
              if self.peakmax is not None and props.peak >= self.peakmax:
                  continue
  
              star_props.append(props)
  
          nstars = len(star_props)
          if nstars == 0:
              warnings.warn('Sources were found, but none pass the sharpness '
                            'and roundness criteria.', NoDetectionsWarning)
              return None
  
          if self.brightest is not None:
              fluxes = [props.flux for props in star_props]
              idx = sorted(np.argsort(fluxes)[-self.brightest:].tolist())
              star_props = [star_props[k] for k in idx]
              nstars = len(star_props)
  
          table = Table()
          table['id'] = np.arange(nstars) + 1
          columns = ('xcentroid', 'ycentroid', 'sharpness', 'roundness1',
                     'roundness2', 'npix', 'sky', 'peak', 'flux', 'mag')
          for column in columns:
              table[column] = [getattr(props, column) for props in star_props]
  
          return table