') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); feat: Creating one py_binary per main module by linzhp · Pull Request #1584 · bazel-contrib/rules_python · GitHub
Skip to content

feat: Creating one py_binary per main module - #1584

Merged
aignas merged 13 commits into
bazel-contrib:mainfrom
linzhp:py_binary
Dec 13, 2023
Merged

feat: Creating one py_binary per main module#1584
aignas merged 13 commits into
bazel-contrib:mainfrom
linzhp:py_binary

Conversation

@linzhp

@linzhplinzhp commented Nov 29, 2023

Copy link
Copy Markdown
Contributor

Many existing Python repos don't use __main__.py to indicate the the main module. Instead, they put something like below in any Python files:

if__name__=="__main__":
main()

This PR makes the Gazelle extension able to recognize main modules like this, when __main__.py doesn't exist. This reduces the need to create __main__.py when enabling Gazelle extensions in existing Python repos.

The current behavior of creating single py_binary for __main__.py is preserved and takes precedence. So this is a backward-compatible change.

Closes#1566.

@linzhp
linzhp requested a review from f0rmiga as a code ownerNovember 29, 2023 20:18
@aignas

aignas commented Dec 3, 2023

Copy link
Copy Markdown
Collaborator

Thanks for the PR, does this replace #1582? If so does it make to add some test cases from that PR in order to have coverage for:

  • Multiple py_binary targets in the output BUILD.bazel.
  • Ensuring that we are not generating py_binary for test files.

@linzhp

Copy link
Copy Markdown
ContributorAuthor

I think #1582 addresses a different problem, but I added the test cases anyways.

@aignas

Copy link
Copy Markdown
Collaborator

Sorry, I meant #1566 and thanks for adding the tests. I agree that #1582 addresses a different problem.

@linzhp

Copy link
Copy Markdown
ContributorAuthor

I didn't realize there is already an open PR for this. Yes, this reimplements that, without parsing the Python files again. It also looks at tokens instead of string matches, with would cover cases like if __name__=="__main__" (no spaces) or if __name__ == "__main__" (extra spaces)

@aignasaignas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think overall LGTM with a few minor comments.

Comment threadgazelle/python/generate.go Outdated
Comment on lines +255 to +265
if args.File != nil {
for _, t := range args.File.Rules {
if t.Name() == pyBinaryTargetName && t.Kind() != actualPyBinaryKind {
fqTarget := label.New("", args.Rel, pyBinaryTargetName)
log.Printf("failed to generate target %q of kind %q: "+
"a target of kind %q with the same name already exists.",
fqTarget.String(), actualPyBinaryKind, t.Kind())
continue mainModulesLoop
}
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: the readability of this code due to nesting and the code location declarations is getting a little hard to follow. If it was possible to reduce indenting and/or split out to separate functions, it would be great, but not blocking this PR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

extract it to a new function and reuse it in all places with similar logic

Comment threadgazelle/python/testdata/binary_without_entrypoint/BUILD.in Outdated
)

py_library(
name = "binary_without_entrypoint",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

should this be library_without_entrypoint?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

given it a better name

@siddharthab

Copy link
Copy Markdown
Contributor

Thanks for doing this. I was thinking of adding this myself if I had not discovered your PR through one of mine.

@aignasaignas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

@aignas
aignas added this pull request to the merge queueDec 12, 2023
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to failed status checks Dec 12, 2023
@aignas
aignas added this pull request to the merge queueDec 12, 2023
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to failed status checks Dec 12, 2023
@aignas
aignas added this pull request to the merge queueDec 13, 2023
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to failed status checks Dec 13, 2023
@rickeylev
rickeylev added this pull request to the merge queueDec 13, 2023
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to failed status checks Dec 13, 2023
@aignas
aignas added this pull request to the merge queueDec 13, 2023
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to failed status checks Dec 13, 2023
@aignas
aignas added this pull request to the merge queueDec 13, 2023
Merged via the queue into bazel-contrib:main with commit 6ffb04eDec 13, 2023
@linzhp
linzhp deleted the py_binary branch December 13, 2023 16:29
github-merge-queueBot pushed a commit that referenced this pull request Jan 9, 2024
[This previous PR](#1584)
added the ability to make a `py_binary` target per file if `if __name__
== "__main__"` tokens were found in the file. This works great in the
default case, but when `python_generation_mode` is set to `file`, the
plugin now attempts to make both a `py_binary` and a `py_library` target
for each main file, which results in an error.
This PR modifies the behavior to work properly with per-file target
generation, and adds tests for this case.
github-merge-queueBot pushed a commit that referenced this pull request Jul 1, 2025
…les (#2998)
Remove entry point file requirements when generating rules. Enable
python rule generation as long as there are .py source files under the
directory so all new packages will have python rules generated in the
package.
The extension used to require entrypoints for generation but:
- entry point for tests (i.e., `__test__.py` ) is no longer required
after #999 and
#2044
- entry point for binaries (i.e., `__main__.py` ) is no longer required
after #1584
The entry point for libraries (`__init__.py` ) shouldn't be required
either, especially for Python 3.3 and after when namespace packages are
supported.
---------
Co-authored-by: yushan <yushan@uber.com>
Co-authored-by: Douglas Thor <dougthor42@users.noreply.github.com>
amartani pushed a commit to benchling/rules_python that referenced this pull request Jul 8, 2025
…les (bazel-contrib#2998)
Remove entry point file requirements when generating rules. Enable
python rule generation as long as there are .py source files under the
directory so all new packages will have python rules generated in the
package.
The extension used to require entrypoints for generation but:
- entry point for tests (i.e., `__test__.py` ) is no longer required
after bazel-contrib#999 and
bazel-contrib#2044
- entry point for binaries (i.e., `__main__.py` ) is no longer required
after bazel-contrib#1584
The entry point for libraries (`__init__.py` ) shouldn't be required
either, especially for Python 3.3 and after when namespace packages are
supported.
---------
Co-authored-by: yushan <yushan@uber.com>
Co-authored-by: Douglas Thor <dougthor42@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@linzhp@aignas@siddharthab