Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG/ENH] Improve generate_report method of multi-subject maskers #3960

Closed
3 of 9 tasks
ymzayek opened this issue Sep 11, 2023 · 1 comment
Closed
3 of 9 tasks

[BUG/ENH] Improve generate_report method of multi-subject maskers #3960

ymzayek opened this issue Sep 11, 2023 · 1 comment
Labels
Bug for bug reports Enhancement for feature requests

Comments

@ymzayek
Copy link
Member

ymzayek commented Sep 11, 2023

Is there an existing issue for this?

  • I have searched the existing issues

Operating system

  • Linux
  • Mac
  • Windows

Operating system version

  • Linux Ubuntu 22.04

Python version

  • 3.11
  • 3.10
  • 3.9
  • 3.8
  • 3.7

nilearn version

10.2.dev

Expected behavior

The multi-subject maskers generate_report behavior can be improved.

The MultiNiftiMasker does not support generate_report even if passed one subject. The following error is raised if called:

NameError: name 'warning_message' is not defined at line 205 column 7 in file [/home/yasmin/nilearn/nilearn/nilearn/reporting/data/html/report_body_template.html](https://file+.vscode-resource.vscode-cdn.net/home/yasmin/nilearn/nilearn/nilearn/reporting/data/html/report_body_template.html)

In the case of the labels and maps multi-subject maskers, it does work with one subject. This is partly improved in PR #3935. It clarifies that generate_report is only supported with one subject. We can think of a way to support multiple subjects where you can click through the first time point of the different subjects but this could present scaling issues.

Current behavior & error messages

This is what I got:

Full Traceback
# Paste the error message here
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Input In [6], in <cell line: 7>()
      4 img = datasets.fetch_development_fmri(n_subjects=1)["func"]
      6 masker = MultiNiftiMasker()
----> 7 masker.fit(img).generate_report()

File [~/nilearn/nilearn/nilearn/maskers/nifti_masker.py:305](https://file+.vscode-resource.vscode-cdn.net/home/yasmin/nilearn/nilearn/~/nilearn/nilearn/nilearn/maskers/nifti_masker.py:305), in NiftiMasker.generate_report(self)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/maskers/nifti_masker.py?line=301'>302</a>](file:///home/yasmin/nilearn/nilearn/nilearn/maskers/nifti_masker.py?line=301%27%3E302%3C/a%3E) """Generate a report of the masker."""
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/maskers/nifti_masker.py?line=302'>303</a>](file:///home/yasmin/nilearn/nilearn/nilearn/maskers/nifti_masker.py?line=302%27%3E303%3C/a%3E) from nilearn.reporting.html_report import generate_report
--> <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/maskers/nifti_masker.py?line=304'>305</a>](file:///home/yasmin/nilearn/nilearn/nilearn/maskers/nifti_masker.py?line=304%27%3E305%3C/a%3E) return generate_report(self)

File [~/nilearn/nilearn/nilearn/reporting/html_report.py:192](https://file+.vscode-resource.vscode-cdn.net/home/yasmin/nilearn/nilearn/~/nilearn/nilearn/nilearn/reporting/html_report.py:192), in generate_report(estimator)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=188'>189</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=188%27%3E189%3C/a%3E) if not hasattr(estimator, '_reporting_data'):
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=189'>190</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=189%27%3E190%3C/a%3E)     warnings.warn('This object has not been fitted yet ! '
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=190'>191</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=190%27%3E191%3C/a%3E)                   'Make sure to run `fit` before inspecting reports.')
--> <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=191'>192</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=191%27%3E192%3C/a%3E)     return _update_template(
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=192'>193</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=192%27%3E193%3C/a%3E)         title='Empty Report',
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=193'>194</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=193%27%3E194%3C/a%3E)         docstring=(
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=194'>195</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=194%27%3E195%3C/a%3E)             "This report was not generated. Please `fit` the object."
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=195'>196</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=195%27%3E196%3C/a%3E)         ),
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=196'>197</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=196%27%3E197%3C/a%3E)         content=_embed_img(None),
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=197'>198</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=197%27%3E198%3C/a%3E)         overlay=None,
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=198'>199</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=198%27%3E199%3C/a%3E)         parameters={},
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=199'>200</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=199%27%3E200%3C/a%3E)         data=data,
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=200'>201</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=200%27%3E201%3C/a%3E)     )
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=202'>203</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=202%27%3E203%3C/a%3E) elif estimator._reporting_data is None:
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=203'>204</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=203%27%3E204%3C/a%3E)     warnings.warn('Report generation not enabled ! '
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=204'>205</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=204%27%3E205%3C/a%3E)                   'No visual outputs will be created.')

File [~/nilearn/nilearn/nilearn/reporting/html_report.py:137](https://file+.vscode-resource.vscode-cdn.net/home/yasmin/nilearn/nilearn/~/nilearn/nilearn/nilearn/reporting/html_report.py:137), in _update_template(title, docstring, content, overlay, parameters, data, template_name)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=133'>134</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=133%27%3E134%3C/a%3E)     raise FileNotFoundError(f"No template {body_template_name}")
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=134'>135</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=134%27%3E135%3C/a%3E) tpl = tempita.HTMLTemplate.from_filename(str(body_template_path),
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=135'>136</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=135%27%3E136%3C/a%3E)                                          encoding='utf-8')
--> <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=136'>137</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=136%27%3E137%3C/a%3E) body = tpl.substitute(title=title, content=content,
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=137'>138</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=137%27%3E138%3C/a%3E)                       overlay=overlay,
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=138'>139</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=138%27%3E139%3C/a%3E)                       docstring=docstring,
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=139'>140</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=139%27%3E140%3C/a%3E)                       parameters=parameters,
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=140'>141</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=140%27%3E141%3C/a%3E)                       **data)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=142'>143</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=142%27%3E143%3C/a%3E) head_template_name = 'report_head_template.html'
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=143'>144</a>](file:///home/yasmin/nilearn/nilearn/nilearn/reporting/html_report.py?line=143%27%3E144%3C/a%3E) head_template_path = resource_path.joinpath(head_template_name)

File [~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:184](https://file+.vscode-resource.vscode-cdn.net/home/yasmin/nilearn/nilearn/~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:184), in Template.substitute(self, *args, **kw)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=181'>182</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=181%27%3E182%3C/a%3E) if self.namespace:
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=182'>183</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=182%27%3E183%3C/a%3E)     ns.update(self.namespace)
--> <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=183'>184</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=183%27%3E184%3C/a%3E) result, defs, inherit = self._interpret(ns)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=184'>185</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=184%27%3E185%3C/a%3E) if not inherit:
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=185'>186</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=185%27%3E186%3C/a%3E)     inherit = self.default_inherit

File [~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:195](https://file+.vscode-resource.vscode-cdn.net/home/yasmin/nilearn/nilearn/~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:195), in Template._interpret(self, ns)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=192'>193</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=192%27%3E193%3C/a%3E) parts = []
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=193'>194</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=193%27%3E194%3C/a%3E) defs = {}
--> <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=194'>195</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=194%27%3E195%3C/a%3E) self._interpret_codes(self._parsed, ns, out=parts, defs=defs)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=195'>196</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=195%27%3E196%3C/a%3E) if '__inherit__' in defs:
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=196'>197</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=196%27%3E197%3C/a%3E)     inherit = defs.pop('__inherit__')

File [~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:223](https://file+.vscode-resource.vscode-cdn.net/home/yasmin/nilearn/nilearn/~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:223), in Template._interpret_codes(self, codes, ns, out, defs)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=220'>221</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=220%27%3E221%3C/a%3E)     out.append(item)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=221'>222</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=221%27%3E222%3C/a%3E) else:
--> <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=222'>223</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=222%27%3E223%3C/a%3E)     self._interpret_code(item, ns, out, defs)

File [~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:240](https://file+.vscode-resource.vscode-cdn.net/home/yasmin/nilearn/nilearn/~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:240), in Template._interpret_code(self, code, ns, out, defs)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=237'>238</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=237%27%3E238%3C/a%3E) elif name == 'cond':
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=238'>239</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=238%27%3E239%3C/a%3E)     parts = code[2:]
--> <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=239'>240</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=239%27%3E240%3C/a%3E)     self._interpret_if(parts, ns, out, defs)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=240'>241</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=240%27%3E241%3C/a%3E) elif name == 'expr':
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=241'>242</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=241%27%3E242%3C/a%3E)     parts = code[2].split('|')

File [~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:296](https://file+.vscode-resource.vscode-cdn.net/home/yasmin/nilearn/nilearn/~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:296), in Template._interpret_if(self, parts, ns, out, defs)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=293'>294</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=293%27%3E294%3C/a%3E)     result = True
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=294'>295</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=294%27%3E295%3C/a%3E) else:
--> <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=295'>296</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=295%27%3E296%3C/a%3E)     result = self._eval(part[2], ns, pos)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=296'>297</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=296%27%3E297%3C/a%3E) if result:
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=297'>298</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=297%27%3E298%3C/a%3E)     self._interpret_codes(part[3], ns, out, defs)

File [~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:319](https://file+.vscode-resource.vscode-cdn.net/home/yasmin/nilearn/nilearn/~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:319), in Template._eval(self, code, ns, pos)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=316'>317</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=316%27%3E317%3C/a%3E) e.args = (self._add_line_info(arg0, pos),)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=317'>318</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=317%27%3E318%3C/a%3E) if PY3:
--> <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=318'>319</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=318%27%3E319%3C/a%3E)     raise(e)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=319'>320</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=319%27%3E320%3C/a%3E) else:
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=320'>321</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=320%27%3E321%3C/a%3E)     raise (exc_info[1], e, exc_info[2])

File [~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:305](https://file+.vscode-resource.vscode-cdn.net/home/yasmin/nilearn/nilearn/~/nilearn/nilearn/nilearn/externals/tempita/__init__.py:305), in Template._eval(self, code, ns, pos)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=302'>303</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=302%27%3E303%3C/a%3E) try:
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=303'>304</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=303%27%3E304%3C/a%3E)     try:
--> <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=304'>305</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=304%27%3E305%3C/a%3E)         value = eval(code, self.default_namespace, ns)
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=305'>306</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=305%27%3E306%3C/a%3E)     except SyntaxError as e:
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=306'>307</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=306%27%3E307%3C/a%3E)         raise SyntaxError(
    <a href='[file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=307'>308</a>](file:///home/yasmin/nilearn/nilearn/nilearn/externals/tempita/__init__.py?line=307%27%3E308%3C/a%3E)             'invalid syntax in expression: %s' % code)

File <string>:1, in <module>

NameError: name 'warning_message' is not defined at line 205 column 7 in file [/home/yasmin/nilearn/nilearn/nilearn/reporting/data/html/report_body_template.html](https://file+.vscode-resource.vscode-cdn.net/home/yasmin/nilearn/nilearn/nilearn/reporting/data/html/report_body_template.html)
Code to reproduce

Steps and code to reproduce bug

# Paste your code here
from nilearn import datasets
from nilearn.maskers import MultiNiftiMasker

img = datasets.fetch_development_fmri(n_subjects=1)["func"]

masker = MultiNiftiMasker()
masker.fit(img).generate_report()
@ymzayek ymzayek added Bug for bug reports Enhancement for feature requests labels Sep 11, 2023
@Remi-Gau Remi-Gau changed the title [BUG/ENH] Impove generate_report method of multi-subject maskers [BUG/ENH] Improve generate_report method of multi-subject maskers Sep 18, 2023
@Remi-Gau
Copy link
Collaborator

Remi-Gau commented Oct 5, 2023

fixed by #4001

@Remi-Gau Remi-Gau closed this as completed Oct 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug for bug reports Enhancement for feature requests
Projects
None yet
Development

No branches or pull requests

2 participants