-
Notifications
You must be signed in to change notification settings - Fork 64
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
Enable mypy review for pyshacl.cli:main and fix reported issues #192
Changes from all commits
e880e62
9c7479a
71d16c6
ef4c857
18cbe68
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,4 +23,4 @@ def str_is_true(s_var: str): | |
|
||
sys.exit(http_cli()) | ||
|
||
sys.exit(main()) | ||
main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
import sys | ||
|
||
from prettytable import PrettyTable | ||
from rdflib import Graph | ||
from rdflib.namespace import SH | ||
|
||
from pyshacl import __version__, validate | ||
|
@@ -183,14 +184,14 @@ def str_is_true(s_var: str): | |
# parser.add_argument('-h', '--help', action="help", help='Show this help text.') | ||
|
||
|
||
def main(): | ||
def main() -> None: | ||
basename = os.path.basename(sys.argv[0]) | ||
if basename == "__main__.py": | ||
parser.prog = "python3 -m pyshacl" | ||
do_server = os.getenv("PYSHACL_HTTP", "") | ||
do_server = os.getenv("PYSHACL_SERVER", do_server) | ||
if do_server: | ||
args = {} | ||
args = argparse.Namespace() | ||
else: | ||
args = parser.parse_args() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This still needs to skip There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Restored, using an empty |
||
if str_is_true(do_server) or args.server: | ||
|
@@ -306,10 +307,11 @@ def col_widther(s, w): | |
t2.field_names = ['No.', 'Severity', 'Focus Node', 'Result Path', 'Message', 'Component', 'Shape', 'Value'] | ||
t2.align = "l" | ||
|
||
assert isinstance(v_graph, Graph) | ||
for i, o in enumerate(v_graph.objects(None, SH.result)): | ||
r = {} | ||
for o2 in v_graph.predicate_objects(o): | ||
r[o2[0]] = str(col_widther(o2[1].replace(f'{SH}', ''), 25)) # max col width 30 chars | ||
r[o2[0]] = str(col_widther(str(o2[1]).replace(f'{SH}', ''), 25)) # max col width 30 chars | ||
t2.add_row( | ||
[ | ||
i + 1, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should
main()
be changed to returnint
exit code, then pass that tosys.exit()
from the caller site? That would avoid all thesys.exit()
calls in here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At some point years ago, the idea wormed into my head that
main()
in Python had to returnNone
.However, I've had poor luck finding out where that idea came from. My current best guess is
mypy
complaining about missing return signatures when I was first learning type annotations. E.g. from this programtry.py
:mypy try.py
returns no issues; fine & dandy, there's no typed context.mypy --strict
catches the error I want aroundx
, but gives this output about the rest:I thought there used to be a specific suggestion about
main
instead of what's on the first 2 or last 1 lines. It might have just been me conflating nearby lines instead. I'm not finding a say on the matter inmypy
's documentation, PEPs on typing (483 and 484), or other search engine results.Since
mypy --strict
didn't complain at this:I'm fine swapping
-> None
with anything else if you think it'll result in cleaner chaining.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I started the "
main
returns anint
" revision, and stopped partway through revising thesys.exit(2)
calls when I remembered another hint I had for whymain
usually returnsNone
.sys.exit(n)
influences the return status of the program call frommain
.return n
doesn't.E.g. here's a file
try.py
:Here's the shell-visible exit status:
So I think the more shell-consistent idiom is to have the calls to
sys.exit(main())
instead just be calls tomain()
, and to leave any deeper-in-main
calls tosys.exit(n)
as they are now. I don't think havingmain() -> int
gains any control-flow advantage oversys.exit
doing hard-stops with a controlled exit status value, orraise SomethingUnfortunate
passing a traceback exit value 1 if uncaught.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checking back in on this thread: My own preference, in the general case for Python beyond this repository, is that
main
should returnNone
, and anything meant to influence Python's exit status as non-0 should be handled withsys.exit()
orraise
.I see the alternative "chaining into
sys.exit
" style seems to be rooted in use ofpyshacl.sh_http.cli()
. I'm guessing there are nuances, possibly for users outside this repository, of handlingtraceback
and control flow the way it's being handled there. So, I could understand you preferringpyshacl.cli.main() -> int
.This seems like the last open review matter on this PR. Which is your preference -
int
orNone
formain
?