Skip to content

BUG: Preserve mask in Time.insert for masked values - #20232

Open
taldcroft wants to merge 5 commits into
astropy:mainfrom
taldcroft:time-fix-insert-masked-after-20178
Open

BUG: Preserve mask in Time.insert for masked values#20232
taldcroft wants to merge 5 commits into
astropy:mainfrom
taldcroft:time-fix-insert-masked-after-20178

Conversation

@taldcroft

Copy link
Copy Markdown
Member

Description

Time.insert silently dropped the mask, exposing values that should have stayed hidden. This is also reachable from Table.add_row on a Time column (see #20230).

This PR upgrades the output to Masked when self is masked, using the TimeFormat._convert_to_masked helper added in #20178, and use np.asanyarray so a Masked input keeps its mask.

Fixes #20230

Important

This is stacked on #20178 — so that needs to be merged first. The diff here is a single commit;
the extra commits shown are #20178's.

AI disclosure

This PR was initially created using Claude Opus 5, but I then edited the tests a fair bit to my liking. I understand all the changes and they match what I would have done (just more slowly).

  • By checking this box, the PR author has requested that maintainers do NOT use the "Squash and Merge" button. Maintainers should respect this when possible; however, the final decision is at the discretion of the maintainer that merges the PR.

Mohit-Ak and others added 4 commits July 31, 2026 02:17
Time.__setitem__ wrote the value's jd1/jd2 straight into the target's
plain ndarrays, so if the target was not yet masked the incoming mask
was dropped and the masked rows showed their underlying values again.
Upgrade jd1/jd2 to Masked first when the value is masked, mirroring what
setting np.ma.masked already does.

This is what made table vstack lose the mask on Time mixin columns: it
builds the output with TimeInfo.new_like (unmasked) and then fills it
via setitem.

Fixes astropy#20173
@taldcroft taldcroft added this to the v7.2.3 milestone Aug 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

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?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for rebase and squash.
  • 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.
  • 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.

@mhvk mhvk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! A suggestion to make it simpler still.

Comment thread astropy/time/core.py
# case of a string input that has a length which is not the length we want).
if not isinstance(values, self.__class__):
values = np.asarray(values)
# asanyarray, not asarray, so that a Masked input keeps its mask.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How often have I asked this over at numpy, only to find it in our own code! Nice that it is so simple, though!

Comment thread astropy/time/core.py Outdated
[self], len(self) + n_values, name=self.info.name
)

# ``new_like`` always makes an unmasked object, so if self is masked then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative is to rely on Time.__setitem__, which will now do this for you, i.e.,

out[:idx0] = self[:idx0]

(and same further down). It would be slightly slower (but only slightly), but definitely clearer.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, good idea.

@pllim

pllim commented Aug 11, 2026

Copy link
Copy Markdown
Member

Hmm this is milestoned for backport but #20178 is not. So which milestone is correct?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Time.insert drops the mask

4 participants