diff --git a/news/releasebuilder.rst b/news/releasebuilder.rst new file mode 100644 index 000000000..cbebfabcf --- /dev/null +++ b/news/releasebuilder.rst @@ -0,0 +1,23 @@ +**Added:** + +* Add `ReleaseListBuilder` functionality, filter criteria + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* diff --git a/src/regolith/builder.py b/src/regolith/builder.py index 0cd1a8c18..b9cbeb403 100644 --- a/src/regolith/builder.py +++ b/src/regolith/builder.py @@ -18,6 +18,7 @@ from regolith.builders.publistbuilder import PubListBuilder from regolith.builders.readinglistsbuilder import ReadingListsBuilder from regolith.builders.reimbursementbuilder import ReimbursementBuilder +from regolith.builders.releaselistbuilder import ReleaseListBuilder from regolith.builders.resumebuilder import ResumeBuilder BUILDERS = { @@ -35,6 +36,7 @@ "postdocad": PostdocadBuilder, "preslist": PresListBuilder, "publist": PubListBuilder, + "releaselist": ReleaseListBuilder, "reading-lists": ReadingListsBuilder, "reimb": ReimbursementBuilder, "recent-collabs": RecentCollaboratorsBuilder, diff --git a/src/regolith/builders/releaselistbuilder.py b/src/regolith/builders/releaselistbuilder.py new file mode 100644 index 000000000..28eaaa749 --- /dev/null +++ b/src/regolith/builders/releaselistbuilder.py @@ -0,0 +1,77 @@ +"""Builder for software release lists.""" + +from regolith.builders.basebuilder import LatexBuilderBase +from regolith.fsclient import _id_key +from regolith.sorters import position_key +from regolith.stylers import month_fullnames, sentencecase +from regolith.tools import all_docs_from_collection, filter_software, group_member_ids + + +class ReleaseListBuilder(LatexBuilderBase): + """Build list of released software from database entries.""" + + btype = "releaselist" + needed_colls = ["groups", "people", "grants", "software", "contacts"] + + def construct_global_ctx(self): + """Constructs the global context.""" + super().construct_global_ctx() + gtx = self.gtx + rc = self.rc + gtx["people"] = sorted( + all_docs_from_collection(rc.client, "people"), + key=position_key, + reverse=True, + ) + gtx["contacts"] = sorted( + all_docs_from_collection(rc.client, "contacts"), + key=position_key, + reverse=True, + ) + gtx["grants"] = sorted(all_docs_from_collection(rc.client, "grants"), key=_id_key) + gtx["groups"] = sorted(all_docs_from_collection(rc.client, "groups"), key=_id_key) + gtx["software"] = sorted(all_docs_from_collection(rc.client, "software"), key=_id_key) + gtx["all_docs_from_collection"] = all_docs_from_collection + gtx["float"] = float + gtx["str"] = str + gtx["zip"] = zip + + def latex(self): + """Render latex template.""" + everybody = self.gtx["people"] + self.gtx["contacts"] + for group in self.gtx["groups"]: + grp = group["_id"] + grpmember_ids = group_member_ids(self.gtx["people"], grp) + for member in grpmember_ids: + if self.rc.people: + if member not in self.rc.people: + continue + progclean = filter_software(everybody, self.gtx["software"], member) + + if len(progclean) > 0: + progclean = sorted( + progclean, + key=lambda k: max(release["release_date"] for release in k["release"]), + reverse=True, + ) + outfile = "software-report-" + member + pi = [person for person in self.gtx["people"] if person["_id"] == member][0] + self.render( + "releaselist.tex", + outfile + ".tex", + pi=pi, + software=progclean, + sentencecase=sentencecase, + monthstyle=month_fullnames, + ) + self.env.trim_blocks = True + self.env.lstrip_blocks = True + # self.render( + # "releaselist.txt", + # outfile + ".txt", + # pi=pi, + # software=progclean, + # sentencecase=sentencecase, + # monthstyle=month_fullnames, + # ) + # self.pdf(outfile) diff --git a/src/regolith/exemplars.json b/src/regolith/exemplars.json index 51dc51246..00bcd6614 100644 --- a/src/regolith/exemplars.json +++ b/src/regolith/exemplars.json @@ -61,13 +61,6 @@ "title": "My Vision", "year": 2015 }, - "software": { - "_id": "unique-package-id", - "active": true, - "url": "https://github.com/diffpy/diffpy.utils", - "grants": ["dmref15", "SymPy-1.1"], - "groups": ["ergs"] - }, "citations": [ { "_id": "meurer2016sympy", @@ -2178,13 +2171,14 @@ "software": [ { "_id": "diffpy.utils", - "groups": ["xrd"], + "groups": ["aeinstein_grp"], "active": true, "org_name": "diffpy", "repo_name": "diffpy.utils", "platform_name": "Github", "grants": ["NSF Funding"], - "author": ["Simon Billinge", "Sanjoon Bob Lee", "Zhiming Xu", "Tieqiong Zhang"], + "program_description": "General utilities for analyzing diffraction data", + "author": ["Sanjoon Bob Lee", "Zhiming Xu", "Tieqiong Zhang", "ANTHONY SCOPATZ"], "release": [ { "major": 3, @@ -2193,10 +2187,10 @@ "release_type": "major", "release_date": "2025-10-25", "summary": "Python 3.14 and something else", - "changes": ["Deprecated python2 feature.", - "Changed to scikit-packaged standard.", - "Add some functionality.", - "Modify existing function to make convenient." + "changes": ["Deprecated Python 2 feature", + "Changed to scikit-packaged standard", + "Add some functionality", + "Modify existing function to make convenient" ], "release_id": "3.1.0" } @@ -2204,13 +2198,14 @@ }, { "_id": "diffpy.srxplanar", - "groups": ["billingegroup"], + "groups": ["aeinstein_grp"], "active": true, - "author": ["Xiaohao Yang", "Rundong Hua","Zhiming Xu", "Simon Billinge"], + "author": ["Xiaohao Yang", "Rundong Hua", "Zhiming Xu", "ANTHONY SCOPATZ"], "org_name": "diffpy", "repo_name": "diffpy.srxplanar", "platform_name": "Github", "grants": ["NSF Funding"], + "program_description": "2D diffraction image integration using non splitting pixel algorithm.", "release": [ { "major": 1, @@ -2237,13 +2232,22 @@ }, { "_id": "diffpy.distanceprinter", - "groups": ["billingegroup"], + "groups": [ + "aeinstein_grp" + ], "active": false, "org_name": "diffpy", "repo_name": "diffpy.distanceprinter", "platform_name": "Github", - "grants": ["NSF Funding"], - "author": ["Xiaohao Yang", "Dasun Abeykoon", "Simon Billinge"], + "grants": [ + "NSF Funding" + ], + "program_description": "Distance Printer, calculate the inter atomic distances. Part of xPDFsuite", + "author": [ + "Xiaohao Yang", + "Dasun Abeykoon", + "ANTHONY SCOPATZ" + ], "release": [ { "major": 0, @@ -2252,8 +2256,8 @@ "release_type": "minor", "release_date": "2025-10-26", "summary": "Python 3.14 and something else", - "changes": ["Change package to scikit-package level-5 standard."], - "release_id": "0.1.0" + "changes": ["Python 3.14 and something else"], + "release_id": "1.0.0" } ] } diff --git a/src/regolith/schemas.json b/src/regolith/schemas.json index 85817e32e..0df17585e 100644 --- a/src/regolith/schemas.json +++ b/src/regolith/schemas.json @@ -2956,6 +2956,11 @@ "required": true, "type": "list" }, + "program_description": { + "description": "The short description of the software.", + "required": true, + "type": "string" + }, "release": { "description": "The release information of the software.", "required": true, diff --git a/src/regolith/templates/releaselist.tex b/src/regolith/templates/releaselist.tex new file mode 100644 index 000000000..afa758726 --- /dev/null +++ b/src/regolith/templates/releaselist.tex @@ -0,0 +1,49 @@ +\documentclass[prl,tighten,amsmath,amssymb,floatfix]{revtex4-1} +\usepackage{graphicx} +\usepackage{times} +\usepackage{booktabs,dcolumn} +\usepackage{siunitx} +\usepackage[utf8]{inputenc} +\usepackage{xcolor} +\usepackage{hyperref} +\usepackage{enumitem} + +\begin{document} + +{% raw %} +\noindent +\colorbox{gray!40}{% + \begin{tabular*}{7in}{l@{\extracolsep{\fill}}r} +{% endraw %} + \textbf{\Large {{ latex_safe(pi['name']).upper() }}} & \textbf{\today} \\ + {{ latex_safe(pi['institution']) }} & {{ latex_safe(pi['email']) }} \\ +{% raw %} + \end{tabular*}% +}\vspace{1em} +{% endraw %} + +\textbf{Software Releaselist} + +\begin{enumerate} +{% for program in software %} + \item \textbf{\href{https://github.com/{{ latex_safe(program['org_name']) }}/{{ latex_safe(program['repo_name']) }}}{ {{- latex_safe(program['org_name']) -}}/{{- latex_safe(program['repo_name']) -}}}:}\\ + \hspace*{1em}{{ latex_safe(program['program_description']) }}\\ + \hspace*{1em}\textit{Authors: {{ latex_safe(', '.join(program.get('author', []))) }}}\\ + \hspace*{1em}Url: https://github.com/{{ latex_safe(program['org_name']) }}/{{ latex_safe(program['repo_name']) }}\\ + \hspace*{1em}\textbf{Releases:}\vspace{-0.5em} + \begin{itemize}[label={}] + {% for release in program['release'] %} + \item \textbf{ {{- latex_safe(release['release_id']) -}}:} {{ latex_safe(release['release_date']) }} + \begin{itemize}[label={}, leftmargin=2em] + {% if release.get('changes') %} + {% for change in release.get('changes', []) %} + \item {{ latex_safe(change) }} + {% endfor %} + \end{itemize} + {% endif %} + {% endfor %} + \end{itemize} +{% endfor %} +\end{enumerate} + +\end{document} diff --git a/src/regolith/tools.py b/src/regolith/tools.py index f4cb0aa57..fadc3c7b9 100644 --- a/src/regolith/tools.py +++ b/src/regolith/tools.py @@ -711,6 +711,137 @@ def filter_presentations( return presclean +def filter_software(people, software, target, types=None, since=None, before=None, active=None): + """Filters presentations for different types and date ranges. + + Parameters + ---------- + people: iterable of dicts + The people collection + software: iterable of dicts + The software collection + target: str + The id of the person you will build the list for + types: list of strings. Optional, default = all + The types to filter for. Allowed types are release_types. + since: date. Optional, default is None + The begin date to filter from + before: date. Optional, default is None + The end date to filter for. None does not apply this filter + statuses: list of str. Optional. Default is active. + The list of statuses to filter for. + """ + + if not types: + types = ["all"] + software = deepcopy(software) + + firstclean = [] + secondclean = [] + thirdclean = [] + fourthclean = [] + progclean = [] + + for program in software: + pauthors = program.get("author", []) + if isinstance(pauthors, str): + pauthors = [pauthors] + authors = [ + fuzzy_retrieval( + people, + ["aka", "name", "_id"], + author, + case_sensitive=False, + ) + for author in pauthors + ] + authorids = [author["_id"] if author is not None else author for author in authors] + if target in authorids: + firstclean.append(program) + + if active is True: + for program in firstclean: + if program.get("active") is True: + secondclean.append(program) + else: + for program in firstclean: + secondclean.append(program) + + for program in secondclean: + releases = program.get("release") + filtered_releases = [ + release for release in releases if "all" in types or release.get("release_type") in types + ] + if filtered_releases: + program["release"] = filtered_releases + thirdclean.append(program) + + if since: + for program in thirdclean: + filtered_releases = [] + for release in program.get("release", []): + releasedate = release.get("release_date") + if releasedate >= since: + filtered_releases.append(release) + if filtered_releases: + program["release"] = filtered_releases + fourthclean.append(program) + else: + fourthclean = thirdclean + + if before: + for program in fourthclean: + filtered_releases = [] + for release in program.get("release", []): + releasedate = release.get("release_date") + if releasedate <= before: + filtered_releases.append(release) + if filtered_releases: + program["release"] = filtered_releases + progclean.append(program) + else: + progclean = fourthclean + + for program in progclean: + pauthors = program["author"] + if isinstance(pauthors, str): + pauthors = [pauthors] + program["authors"] = [ + ( + author + if fuzzy_retrieval( + people, + ["aka", "name", "_id"], + author, + case_sensitive=False, + ) + is None + else fuzzy_retrieval( + people, + ["aka", "name", "_id"], + author, + case_sensitive=False, + )["name"] + ) + for author in pauthors + ] + authorlist = ", ".join(program["author"]) + program["authors"] = authorlist + + for release in program.get("release", []): + releasedate = release.get("release_date") + if isinstance(releasedate, date): + release["release_date"] = releasedate.isoformat() + + if len(progclean) > 0: + progclean = sorted( + progclean, + key=lambda k: max(release["release_date"] for release in k["release"]), + reverse=True, + ) + return progclean + + def awards_grants_honors(person, target_name, funding=True, service_types=None): """Make sorted awards grants and honors list. diff --git a/tests/outputs/releaselist/releaselist.tex b/tests/outputs/releaselist/software-report-scopatz.tex similarity index 75% rename from tests/outputs/releaselist/releaselist.tex rename to tests/outputs/releaselist/software-report-scopatz.tex index b9b7ab839..8ab5e97e2 100644 --- a/tests/outputs/releaselist/releaselist.tex +++ b/tests/outputs/releaselist/software-report-scopatz.tex @@ -14,8 +14,8 @@ \noindent \colorbox{gray!40}{% \begin{tabular*}{7in}{l@{\extracolsep{\fill}}r} - \textbf{\Large Prof. Simon J.~L.~Billinge} & \textbf{\today} \\ - Columbia University in the City of New York & sb2896@columbia.edu \\ + \textbf{\Large ANTHONY SCOPATZ} & \textbf{\today} \\ + & scopatz@cec.sc.edu \\ \end{tabular*}% }\vspace{1em} @@ -23,24 +23,20 @@ \begin{enumerate} - \item \textbf{\href{https://github.com/diffpy/diffpy.utils}{diffpy/diffpy.utils}:}\\ - \hspace*{1em}General utilities for analyzing diffraction data\\ - \hspace*{1em}\textit{Authors: Simon J.~L. Billinge, Sanjoon Bob Lee, Zhiming Xu, Tieqiong Zhang}\\ - \hspace*{1em}Url: https://github.com/diffpy/diffpy.utils\\ + \item \textbf{\href{https://github.com/diffpy/diffpy.distanceprinter}{diffpy/diffpy.distanceprinter}:}\\ + \hspace*{1em}Distance Printer, calculate the inter atomic distances. Part of xPDFsuite\\ + \hspace*{1em}\textit{Authors: Xiaohao Yang, Dasun Abeykoon, ANTHONY SCOPATZ}\\ + \hspace*{1em}Url: https://github.com/diffpy/diffpy.distanceprinter\\ \hspace*{1em}\textbf{Releases:}\vspace{-0.5em} \begin{itemize}[label={}] - \item \textbf{3.1.0:} 2025-10-25 + \item \textbf{1.0.0:} 2025-10-26 \begin{itemize}[label={}, leftmargin=2em] - \item Deprecated Python 2 feature - \item Changed to scikit-packaged standard. - \item Add some functionality - \item Modify existing function to make convenient. + \item Python 3.14 and something else \end{itemize} \end{itemize} - - \item \textbf{\href{https://github.com/diffpy/diffpy.srxplanar}{diffpy/diffpy.srxplanar}:}\\ + \item \textbf{\href{https://github.com/diffpy/diffpy.srxplanar}{diffpy/diffpy.srxplanar}:}\\ \hspace*{1em}2D diffraction image integration using non splitting pixel algorithm.\\ - \hspace*{1em}\textit{Authors: Xiaohao Yang, Rundong Hua, Zhiming Xu, Simon J.~L.~Billinge}\\ + \hspace*{1em}\textit{Authors: Xiaohao Yang, Rundong Hua, Zhiming Xu, ANTHONY SCOPATZ}\\ \hspace*{1em}Url: https://github.com/diffpy/diffpy.srxplanar\\ \hspace*{1em}\textbf{Releases:}\vspace{-0.5em} \begin{itemize}[label={}] @@ -50,19 +46,22 @@ \end{itemize} \item \textbf{0.1.1-rc.2:} 2025-10-20 \begin{itemize}[label={}, leftmargin=2em] - \item change package to scikit-package level-5 standard. + \item Change package to scikit-package level-5 standard. \end{itemize} \end{itemize} - \item \textbf{\href{https://github.com/diffpy/diffpy.distanceprinter}{diffpy/diffpy.distanceprinter}:}\\ - \hspace*{1em}Distance Printer, calculate the inter atomic distances. Part of xPDFsuite\\ - \hspace*{1em}\textit{Authors: Xiaohao Yang, Rundong Hua, Zhiming Xu, Simon J.~L.~Billinge}\\ - \hspace*{1em}Url: https://github.com/diffpy/diffpy.distanceprinter\\ + \item \textbf{\href{https://github.com/diffpy/diffpy.utils}{diffpy/diffpy.utils}:}\\ + \hspace*{1em}General utilities for analyzing diffraction data\\ + \hspace*{1em}\textit{Authors: Sanjoon Bob Lee, Zhiming Xu, Tieqiong Zhang, ANTHONY SCOPATZ}\\ + \hspace*{1em}Url: https://github.com/diffpy/diffpy.utils\\ \hspace*{1em}\textbf{Releases:}\vspace{-0.5em} \begin{itemize}[label={}] - \item \textbf{0.1.0:} 2025-10-26 + \item \textbf{3.1.0:} 2025-10-25 \begin{itemize}[label={}, leftmargin=2em] - \item Python 3.14 and something else + \item Deprecated Python 2 feature + \item Changed to scikit-packaged standard + \item Add some functionality + \item Modify existing function to make convenient \end{itemize} \end{itemize} diff --git a/tests/test_builders.py b/tests/test_builders.py index 6e9ca2626..4910e75f3 100644 --- a/tests/test_builders.py +++ b/tests/test_builders.py @@ -30,6 +30,7 @@ "review-man", # reading-lists need tests for this "reimb", + "releaselist", ] db_srcs = ["mongo", "fs"] diff --git a/tests/test_tools.py b/tests/test_tools.py index ca9686fc8..110db1a8c 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -18,6 +18,7 @@ filter_employment_for_advisees, filter_presentations, filter_publications, + filter_software, fragment_retrieval, fuzzy_retrieval, get_appointments, @@ -3000,6 +3001,241 @@ def test_filter_presentations(args, kwargs, expected): assert actual == expected +person3 = {"_id": "sbillinge", "aka": "Simon", "name": "Simon Billinge"} +person4 = {"_id": "stevenhua0320", "aka": "Steven hua", "name": "Rundong Hua"} +PEOPLE = [person3, person4] +software1 = { + "_id": "diffpy.utils", + "groups": ["xrd"], + "active": True, + "org_name": "diffpy", + "repo_name": "diffpy.utils", + "platform_name": "Github", + "grants": ["NSF Funding"], + "program_description": "General utilities for analyzing diffraction data", + "author": ["Simon Billinge", "Sanjoon Bob Lee", "Zhiming Xu", "Tieqiong Zhang"], + "release": [ + { + "major": 3, + "minor": 1, + "patch": 0, + "release_type": "major", + "release_date": "2025-10-25", + "summary": "Python 3.14 and something else", + "changes": [ + "deprecated python2 feature.", + "changed to scikit-packaged standard.", + "Add some functionality.", + "Modify existing function to make convenient.", + ], + "release_id": "3.1.0", + } + ], +} +software2 = { + "_id": "diffpy.srxplanar", + "groups": ["billingegroup"], + "active": True, + "author": ["Xiaohao Yang", "Rundong Hua", "Zhiming Xu", "Simon Billinge"], + "org_name": "diffpy", + "repo_name": "diffpy.srxplanar", + "platform_name": "Github", + "grants": ["NSF Funding"], + "program_description": "2D diffraction image integration using non splitting pixel algorithm.", + "release": [ + { + "major": 1, + "minor": 0, + "patch": 1, + "release_type": "major", + "release_date": "2025-10-26", + "summary": "Python 3.14 and something else", + "changes": [], + "release_id": "1.0.0", + }, + { + "major": 0, + "minor": 1, + "patch": 1, + "release_type": "pre-release", + "pre_release": 2, + "release_date": "2025-10-20", + "summary": "Package pre-release", + "changes": ["change package to scikit-package level-5 standard."], + "release_id": "0.1.1-rc.2", + }, + ], +} +software3 = { + "_id": "diffpy.distanceprinter", + "groups": ["billingegroup"], + "active": False, + "org_name": "diffpy", + "repo_name": "diffpy.distanceprinter", + "platform_name": "Github", + "grants": ["NSF Funding"], + "program_description": "Distance Printer, calculate the inter atomic distances. Part of xPDFsuite", + "author": ["Xiaohao Yang", "Dasun Abeykoon", "Simon Billinge"], + "release": [ + { + "major": 0, + "minor": 1, + "patch": 0, + "release_type": "minor", + "release_date": "2025-10-26", + "summary": "Python 3.14 and something else", + "changes": [], + "release_id": "1.0.0", + } + ], +} +SOFTWARE = [software1, software2, software3] + +expected4 = { + "_id": "diffpy.srxplanar", + "active": True, + "author": ["Xiaohao Yang", "Rundong Hua", "Zhiming Xu", "Simon Billinge"], + "authors": "Xiaohao Yang, Rundong Hua, Zhiming Xu, Simon Billinge", + "grants": ["NSF Funding"], + "groups": ["billingegroup"], + "org_name": "diffpy", + "platform_name": "Github", + "program_description": "2D diffraction image integration using non splitting " "pixel algorithm.", + "release": [ + { + "changes": [], + "major": 1, + "minor": 0, + "patch": 1, + "release_date": "2025-10-26", + "release_id": "1.0.0", + "release_type": "major", + "summary": "Python 3.14 and something else", + }, + { + "changes": ["change package to scikit-package level-5 " "standard."], + "major": 0, + "minor": 1, + "patch": 1, + "pre_release": 2, + "release_date": "2025-10-20", + "release_id": "0.1.1-rc.2", + "release_type": "pre-release", + "summary": "Package pre-release", + }, + ], + "repo_name": "diffpy.srxplanar", +} + +expected5 = { + "_id": "diffpy.distanceprinter", + "active": False, + "author": ["Xiaohao Yang", "Dasun Abeykoon", "Simon Billinge"], + "authors": "Xiaohao Yang, Dasun Abeykoon, Simon Billinge", + "grants": ["NSF Funding"], + "groups": ["billingegroup"], + "org_name": "diffpy", + "platform_name": "Github", + "program_description": "Distance Printer, calculate the inter atomic " "distances. Part of xPDFsuite", + "release": [ + { + "changes": [], + "major": 0, + "minor": 1, + "patch": 0, + "release_date": "2025-10-26", + "release_id": "1.0.0", + "release_type": "minor", + "summary": "Python 3.14 and something else", + } + ], + "repo_name": "diffpy.distanceprinter", +} + +expected6 = { + "_id": "diffpy.utils", + "active": True, + "author": ["Simon Billinge", "Sanjoon Bob Lee", "Zhiming Xu", "Tieqiong Zhang"], + "authors": "Simon Billinge, Sanjoon Bob Lee, Zhiming Xu, Tieqiong Zhang", + "grants": ["NSF Funding"], + "groups": ["xrd"], + "org_name": "diffpy", + "platform_name": "Github", + "program_description": "General utilities for analyzing diffraction data", + "release": [ + { + "changes": [ + "deprecated python2 feature.", + "changed to scikit-packaged standard.", + "Add some functionality.", + "Modify existing function to make convenient.", + ], + "major": 3, + "minor": 1, + "patch": 0, + "release_date": "2025-10-25", + "release_id": "3.1.0", + "release_type": "major", + "summary": "Python 3.14 and something else", + } + ], + "repo_name": "diffpy.utils", +} + +expected7 = { + "_id": "diffpy.srxplanar", + "active": True, + "author": ["Xiaohao Yang", "Rundong Hua", "Zhiming Xu", "Simon Billinge"], + "authors": "Xiaohao Yang, Rundong Hua, Zhiming Xu, Simon Billinge", + "grants": ["NSF Funding"], + "groups": ["billingegroup"], + "org_name": "diffpy", + "platform_name": "Github", + "program_description": "2D diffraction image integration using non splitting " "pixel algorithm.", + "release": [ + { + "changes": [], + "major": 1, + "minor": 0, + "patch": 1, + "release_date": "2025-10-26", + "release_id": "1.0.0", + "release_type": "major", + "summary": "Python 3.14 and something else", + }, + ], + "repo_name": "diffpy.srxplanar", +} + + +@pytest.mark.parametrize( + "args, kwargs, expected", + [ + # this tests no kwargs + ([PEOPLE, SOFTWARE, "sbillinge"], {}, [expected4, expected5, expected6]), + # this tests 'statuses' kwarg + ([PEOPLE, SOFTWARE, "sbillinge"], {"active": True}, [expected4, expected6]), + # this tests 'active' and 'types' kwargs together + ([PEOPLE, SOFTWARE, "stevenhua0320"], {"active": True, "types": ["major"]}, [expected7]), + # this tests 'active' and 'since' kwargs together + ( + [PEOPLE, SOFTWARE, "sbillinge"], + {"active": True, "since": "2025-10-21"}, + [expected7, expected6], + ), + # this tests the 'active' and 'before' kwargs together + ( + [PEOPLE, SOFTWARE, "sbillinge"], + {"active": True, "before": "2025-10-30"}, + [expected4, expected6], + ), + ], +) +def test_filter_software(args, kwargs, expected): + actual = filter_software(*args, **kwargs) + assert actual == expected + + @pytest.mark.parametrize( "coll, expected", [