Skip to content

Commit

Permalink
0.4.19 release notes (#3)
Browse files Browse the repository at this point in the history
* fix base branch

* Initial patches 0.4.19 release

* undo commit

* precommit fix

* add patch files

* update for generate release notes

* allow select unmerged PR

* add option to skip commits that requires separate PR to cherry pick

* run pre-commit

* Update highlight/0.4.19.md

Co-authored-by: Wouter-Michiel Vierdag <[email protected]>

* Update highlight/0.4.19.md

Co-authored-by: Lorenzo Gaifas <[email protected]>

* Apply suggestions from code review

Co-authored-by: Peter Sobolewski <[email protected]>

* docs cherry picking

* try github format

* fix trailing spaces

* add new patches

* fix link to webpage

* update patches

* docs cherry-pick

* again rebase

* update highlight

* add patches

* add docs pataches

* Add patch files

* fix generate release notes script

* add patch files

* Add #6102 as a feature highlight (#4)

* add 6102 as a feature highlight

* copy edits

Co-authored-by: Melissa Weber Mendonça <[email protected]>

* fix pr link

---------

Co-authored-by: Melissa Weber Mendonça <[email protected]>

* word wrap in highlight, add one pr to performance sequence

* Apply suggestions from code review

Co-authored-by: Lorenzo Gaifas <[email protected]>

* Full rewrite of highlights section

This ensures it is now dripping with enthusiasm (much deserved) =P

* Add API break note

* update script to alow multiple notes

* filter out mentioned PR

* Add deprecations and api changes notes

* fix pre-commit

* last changes before merge

---------

Co-authored-by: wmv_hpomen <[email protected]>
Co-authored-by: Lorenzo Gaifas <[email protected]>
Co-authored-by: Peter Sobolewski <[email protected]>
Co-authored-by: Melissa Weber Mendonça <[email protected]>
Co-authored-by: Juan Nunez-Iglesias <[email protected]>
  • Loading branch information
6 people authored Feb 1, 2024
1 parent 64d9ed9 commit 49143c4
Show file tree
Hide file tree
Showing 111 changed files with 47,641 additions and 25 deletions.
9 changes: 6 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0 # Use the ref you want to point at
rev: v4.5.0 # Use the ref you want to point at
hooks:
- id: trailing-whitespace
exclude: patch_dir
- id: check-toml
- id: end-of-file-fixer
exclude: patch_dir
- id: check-yaml
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 23.7.0
rev: 23.10.1
hooks:
- id: black
pass_filenames: true
exclude: _vendor|vendored|examples
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.284
rev: v0.1.3
hooks:
- id: ruff
exclude: _vendor|vendored
args: [--output-format, github]
14 changes: 14 additions & 0 deletions additional_notes/0.4.19/api changes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

[#6102](https://github.com/napari/napari/pull/6102) added the ability to set
linear colormaps from black to a named color by using `colormap="color-name"`
syntax. It turns out that "orange" is both the name of a
white-to-orange colormap in VisPy, and one of the color names in the color
dictionary, therefore implicitly a *black-to-orange* colormap! We decided to use
the new, color-name behavior in this update. So if you are wondering why your
`imshow(data, colormap='orange')` calls look different — this is why.

In [#6178](https://github.com/napari/napari/pull/6178), the "action" type of
events emitted when editing Shapes or Points was changed to be more granular.
The types are no longer "add", "remove", and "change", but "adding", "added",
"removing", "removed", "changing", and "changed". This gives listeners more
control over when to take action in response to an event.
21 changes: 21 additions & 0 deletions additional_notes/0.4.19/deprecations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[#6542](https://github.com/napari/napari/pull/6542) made a number of
deprecations to the Labels API to simplify it. Rather than having color-related
properties strewn all over the layer, color control is moved strictly to the
layer's `colormap`. Here is the full list of deprecated attributes and their
replacements:

- num_colors: `layer.num_colors` becomes `len(layer.colormap)`.
`layer.num_colors = n` becomes `layer.colormap = label_colormap(n)`.
- `napari.utils.colormaps.LabelColormap` is deprecated and has been renamed to
`napari.utils.colormaps.CyclicLabelColormap`.
- color: `layer.color` becomes `layer.colormap.color_dict`.
`layer.color = color_dict` becomes
`layer.colormap = DirectLabelColormap(color_dict)`.
- _background_label: `layer._background_label` is now at
`layer.colormap.background_value`.
- color_mode: `layer.color_mode` is set by setting the colormap using the
corresponding colormap type (`CyclicLabelColormap` or `DirectLabelColormap`;
these classes can be imported from `napari.utils.colormaps`.).
- `seed`: was only used for shifting labels around in [0, 1]. It is
superseded by `layer.new_colormap()` which was implemented in
[#6460](https://github.com/napari/napari/pull/6460).
109 changes: 109 additions & 0 deletions additional_notes/0.4.19/highlights.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
This release mostly contains a lot of bug fixes and performance improvements.
But look out for 0.5.0, coming to a software repository near you — we expect to
release a lot of new features then!

### BIG improvements to the Labels layer

[#3308](https://github.com/napari/napari/pull/3308) closed *many* long-standing
bugs in the handling of colors in the Labels layer: the color swatch in the
Labels controls now always matches the color on the canvas, direct color
mapping with thousands of colors works fine, and shuffling colors (when two
touching labels coincidentally had the same color) is now much more likely to
map them to different colors. 🎨🚀🚀🚀

Unfortunately, the fix turned out to have rather
terrible consequences for the rendering performance of 3D Labels, and each time
we fixed one thing something else reappeared in a game of bug fix whack-a-mole
that any programmer would recognize. A great many
fixes later (
[#6411](https://github.com/napari/napari/pull/6411),
[#6439](https://github.com/napari/napari/pull/6439),
[#6459](https://github.com/napari/napari/pull/6459),
[#6460](https://github.com/napari/napari/pull/6460),
[#6461](https://github.com/napari/napari/pull/6461),
[#6467](https://github.com/napari/napari/pull/6467),
[#6479](https://github.com/napari/napari/pull/6479),
[#6520](https://github.com/napari/napari/pull/6520),
[#6540](https://github.com/napari/napari/pull/6540),
[#6571](https://github.com/napari/napari/pull/6571),
[#6580](https://github.com/napari/napari/pull/6580),
[#6596](https://github.com/napari/napari/pull/6596),
[#6602](https://github.com/napari/napari/pull/6602),
[#6607](https://github.com/napari/napari/pull/6607),
[#6616](https://github.com/napari/napari/pull/6616),
[#6618](https://github.com/napari/napari/pull/6618)
) — thank you for your patience! 😅 — Labels are faster than ever
*and* color accurate. *But*, to get the best performance, if you can use
8- or 16-bit integers as your data type, you should do so, and if not, you
should install *numba*, a just-in-time compiler for numerical code in Python.
(Ultimately, the data sent to the GPU will be 8- or 16-bit, so if you use a
larger data type, you will pay some conversion cost.)

These improvements in color handling are accompanied by updates to the Labels
API. You can now easily set a specific color cycle for Labels data. For
example, to use the famous [Glasbey look-up table/color
cycle](https://onlinelibrary.wiley.com/doi/10.1002/col.20327), you can combine
the [`glasbey`](https://pypi.org/project/glasbey/) Python package with the new
`CyclicLabelColormap` API:

```python
import glasbey
from napari.utils.colormaps import CyclicLabelColormap
# ...
labels_layer = viewer.add_labels(
segmentation, colormap=CyclicLabelColormap(glasbey.create_palette(256))
)
```

See the ["Deprecations" section below](#Deprecations) for more information on
the new API. ([#6542](https://github.com/napari/napari/pull/6542))

### More on colormaps!

Yes, this is the colors update! 🌈

Making image layers with linear colormaps using custom colors is easier than
ever! You can just do `viewer.add_image(data, color='turquoise')` to get a
black-to-turquoise linear colormap for that image. For the full list of colors
available, see the
[VisPy color dict](https://github.com/vispy/vispy/blob/269ed1ac4d8126421fd5a7eb06a2996d63f46b17/vispy/color/_color_dict.py#L181)
([#6102](https://github.com/napari/napari/pull/6102)). You can also pass in an
RGB hex color prefixed with `#`, as in
`napari.imshow(data, colormap=`#88ff1a`)`.

(For an amusing side note, though, check out the [API Changes](#api-changes)
note related to this PR. 😅)

### Some technical stuff

If you were worried about those pesky "public access to `qt_viewer` will be
removed" warnings, fret not! Its removal has been postponed until at least
0.6.0! We want to spend more time working with the community to ensure your
use case is supported before pulling out the rug. 🤝 If you are using the
`qt_viewer` because we don't have another public API to do what you need,
please [raise an issue](https://github.com/napari/napari/issues/new) so we can
make sure your use case is supported before we remove it.
([#6283](https://github.com/napari/napari/pull/6283))

Finally, although we still use pydantic 1.0 objects internally, napari
installs correctly with both pydantic v1 and pydantic v2. If you wanted to
upgrade your napari library or plugin to use Pydantic 2, now you can!

Note though, for 0.4.19, the napari bundled app still ships with Pydantic 1.x.
However, we will bundle v2 starting with 0.5.0, so if you use Pydantic
internally, now is a good time to check that you are compatible either v2 or
both v1 and v2
([#6358](https://github.com/napari/napari/pull/6358)).

### Onwards!

As always, napari is developed by the community, for the community. We want to
hear from you and help you get your napari visualization and/or plugin use done
faster! And if napari is missing something you need, we can help you add it! So
please remember to ask [questions on
image.sc](https://forum.image.sc/tag/napari), join our [Zulip chat
room](https://napari.zulipchat.com/), come to our [community
meetings](https://napari.org/stable/community/meeting_schedule.html), or [tag
us on Mastodon](https://fosstodon.org/@napari)!

Read on for the full list of changes that went into this release.
24 changes: 19 additions & 5 deletions cherry_pick_process.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# PYTHON_ARGCOMPLETE_OK
"""
This is script to cherry-pick commits base on PR labels
"""
Expand All @@ -7,6 +8,7 @@
import os
from pathlib import Path

import argcomplete
from git import GitCommandError, Repo
from tqdm import tqdm

Expand All @@ -31,9 +33,7 @@ def main():
parser.add_argument(
"--first-commits", help="file with list of first commits to cherry pick"
)
parser.add_argument(
"--stop-after", help="Stop after this commit", default=0, type=int
)
parser.add_argument("--stop-after", help="Stop after this PR", default=0, type=int)
parser.add_argument(
"--git-main-branch",
help="The git main branch",
Expand All @@ -43,7 +43,14 @@ def main():
parser.add_argument(
"--working-dir", help="path to repository", default=LOCAL_DIR, type=Path
)
parser.add_argument(
"--skip-commits",
nargs="+",
help="list of commits to skip as they are already cherry-picked",
type=int,
)

argcomplete.autocomplete(parser)
args = parser.parse_args()

target_branch = f"v{args.milestone}x"
Expand All @@ -62,6 +69,7 @@ def main():
stop_after=args.stop_after,
base_branch=args.base_branch,
main_branch=args.git_main_branch,
skip_commits=args.skip_commits,
)


Expand Down Expand Up @@ -94,6 +102,7 @@ def perform_cherry_pick(
stop_after: int | None,
base_branch: str,
main_branch: str = "main",
skip_commits: list[int] = None,
):
"""
Perform cherry-pick process
Expand All @@ -115,6 +124,8 @@ def perform_cherry_pick(
main_branch: str
the main branch of repository, by default is ``main``
but could be for example ``master``
skip_commits: list[int]
list of commits to skip as they are already cherry-picked
Returns
-------
Expand All @@ -140,14 +151,17 @@ def perform_cherry_pick(
if x.milestone == milestone
]

pr_commits_dict = get_pr_commits_dict(repo, base_branch)
pr_commits_dict = get_pr_commits_dict(repo, main_branch)
consumed_pr = get_consumed_pr(repo, target_branch)

if skip_commits:
consumed_pr.update(skip_commits)

# check for errors, may require to reset cache if happens
for el in pr_targeted_for_release:
assert el.closed_at is not None, el

# order PR by merge date, move "first_commits" on begin
# order PR by merge date, move "first_commits" to begin
# (by default PR are ordered by creation date)
pr_list_base = sorted(
pr_targeted_for_release,
Expand Down
7 changes: 4 additions & 3 deletions docs_cherry_pick.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
from tqdm import tqdm

from release_utils import (
PR_NUM_PATTERN,
REPO_DIR_NAME,
get_milestone,
iter_pull_request,
pr_num_pattern,
setup_cache,
)

Expand Down Expand Up @@ -44,7 +45,7 @@ def get_consumed_pr():
base = repo.merge_base(f"docs_{milestone.title}", f"v{milestone.title}x")

for commit in repo.iter_commits(f"{base[0].binsha.hex()}..docs_{milestone.title}"):
if (match := pr_num_pattern.search(commit.message)) is not None:
if (match := PR_NUM_PATTERN.search(commit.message)) is not None:
pr_num = int(match[1])
res.add(pr_num)
return res
Expand All @@ -67,7 +68,7 @@ def get_consumed_pr():
patch_dir_path.mkdir()


repo = Repo(LOCAL_DIR / "napari_repo")
repo = Repo(LOCAL_DIR / REPO_DIR_NAME)
repo.git.checkout(f"docs_{milestone.title}")


Expand Down
38 changes: 33 additions & 5 deletions generate_release_notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@
help="The file with the corrections",
default=LOCAL_DIR / "name_corrections.yaml",
)
parser.add_argument(
"--with-pr",
help="Include PR numbers for not merged PRs",
type=int,
default=None,
nargs="+",
)

args = parser.parse_args()

Expand Down Expand Up @@ -113,9 +120,8 @@ def add_to_users(users_dkt, new_user):
}


for pull in iter_pull_request(f"milestone:{args.milestone} is:merged"):
issue = pull.as_issue()
assert pull.merged
def parse_pull(pull):
assert pull.merged or pull.number in args.with_pr

commit = repo.get_commit(pull.merge_commit_sha)

Expand Down Expand Up @@ -143,6 +149,14 @@ def add_to_users(users_dkt, new_user):
other_pull_requests[pull.number] = {"summary": summary, "repo": GH_REPO}


for pull_ in iter_pull_request(f"milestone:{args.milestone} is:merged"):
parse_pull(pull_)

if args.with_pr is not None:
for pr_num in args.with_pr:
pull = repo.get_pull(pr_num)
parse_pull(pull)

for pull in iter_pull_request(
f"milestone:{args.milestone} is:merged", repo=GH_DOCS_REPO
):
Expand Down Expand Up @@ -181,6 +195,7 @@ def add_to_users(users_dkt, new_user):


user_name_pattern = re.compile(r"@([\w-]+)") # pattern for GitHub usernames
pr_number_pattern = re.compile(r"#(\d+)") # pattern for GitHub PR numbers

old_contributors = set()

Expand Down Expand Up @@ -214,17 +229,30 @@ def add_to_users(users_dkt, new_user):
print(
"""
For more information, examples, and documentation, please visit our website:
https://github.com/napari/napari
https://napari.org/stable/
""",
file=file_handle,
)

for section, pull_request_dicts in highlights.items():
print(f"## {section}\n", file=file_handle)
section_path = (
LOCAL_DIR / "additional_notes" / args.milestone / f"{section.lower()}.md"
)
mentioned_pr = set()
if section_path.exists():
with section_path.open() as f:
text = f.read()
for pr_number in pr_number_pattern.findall(text):
mentioned_pr.add(int(pr_number))
print(text, file=file_handle)

for number, pull_request_info in pull_request_dicts.items():
if number in mentioned_pr:
continue
repo_str = pull_request_info["repo"]
print(
f'- {pull_request_info["summary"]} ([napari/{repo_str}/#{number}](https://{GH}/{GH_USER}/{repo_str}/pull/{number}))',
f'- {pull_request_info["summary"]} ([napari/{repo_str}#{number}](https://{GH}/{GH_USER}/{repo_str}/pull/{number}))',
file=file_handle,
)
print("", file=file_handle)
Expand Down
Loading

0 comments on commit 49143c4

Please sign in to comment.