Repository: astropy/ccdproc

Issue:
`Combiner` and `combine` should accept a generator as argument
Both `Combine` and `combiner` should accept a generator (e.g. `Combiner(ifo.ccds())`) instead of requiring that the input be a list (e.g. `Combiner ([ccd for ccd in ifc.ccds()])`). This issue was first raised by @janerigby in #754.

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/astropy/ccdproc/pull/757?src=pr&el=h1) Report
> Merging [#757](https://codecov.io/gh/astropy/ccdproc/pull/757?src=pr&el=desc) (76a5590) into [master](https://codecov.io/gh/astropy/ccdproc/commit/6ee2f6763425827e646e84171234fb08e607506e?el=desc) (6ee2f67) will **increase** coverage by `0.20%`.
> The diff coverage is `99.29%`.

[![Impacted file tree graph](https://codecov.io/gh/astropy/ccdproc/pull/757/graphs/tree.svg?width=650&height=150&src=pr&token=78IoK9MaI4)](https://codecov.io/gh/astropy/ccdproc/pull/757?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #757      +/-   ##
==========================================
+ Coverage   95.34%   95.55%   +0.20%     
==========================================
  Files          30       30              
  Lines        3888     4068     +180     
==========================================
+ Hits         3707     3887     +180     
  Misses        181      181              
```


| [Impacted Files](https://codecov.io/gh/astropy/ccdproc/pull/757?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [ccdproc/combiner.py](https://codecov.io/gh/astropy/ccdproc/pull/757/diff?src=pr&el=tree#diff-Y2NkcHJvYy9jb21iaW5lci5weQ==) | `93.06% <86.66%> (+0.05%)` | :arrow_up: |
| [ccdproc/tests/run\_for\_memory\_profile.py](https://codecov.io/gh/astropy/ccdproc/pull/757/diff?src=pr&el=tree#diff-Y2NkcHJvYy90ZXN0cy9ydW5fZm9yX21lbW9yeV9wcm9maWxlLnB5) | `60.91% <100.00%> (+0.45%)` | :arrow_up: |
| [ccdproc/tests/run\_with\_file\_number\_limit.py](https://codecov.io/gh/astropy/ccdproc/pull/757/diff?src=pr&el=tree#diff-Y2NkcHJvYy90ZXN0cy9ydW5fd2l0aF9maWxlX251bWJlcl9saW1pdC5weQ==) | `74.22% <100.00%> (+0.54%)` | :arrow_up: |
| [ccdproc/tests/test\_combiner.py](https://codecov.io/gh/astropy/ccdproc/pull/757/diff?src=pr&el=tree#diff-Y2NkcHJvYy90ZXN0cy90ZXN0X2NvbWJpbmVyLnB5) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/astropy/ccdproc/pull/757?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/astropy/ccdproc/pull/757?src=pr&el=footer). Last update [6ee2f67...5d29929](https://codecov.io/gh/astropy/ccdproc/pull/757?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

mwcraig: @Yash-10 -- it is going to take me a day or two to review this one. `combine` and `Combiner` should still be able to take a list, and I had thought this would be a fairly small change. Hopefully I'll get a look at it on Saturday, otherwise Monday.

In the meantime, can you please add yourself to the contributor list? 😃
Yash-10: Hello @mwcraig, thank you for your reply and sorry for my delayed response. As you have suggested, I have also added myself to the contributing list.

Thanks!
mwcraig: I had been thinking of this as a much more limited change, basically two things:

+ add a new test that calls `Combiner` with a generator instead of a list, and that *fails* with the code currently on the main branch. I like writing tests like that first when I get a bug report to make sure that the that the test detects the bug. 
+ Adding [this line](https://github.com/astropy/ccdproc/blob/a6f90de460df3dd6f45a4b605fe482523bfe8de9/ccdproc/combiner.py#L75) to `Combiner`. 

I *think* those two changes should be all that is necessary to fix the issue. It might be easier to open a new PR with just those changes to see if it works, though you could try undoing many of the changes here and keep working on it here.



Patch:
diff --git a/AUTHORS.rst b/AUTHORS.rst
index aaf3470..f067a45 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -56,6 +56,7 @@ Alphabetical list of contributors
 * Nathan Walker (@walkerna22)
 * Benjamin Weiner (@bjweiner)
 * Jiyong Youn (@hletrd)
+* Yash Gondhalekar (@Yash-10)
 
 (If you have contributed to the ccdproc project and your name is missing,
 please send an email to the coordinators, or
diff --git a/CHANGES.rst b/CHANGES.rst
index 1d9ac18..d21f3a1 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -16,6 +16,8 @@ Bug Fixes
 - ``test_image_collection.py`` in the test suite no longer produces
  permanent files on disk and cleans up after itself. [#738]
 
+- Change ``Combiner`` to allow accepting either a list or a generator [#757]
+
 2.1.0 (2019-12-24)
 ------------------
 
diff --git a/ccdproc/combiner.py b/ccdproc/combiner.py
index 2e6eefc..39f3e28 100644
--- a/ccdproc/combiner.py
+++ b/ccdproc/combiner.py
@@ -22,8 +22,8 @@ class Combiner:
 
     Parameters
     -----------
-    ccd_list : list
-        A list of CCDData objects that will be combined together.
+    ccd_iter : list or generator
+        A list or generator of CCDData objects that will be combined together.
 
     dtype : str or `numpy.dtype` or None, optional
         Allows user to set dtype. See `numpy.array` ``dtype`` parameter
@@ -33,7 +33,7 @@ class Combiner:
     Raises
     ------
     TypeError
-        If the ``ccd_list`` are not `~astropy.nddata.CCDData` objects, have different
+        If the ``ccd_iter`` are not `~astropy.nddata.CCDData` objects, have different
         units, or are different shapes.
 
     Examples
@@ -56,15 +56,18 @@ class Combiner:
                  [ 0.66666667,  0.66666667,  0.66666667,  0.66666667],
                  [ 0.66666667,  0.66666667,  0.66666667,  0.66666667]])
     """
-    def __init__(self, ccd_list, dtype=None):
-        if ccd_list is None:
-            raise TypeError("ccd_list should be a list of CCDData objects.")
+    def __init__(self, ccd_iter, dtype=None):
+        if ccd_iter is None:
+            raise TypeError("ccd_iter should be a list or a generator of CCDData objects.")
 
         if dtype is None:
             dtype = np.float64
 
         default_shape = None
         default_unit = None
+
+        ccd_list = list(ccd_iter)
+
         for ccd in ccd_list:
             # raise an error if the objects aren't CCDData objects
             if not isinstance(ccd, CCDData):


Test patch:
diff --git a/ccdproc/tests/test_combiner.py b/ccdproc/tests/test_combiner.py
index a9988d3..b758c66 100644
--- a/ccdproc/tests/test_combiner.py
+++ b/ccdproc/tests/test_combiner.py
@@ -696,3 +696,13 @@ def test_ystep_calculation(num_chunks, expected):
 
     xstep, ystep = _calculate_step_sizes(2000, 2000, num_chunks)
     assert xstep == expected[0] and ystep == expected[1]
+
+def test_combiner_gen():
+    ccd_data = ccd_data_func()
+    def create_gen():
+        yield ccd_data
+        yield ccd_data
+        yield ccd_data
+    c = Combiner(create_gen())
+    assert c.data_arr.shape == (3, 100, 100)
+    assert c.data_arr.mask.shape == (3, 100, 100)