prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  string representation of various Maker classes may cause a TypeError
  This was tested against Gammapy 0.19 and the development version.
  
  In some cases, printing (or using the string representation in another way) of an instance of a `gammapy.makers.Maker` subclass may cause a TypeError.
  
  An example directly from the tutorials (introduction, low-level analysis):
  ```
  from astropy import units
  from regions import CircleSkyRegion
  from gammapy.makers import FoVBackgroundMaker
  from astropy.coordinates import SkyCoord
  from gammapy.maps import WcsGeom, MapAxis
  
  energy_axis = MapAxis.from_energy_bounds(1.0, 10.0, 4, unit="TeV")
  geom = WcsGeom.create(
      skydir=(83.633, 22.014),
      binsz=0.02,
      width=(2, 2),
      frame="icrs",
      proj="CAR",
      axes=[],
  )
  circle = CircleSkyRegion(
      center=SkyCoord("83.63 deg", "22.14 deg"), radius=0.2 * units.deg
  )
  exclusion_mask = ~geom.region_mask(regions=[circle])
  maker_fov = FoVBackgroundMaker(method="fit", exclusion_mask=exclusion_mask)
  str(maker_fov)
  ```
  
  will cause a 
  ```
  TypeError: Cannot parse "not available" as a Quantity. It does not start with a number.
  ```
  (full traceback at the bottom).
  
  The reason is in the `__str__` implementation of the `gammapy.makers.Maker` abstract class:
  ```
      def __str__(self):
          # <snip>
          for name in names:
              value = getattr(self, name, "not available")
  
              if value == "not available":
                  continue
              else:
                  s += f"\t{name:{max_len}s}: {value}\n"
  
          return s.expandtabs(tabsize=2)
  ```
  
  When an attribute is not found, it is set to the string "not available". Otherwise, the attribute's value is retrieved.
  The resulting value is then compared to the string "not available" to determine whether it is an existing attribute. But some classes can't compare to string. In this particular case, comparing an instance of `WcsNDMap` fails this comparison, resulting (indirectly) in the `TypeError`.
  
  Perhaps the most Pythonic solution is to have `WcsNDMap` handle comparisons with any arbirtrary type, and return `False`. This is what Python does: `1 == "abc"` is valid and returns `False`; similar for e.g. `1 = ["abc", 5.5]`.
  
  Perhaps easier, and in my opinion semantically better, is to use
  ```
  value = getattr(self, name, None)
  if value is None:
      continue
  s += f"\t{name:{max_len}s}: {value}\n"
  ```
  since `None` signifies the optional type in Python.
  
  Though even better, in my opinion, is to simply use
  ```
  for name in names:
      try:
          value = getattr(self, name)
      except AttributeError:
          continue
      s += f"\t{name:{max_len}s}: {value}\n" 
  ```
  After all, this is what exceptions are for. (People sometimes mention speed reasons if the lookup fails a lot of times, but I don't think that's relevant here for a `__str__` implementation.)
  
  I would even simply use `self.name`, but that'll fail because `Maker` is an abstract class, so more dynamic retrieval of attributes is required. I assume this is why it's implemented in its current way.
  
  
  -----
  
  Full traceback:
  ```
  Traceback (most recent call last):
    File "/home/user/.miniconda3/envs/gammapy-dev/lib/python3.7/site-packages/astropy/units/quantity.py", line 333, in __new__
      value = float(v.group())
  AttributeError: 'NoneType' object has no attribute 'group'
  
  During handling of the above exception, another exception occurred:
  
  Traceback (most recent call last):
    File "gammapy_maker_str.py", line 22, in <module>
      str(maker_fov)
    File "/home/user/.miniconda3/envs/gammapy-dev/lib/python3.7/site-packages/gammapy/makers/core.py", line 31, in __str__
      if value == "not available":
    File "/home/user/.miniconda3/envs/gammapy-dev/lib/python3.7/site-packages/gammapy/maps/core.py", line 1612, in __eq__
      return self._arithmetics(np.equal, other, copy=True)
    File "/home/user/.miniconda3/envs/gammapy-dev/lib/python3.7/site-packages/gammapy/maps/core.py", line 1552, in _arithmetics
      q = u.Quantity(other, copy=False)
    File "/home/user/.miniconda3/envs/gammapy-dev/lib/python3.7/site-packages/astropy/units/quantity.py", line 338, in __new__
      .format(value, cls.__name__))
  TypeError: Cannot parse "not available" as a Quantity. It does not start with a number.
  ```
  
  
  </issue>
  <code>
  [start of gammapy/makers/core.py]
  1 # Licensed under a 3-clause BSD style license - see LICENSE.rst
  2 import abc
  3 import numpy as np
  4 
  5 __all__ = ["Maker"]
  6 
  7 
  8 class Maker(abc.ABC):
  9     """Abstract maker base class."""
  10 
  11     @property
  12     @abc.abstractmethod
  13     def tag(self):
  14         pass
  15 
  16     @abc.abstractmethod
  17     def run(self):
  18         pass
  19 
  20     def __str__(self):
  21         s = f"{self.__class__.__name__}\n"
  22         s += "-" * (len(s) - 1) + "\n\n"
  23 
  24         names = self.__init__.__code__.co_varnames
  25 
  26         max_len = np.max([len(_) for _ in names]) + 1
  27 
  28         for name in names:
  29             value = getattr(self, name, "not available")
  30 
  31             if value == "not available":
  32                 continue
  33             else:
  34                 s += f"\t{name:{max_len}s}: {value}\n"
  35 
  36         return s.expandtabs(tabsize=2)
  37
  [end of gammapy/makers/core.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/gammapy/makers/core.py b/gammapy/makers/core.py
  --- a/gammapy/makers/core.py
  +++ b/gammapy/makers/core.py
  @@ -26,9 +26,9 @@
           max_len = np.max([len(_) for _ in names]) + 1
   
           for name in names:
  -            value = getattr(self, name, "not available")
  +            value = getattr(self, name, None)
   
  -            if value == "not available":
  +            if value is None:
                   continue
               else:
                   s += f"\t{name:{max_len}s}: {value}\n"
  
verification_info: {"golden_diff": "diff --git a/gammapy/makers/core.py b/gammapy/makers/core.py\n--- a/gammapy/makers/core.py\n+++ b/gammapy/makers/core.py\n@@ -26,9 +26,9 @@\n         max_len = np.max([len(_) for _ in names]) + 1\n \n         for name in names:\n-            value = getattr(self, name, \"not available\")\n+            value = getattr(self, name, None)\n \n-            if value == \"not available\":\n+            if value is None:\n                 continue\n             else:\n                 s += f\"\\t{name:{max_len}s}: {value}\\n\"\n", "issue": "string representation of various Maker classes may cause a TypeError\nThis was tested against Gammapy 0.19 and the development version.\r\n\r\nIn some cases, printing (or using the string representation in another way) of an instance of a `gammapy.makers.Maker` subclass may cause a TypeError.\r\n\r\nAn example directly from the tutorials (introduction, low-level analysis):\r\n```\r\nfrom astropy import units\r\nfrom regions import CircleSkyRegion\r\nfrom gammapy.makers import FoVBackgroundMaker\r\nfrom astropy.coordinates import SkyCoord\r\nfrom gammapy.maps import WcsGeom, MapAxis\r\n\r\nenergy_axis = MapAxis.from_energy_bounds(1.0, 10.0, 4, unit=\"TeV\")\r\ngeom = WcsGeom.create(\r\n    skydir=(83.633, 22.014),\r\n    binsz=0.02,\r\n    width=(2, 2),\r\n    frame=\"icrs\",\r\n    proj=\"CAR\",\r\n    axes=[],\r\n)\r\ncircle = CircleSkyRegion(\r\n    center=SkyCoord(\"83.63 deg\", \"22.14 deg\"), radius=0.2 * units.deg\r\n)\r\nexclusion_mask = ~geom.region_mask(regions=[circle])\r\nmaker_fov = FoVBackgroundMaker(method=\"fit\", exclusion_mask=exclusion_mask)\r\nstr(maker_fov)\r\n```\r\n\r\nwill cause a \r\n```\r\nTypeError: Cannot parse \"not available\" as a Quantity. It does not start with a number.\r\n```\r\n(full traceback at the bottom).\r\n\r\nThe reason is in the `__str__` implementation of the `gammapy.makers.Maker` abstract class:\r\n```\r\n    def __str__(self):\r\n        # <snip>\r\n        for name in names:\r\n            value = getattr(self, name, \"not available\")\r\n\r\n            if value == \"not available\":\r\n                continue\r\n            else:\r\n                s += f\"\\t{name:{max_len}s}: {value}\\n\"\r\n\r\n        return s.expandtabs(tabsize=2)\r\n```\r\n\r\nWhen an attribute is not found, it is set to the string \"not available\". Otherwise, the attribute's value is retrieved.\r\nThe resulting value is then compared to the string \"not available\" to determine whether it is an existing attribute. But some classes can't compare to string. In this particular case, comparing an instance of `WcsNDMap` fails this comparison, resulting (indirectly) in the `TypeError`.\r\n\r\nPerhaps the most Pythonic solution is to have `WcsNDMap` handle comparisons with any arbirtrary type, and return `False`. This is what Python does: `1 == \"abc\"` is valid and returns `False`; similar for e.g. `1 = [\"abc\", 5.5]`.\r\n\r\nPerhaps easier, and in my opinion semantically better, is to use\r\n```\r\nvalue = getattr(self, name, None)\r\nif value is None:\r\n    continue\r\ns += f\"\\t{name:{max_len}s}: {value}\\n\"\r\n```\r\nsince `None` signifies the optional type in Python.\r\n\r\nThough even better, in my opinion, is to simply use\r\n```\r\nfor name in names:\r\n    try:\r\n        value = getattr(self, name)\r\n    except AttributeError:\r\n        continue\r\n    s += f\"\\t{name:{max_len}s}: {value}\\n\" \r\n```\r\nAfter all, this is what exceptions are for. (People sometimes mention speed reasons if the lookup fails a lot of times, but I don't think that's relevant here for a `__str__` implementation.)\r\n\r\nI would even simply use `self.name`, but that'll fail because `Maker` is an abstract class, so more dynamic retrieval of attributes is required. I assume this is why it's implemented in its current way.\r\n\r\n\r\n-----\r\n\r\nFull traceback:\r\n```\r\nTraceback (most recent call last):\r\n  File \"/home/user/.miniconda3/envs/gammapy-dev/lib/python3.7/site-packages/astropy/units/quantity.py\", line 333, in __new__\r\n    value = float(v.group())\r\nAttributeError: 'NoneType' object has no attribute 'group'\r\n\r\nDuring handling of the above exception, another exception occurred:\r\n\r\nTraceback (most recent call last):\r\n  File \"gammapy_maker_str.py\", line 22, in <module>\r\n    str(maker_fov)\r\n  File \"/home/user/.miniconda3/envs/gammapy-dev/lib/python3.7/site-packages/gammapy/makers/core.py\", line 31, in __str__\r\n    if value == \"not available\":\r\n  File \"/home/user/.miniconda3/envs/gammapy-dev/lib/python3.7/site-packages/gammapy/maps/core.py\", line 1612, in __eq__\r\n    return self._arithmetics(np.equal, other, copy=True)\r\n  File \"/home/user/.miniconda3/envs/gammapy-dev/lib/python3.7/site-packages/gammapy/maps/core.py\", line 1552, in _arithmetics\r\n    q = u.Quantity(other, copy=False)\r\n  File \"/home/user/.miniconda3/envs/gammapy-dev/lib/python3.7/site-packages/astropy/units/quantity.py\", line 338, in __new__\r\n    .format(value, cls.__name__))\r\nTypeError: Cannot parse \"not available\" as a Quantity. It does not start with a number.\r\n```\r\n\n", "before_files": [{"content": "# Licensed under a 3-clause BSD style license - see LICENSE.rst\nimport abc\nimport numpy as np\n\n__all__ = [\"Maker\"]\n\n\nclass Maker(abc.ABC):\n    \"\"\"Abstract maker base class.\"\"\"\n\n    @property\n    @abc.abstractmethod\n    def tag(self):\n        pass\n\n    @abc.abstractmethod\n    def run(self):\n        pass\n\n    def __str__(self):\n        s = f\"{self.__class__.__name__}\\n\"\n        s += \"-\" * (len(s) - 1) + \"\\n\\n\"\n\n        names = self.__init__.__code__.co_varnames\n\n        max_len = np.max([len(_) for _ in names]) + 1\n\n        for name in names:\n            value = getattr(self, name, \"not available\")\n\n            if value == \"not available\":\n                continue\n            else:\n                s += f\"\\t{name:{max_len}s}: {value}\\n\"\n\n        return s.expandtabs(tabsize=2)\n", "path": "gammapy/makers/core.py"}]}