-
Notifications
You must be signed in to change notification settings - Fork 63
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
Command line interface: Implement --fields for list command #246
Conversation
This doesn't refactor any of the existing commands (I'm not sure what our deprecation strategy is for them). This doesn't break existing functionality of list command. This doesn't add a way to access first_name. (I'm not sure how we want to design the property for names) |
Thank you that looks very cool! Can you add a proper doc comment to all your functions and check pep8 formatting, please (I think I saw some function arguments wothout spaces inbetween). I will do a full review next. |
What do you think about the pretty_name function? It exists for the purpose of backwards compatibility (and maybe for the header to look nice?) It also exists so that the fields can be case insensitive... but maybe we would prefer to show the snake_cased ugly name instead? |
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 left some line comments. For pep8 there are also tools like pylint that you can use.
Nice work so far :)
khard/khard.py
Outdated
attr_name = field.split('.')[0] | ||
val = '' | ||
if hasattr(vcard, attr_name): | ||
val = getattr(vcard, attr_name) | ||
# Nest multiple keys like emails.home.1 | ||
for partial in field.split('.')[1:]: | ||
if isinstance(val, dict) and partial in val: | ||
val = val[partial] | ||
elif partial.isdigit() and isinstance(val, list) \ | ||
and len(val) > int(partial): | ||
val = val[int(partial)] | ||
# TODO: Completely support case insensitive indexing | ||
elif isinstance(val, dict) and partial.upper() in val: | ||
val = val[partial.upper()] | ||
else: | ||
val = '' | ||
row.append(val) |
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.
Maybe you could put this in a separate function get_nested_field
. That would make it easier to write unit tests for this as it seems like an important piece of new code. What do you think?
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.
Done. In what file should the tests be written for this function?
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 think you could start a new test class in test/test_command_line_interface.py
which is named after the function and has tests for some important cases of its behaviour.
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.
Sounds like a good idea.
This merge request is getting pretty big though. I don't know when/if I'll get around to writing comprehensive tests for that function.
The idea of |
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.
Please give your type documentation explicitly instead of inline in the text. Many other functions do it that way:
def foo(x, y):
"""This does the foo for bar to baz ...
:param list(str|bool) x: the x that will be fooed
:param y: that is the bar (with a long type name)
:type y: some_long_module.and_type_name.Bar
:returns: 42, always
:rtype: int
"""
return 42
@@ -1030,6 +1034,8 @@ def list_subcommand(vcard_list, parsable, fields): | |||
:type vcard_list: list of carddav_object.CarddavObject | |||
:param parsable: machine readable output: columns devided by tabulator (\t) | |||
:type parsable: bool | |||
:param fields: list of strings for field evaluation | |||
:type fields: list |
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.
list(str)
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.
Is this used to generate some documentation somewhere?
Otherwise, this type of repetitious documentation is not helping anyone;
would make the writers of https://www.python.org/dev/peps/pep-0257 sad.
Please update CONTRIBUTING.rst
if this type of documentation is necessary.
(otherwise, feel free to add it yourself).
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.
These are used in the sphinx generated documentation. Try make -c doc html && $BROWSER doc/build/html/index.html
locally or go to https://khard.readthedocs.io/ . Although the python modules (and these signatures) are not yet visible on readthedocs (only after the next release).
I tend to put a more "human" description in the :param:
part and the explicit type signature in the :type:
part.
:type fields: list | |
:param fields: the object path to the field on the vcard that should be printed | |
:type fields: list(str) |
But I can fix these small things when I merge. I know that I am very picky about such things.
About duplication info: I am also thinking about real python type signatures in #204. But that is another big project and seems to bring its own complications.
So then, should the "pretty" formats be TitleCase? (If the header reads "E-mail" as it does, then if someone sees that and wants to use |
Thank you for all the prompt feedback! |
Another consideration is that it is pulling attribute names from carddav_object, of which, many have underscores
|
Is there any special reason you invited my to your khard repository? I was thinking about normalizing field names and spotting typos: I suggest that we allow only a very minimal character set in field names for the So if a user specifies invalid characters we can give an error message. But what about field names? Try
Furthermore I was thinking about private object and other special cases: I think we can postpone private objects and formatted post addresses and formatted anniversary and birthdays. But I came up with a plan that might be doable after this PR: Add new read only properties to the CarddavObject for these special cases (and other special cases like the different name gettes) so that they can be handled in a uniform way when formating output with fields. Later these can also be used for a custom query syntax like planned in #131. |
Is there a reason why you have a markdown list token in front of every commit? I would remove them. |
I like the idea about a fixed list of valid fields more the longer I think about it. We could still ignore case but require one specific spelling (plural or singular, underscores) and given propper error messages. |
When I'm committing to a repository that doesn't have a commit message standard, I just go with what I'm used to (what we use at my workplace, which I believe was inspired by Code::Blocks's standard)
Personally, I don't care much for 'minor commits', and think in general you should make them go away when you |
Right now It is currently the only field that does so (and special logic was written so it does so). Should we have a specific way of referring to the shortened uid, like |
It should be noted that 44c090d broke the existing tests... |
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 do not understand the reason for a6c2e25 . Why do we need the explicit name?
I would ask you to remove the The category or section name in the beginning og the commit message is nice and can also be understood by new readers without extra documentation. |
Currently Aditionally we should think about two things related to empty fields (one was already mentioned above):
|
It's just doing python string conversion: the attribute is returning None. We should probably change the str() method on the value returned so it shows only the day, or the empty string.
Show only lines that have non-space-characters. (We would definitely want our
-P for perl regex (allows the \t to mean tab), -v for inverse. If we change it to output the empty string instead of 'None', this would be `grep -Pv '\t$' ($ meaning the end of the line). I believe this project should only be as complicated as necessary... |
Was probably a little too overzealous making breaking changes. -- the idea was that the presentation of a field should not change when you change the Thinking about it more, it's probably not worth it for having the header change. reverted in 98b395b I think the only breaking chance you are authorizing is changing
|
For a web-based project, I have been thinking about Edit-List-View for different fields of a model. In khard, this is pretty similar (except that the command for view is called show, and we have multiple lists for pseudo-models email, postaddress, phone). Really, |
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.
nearly done :)
The only things still missing are:
- the failing tests and
- the rewriting of the commit messages.
- and the
None
problem and the field checking on the command line. I pushed some suggestions for that to the branch earboxer/khard@ls-fields...scheibler:ls-fields-suggestions You could use them or do something similar.
After that I think we can merge. 🎉
Okay, I fixed the tests, and rewrote history a little. |
Thank you very much @earboxer :) |
#179 (comment)
Things you can do with this
python3 -m khard ls -F name,birthday
(likekhard bdays
, but it doesn't sort, doesn't exclude missing birthdays, and outputs in a different format)python3 -m khard ls -pF emails.home.0,name
(shows first home email address for each user)python3 -m khard ls --fields phone_numbers.cell.0,phone_numbers
(shows first cell number, and all phone numbers in python format)python3 -m khard ls -p -F Name,post_addresses.home.0.region,post_addresses.home.0.code
(name, state and zip code)The list of properties can be seen with
grep '@property' -A1 khard/carddav_object.py
(Additional fields can easily be added by making them attributes in carddav_object.py)
For backwards compatibility with previous usage, the additional fields are defined:
address_bookuid_short