Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6c23a64
Change readin for to_fits roundtrip (#1521)
Nschanche Jan 22, 2026
a19323d
Update CHANGES.rst
Nschanche Jan 22, 2026
f25b2c2
fix 3_12 test name (#1539)
Nschanche Feb 12, 2026
b705426
Changed search - no longer emits a ERROR log message for empty result…
orionlee Feb 23, 2026
5348404
Update CHANGES.rst
Nschanche Feb 23, 2026
3431579
Ensure search by TIC for TICs with < 9 digits is done by correct exac…
orionlee Feb 25, 2026
e0dc224
Update CHANGES.rst
Nschanche Feb 25, 2026
92758ea
testing SAP_QUALITY FIX (#1538)
rebekah9969 Mar 4, 2026
0188a0c
allow fast CBVs (#1537)
Nschanche Mar 4, 2026
23a4b57
Update LightCurve docs to address MaskedQuantities (#1533)
d-giles Mar 4, 2026
20a7e71
Update CHANGES.rst
Nschanche Mar 4, 2026
1dc4f10
fix for issue 1546 - added ipython in toml dev (#1548)
rebekah9969 Mar 18, 2026
a916fc3
add support for nifty-ls (#1550)
keatonb Apr 1, 2026
f5f3a90
Update CHANGES.rst
Nschanche Apr 1, 2026
64260c8
added new tutorial to help users with to_fits and read_generic_lightc…
rebekah9969 Apr 15, 2026
24fa84b
Update CHANGES.rst
Nschanche Apr 15, 2026
757d503
Add support for generic FITS light curves (JDREF, etc.) (#1535)
adrianlucy Apr 16, 2026
efb1188
Update CHANGES.rst
Nschanche Apr 16, 2026
7db4dd9
Update pyproject.toml
Nschanche Apr 16, 2026
3d79898
Update version.py
Nschanche Apr 16, 2026
0143ab2
Update pyproject.toml
Nschanche Apr 16, 2026
4593381
Update CHANGES.rst
Nschanche Apr 16, 2026
f5c3f9f
Update version.py
Nschanche Apr 16, 2026
aad9150
Fixed SearchResult sort order for TESS sectors 99 + 100, etc. (#1558)
orionlee May 4, 2026
740dfed
Update CHANGES.rst
Nschanche May 4, 2026
518b3e9
Update URL (#1556)
Nschanche May 27, 2026
f663a72
Update CHANGES.rst
Nschanche May 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lightkurve-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
- name: "3.11"
python-version: "3.11"
pytest-command: ./poetry/bin/poetry run pytest
- name: "3.12-remote-data"
- name: "3.12"
python-version: "3.12"
pytest-command: ./poetry/bin/poetry run pytest
- name: "3.13"
Expand Down
17 changes: 16 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
2.5.2dev (unreleased)
2.6.1dev
=====================
- Update search URL for query_solar_system_objects [#1556]
- Fixed search result sort order for the cases involving TESS sectors 99 and 100, etc. [#1558]

2.6.0 (2026-04-16)
=====================
- Patch for changes to astroquery 0.4.11. Search results using GAIA DR2 now case insensitive. Integer searches converted to string. [#1511]
- Added Folded lightcurve reader to open data saved with ``lk.FoldedLightCurve.to_fits()`` [#1488]
Expand All @@ -7,8 +12,18 @@
- Include MOM_CENTR1 and MOM_CENTR2, if it exists, when saving fits files [#1488]
- Fixed bugs in ``bin`` for ``flux_err`` column. Improved ``bin`` performance. [#1499]
- Updated search result sort order [#1384]
- When reading in data saved with to_fits, change meta.flux_origin to reflect origin [#1371]
- Convert flux and flux_err to Quantity objects when using ``select_flux`` [#1513]
- Fixed bugs in ``FoldedLightCurve`` objects with normalized phase to support pickle / dill [#1529]
- Added support in ``read_generic_lightcurve()`` for FITS Standard reference time keywords like [M]JDREF [#1535]
- Capped pandas version at <3.0.0 for breaking changes [#1534]
- Added ability to download 20-s CBV products for TESS [#1537]
- Changed search so that it longer emits ERROR log message when the search result is empty [#1540]
- Fixed search by exact match for TICs with fewer than 9 digits, avoiding the extra
fallback cone search [#1541]
- Modified how SAP_QUALITY is treated when reading/writing TESS and Kepler data [#1538]
- Added ability to use nifty-ls for periodograms [#1550]
- Added new tutorial for read_generic_lightcurve [#1542]

2.5.1 (2025-05-20)
=====================
Expand Down

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "lightkurve"
version = "2.5.2dev"
version = "2.6.1dev"
description = "A friendly package for Kepler & TESS time series analysis in Python."
license = "MIT"
authors = ["Geert Barentsen <hello@geert.io>", "TESS Science Support Center <tesshelp@bigbang.gsfc.nasa.gov>"]
Expand Down Expand Up @@ -36,7 +36,7 @@ beautifulsoup4 = ">=4.6.0"
requests = ">=2.22.0"
urllib3 = { version = ">=1.23", python = ">=3.8,<4.0" } # necessary to make requests work on py310
tqdm = ">=4.25.0"
pandas = ">=1.3.6"
pandas = ">=1.3.6, <3.0.0"
uncertainties = ">=3.1.4"
patsy = ">=0.5.0"
fbpca = ">=1.0"
Expand Down Expand Up @@ -81,6 +81,7 @@ mistune = "<2.0.0" # Workaround for #1162 (not a true dependency)
# See https://github.com/python-poetry/poetry/issues/9293
docutils = "!=0.21"
lxml-html-clean = "^0.4.2"
ipython = ">=7.0"

[build-system]
requires = ["poetry-core"]
Expand Down
24 changes: 18 additions & 6 deletions src/lightkurve/correctors/cbvcorrector.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class CBVCorrector(RegressionCorrector):
"""

def __init__(self, lc, interpolate_cbvs=False, extrapolate_cbvs=False, do_not_load_cbvs=False,
cbv_dir=None):
cbv_dir=None, fast_cadence=False):
"""Constructor

This constructor will retrieve all relevant CBVs from MAST and then
Expand All @@ -120,6 +120,8 @@ def __init__(self, lc, interpolate_cbvs=False, extrapolate_cbvs=False, do_not_lo
cbv_dir : str
Path to specific directory holding TESS CBVs. If this is None, will query
MAST by default.
fast_cadence : bool
If True, then the 20-s fast cadence CBV file will be loaded
"""
if not isinstance(lc, LightCurve):
raise Exception('<lc> must be a LightCurve class')
Expand All @@ -129,6 +131,11 @@ def __init__(self, lc, interpolate_cbvs=False, extrapolate_cbvs=False, do_not_lo

if extrapolate_cbvs and (extrapolate_cbvs != interpolate_cbvs):
raise Exception('interpolate_cbvs must be True if extrapolate_cbvs is True')

# Check if the lightkurve has 20-s cadence.
if hasattr(lc, 'filename'):
if 'fast' in lc.filename:
fast_cadence = True

# We do not want any NaNs
lc = lc.remove_nans()
Expand All @@ -151,7 +158,7 @@ def __init__(self, lc, interpolate_cbvs=False, extrapolate_cbvs=False, do_not_lo
# For TESS we load multiple CBV types
# Single-Scale
cbvs.append(load_tess_cbvs(cbv_dir=cbv_dir,sector=self.lc.sector,
camera=self.lc.camera, ccd=self.lc.ccd, cbv_type='SingleScale'))
camera=self.lc.camera, ccd=self.lc.ccd, cbv_type='SingleScale', fast_cadence=fast_cadence))

# Multi-Scale
# Although there has always been 3 bands, there could be more,
Expand All @@ -162,15 +169,15 @@ def __init__(self, lc, interpolate_cbvs=False, extrapolate_cbvs=False, do_not_lo
iBand += 1
cbvObj = load_tess_cbvs(cbv_dir=cbv_dir,sector=self.lc.sector,
camera=self.lc.camera, ccd=self.lc.ccd, cbv_type='MultiScale',
band=iBand)
band=iBand, fast_cadence=fast_cadence)
if (cbvObj.band == iBand):
cbvs.append(cbvObj)
else:
moreData = False

# Spike
cbvs.append(load_tess_cbvs(cbv_dir=cbv_dir,sector=self.lc.sector,
camera=self.lc.camera, ccd=self.lc.ccd, cbv_type='Spike'))
camera=self.lc.camera, ccd=self.lc.ccd, cbv_type='Spike', fast_cadence=fast_cadence))

else:
raise ValueError('Unknown mission type')
Expand Down Expand Up @@ -1837,7 +1844,7 @@ def download_tess_cbvs(*args, **kwargs):


def load_tess_cbvs(cbv_dir=None,sector=None, camera=None,
ccd=None, cbv_type='SingleScale', band=None):
ccd=None, cbv_type='SingleScale', band=None, fast_cadence=False):
"""Loads TESS cotrending basis vectors, either from a directory of
CBV files already saved locally if cbv_dir is passed, or else
will retrieve the relevant files programmatically from MAST.
Expand All @@ -1863,6 +1870,8 @@ def load_tess_cbvs(cbv_dir=None,sector=None, camera=None,
'SingleScale' or 'MultiScale' or 'Spike'
band : int
Multi-scale band number
fast_cadence : bool
'True' to get 20-s cadence CBVs. If False, defaults to the 2-min CBV file.

Returns
-------
Expand Down Expand Up @@ -1934,7 +1943,10 @@ def load_tess_cbvs(cbv_dir=None,sector=None, camera=None,

else:
curlBaseUrl = 'https://archive.stsci.edu/missions/tess/download_scripts/sector/tesscurl_sector_'
curlEndUrl = '_cbv.sh'
if fast_cadence:
curlEndUrl = '_fast-cbv.sh'
else:
curlEndUrl = '_cbv.sh'
curlUrl = curlBaseUrl + str(sector) + curlEndUrl

# This is the string to search for in the curl script file
Expand Down
36 changes: 33 additions & 3 deletions src/lightkurve/io/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,29 @@ def read_generic_lightcurve(
log.debug("Ignoring {} rows with NaN times".format(np.sum(nans)))
tab = tab[~nans]

# Set default reference time value to 0.0
reference_time_value = 0.0

# Prepare a special time column
if not time_format:
# Check for the Kepler and TESS special cases
if hdulist[ext].header.get("BJDREFI") == 2454833: # Kepler specific
time_format = "bkjd"
elif hdulist[ext].header.get("BJDREFI") == 2457000: # TESS specific
time_format = "btjd"
# Work through options from the FITS Standard v4.0 Section 9.2.2
elif ("MJDREFI" in hdulist[ext].header) and ("MJDREFF" in hdulist[ext].header): # Check if MJDREFI and MJDREFF set
time_format = "mjd"
reference_time_value = hdulist[ext].header.get("MJDREFI") + hdulist[ext].header.get("MJDREFF")
elif "MJDREF" in hdulist[ext].header: # Check if MJDREF set
time_format = "mjd"
reference_time_value = hdulist[ext].header.get("MJDREF")
elif ("JDREFI" in hdulist[ext].header) and ("JDREFF" in hdulist[ext].header): # Check if JDREFI and JDREFF set
time_format = "jd"
reference_time_value = hdulist[ext].header.get("JDREFI") + hdulist[ext].header.get("JDREFF")
elif "JDREF" in hdulist[ext].header: # Check if JDREF set
time_format = "jd"
reference_time_value = hdulist[ext].header.get("JDREF")
# make compatible with normalized light curves without absolute start sime (see #1502)
elif hdulist[ext].header.get("TIMESYS") == "local":
try:
Expand All @@ -115,14 +132,19 @@ def read_generic_lightcurve(
tab.remove_column("time")
except:
raise KeyError(f"Unclear unit for local time system: TUNIT1 must be astropy.unit value.") # Error handling for invalid astropy.unit value or if the TUNIT1 keyword is missing from header

# Check for nonstandard, format-flavored values of TIMESYS
elif hdulist[ext].header.get("TIMESYS") == "mjd":
time_format = 'mjd'
elif hdulist[ext].header.get("TIMESYS") == "jd":
time_format = 'jd'
# Raise error if reference time (or related variants) not found
else:
raise ValueError(f"Input file has unclear time format: {filename}")
raise ValueError(f"No reference time found in {filename}. Pass in a common time_format manually, or edit the FITS header.")
if 'time' not in locals():
if (tab["time"].unit is not None) and (tab["time"].unit != u.d) and (type(tab["time"].unit) is not u.UnrecognizedUnit):
# If time column is in a recognized unit other than days...
tab["time"] = tab["time"].to(u.d, copy=False) # ...convert to days.
tab["time"] += reference_time_value # Add reference time to the time column values
time = Time(
tab["time"].data,
scale=hdulist[ext].header.get("TIMESYS", "tdb").lower(),
Expand Down Expand Up @@ -156,7 +178,15 @@ def read_generic_lightcurve(
tab.meta["RA"] = hdulist[0].header.get("RA_OBJ")
tab.meta["DEC"] = hdulist[0].header.get("DEC_OBJ")
tab.meta["FILENAME"] = filename
tab.meta["FLUX_ORIGIN"] = flux_column
# issue 1371 -
# When reading in a file saved with to_fits, the flux source is not known
# We could save the flux_origin keyword, but that is an incomplete story,
# as we don't know if other manipulation (like detrending) also occurred
# So, we populate the 'FLUX_ORIGIN' meta data with 'to_fits' to contain that ambiguity
if ("CREATOR" in hdulist[0].header) and (hdulist[0].header["CREATOR"] == 'lightkurve.LightCurve.to_fits()'):
tab.meta["FLUX_ORIGIN"] = "lightkurve.LightCurve.to_fits()"
else:
tab.meta["FLUX_ORIGIN"] = flux_column

return LightCurve(time=time, data=tab)
finally:
Expand Down
7 changes: 7 additions & 0 deletions src/lightkurve/io/kepler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from .generic import read_generic_lightcurve

import numpy as np


def read_kepler_lightcurve(
filename, flux_column="pdcsap_flux", quality_bitmask="default"
Expand Down Expand Up @@ -38,6 +40,11 @@ def read_kepler_lightcurve(
time_format="bkjd",
)

#RAH - To allow generic lightcurves to be read by Kepler read we need to add this work around
if "sap_quality" not in lc.columns:
lc['sap_quality'] = np.zeros(len(lc['time']), dtype=int)


# Filter out poor-quality data
# NOTE: Unfortunately Astropy Table masking does not yet work for columns
# that are Quantity objects, so for now we remove poor-quality data instead
Expand Down
6 changes: 6 additions & 0 deletions src/lightkurve/io/tess.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from .generic import read_generic_lightcurve

import numpy as np


def read_tess_lightcurve(
filename, flux_column="pdcsap_flux", quality_bitmask="default", time_format="btjd",
Expand Down Expand Up @@ -32,6 +34,10 @@ def read_tess_lightcurve(
"""
lc = read_generic_lightcurve(filename, flux_column=flux_column, time_format=time_format)

#RAH - To allow generic lightcurves to be read by TESS read we need to add this work around
if "quality" not in lc.columns:
lc['quality'] = np.zeros(len(lc['time']), dtype=int)

# Filter out poor-quality data
# NOTE: Unfortunately Astropy Table masking does not yet work for columns
# that are Quantity objects, so for now we remove poor-quality data instead
Expand Down
Loading