Hi Joe,

Thank you for taking the time to review. My comments are below. 
Incidentally, you've brought up some very good points that have made me 
go "hrmmmm," so I'd say it's a worthwhile review!

- Keith

Joseph J VLcek wrote:
>
> Hey Keith,
>
> Here is my feedback. Many of my comments are nit/questions. My Python 
> experience is limited still. So many of my comments my be due to naivety.
>
> I may have learned more from doing this review than I provide.
>
> Hope this help.
> Joe
>
> ---
>
> +-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=
>  
>
> From code walkthrough:
> +-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=
>  
>
>
> Comment:
> --------
>
> scroll_window.py
>
>     I have a comment about init_scroll_bar.
>
> disk_window.py has:
>                 self.right_win.init_scroll_bar()
>
>     Why init_scroll_bar is sometimes passed, FALSE, TRUE and
> nothing indicates to me this is not a BOOLIAN. It actually has
> 3 values. I think the argument should accept something like:
>
> DRAW_SCROLL_BAR, REMOVE_SCROLL_BAR, UNALTER_SCROLL_BAR

While I see your point, I'm not sure I agree with the need to create a 
separate enum-type setup to cover this scenario. Essentially, I've 
combined functionality that could be separated into a single function 
(i.e., "set/get_use_scroll_bar" and "repaint_scroll_bar"). If the 
current setup makes usage non-obvious, I think splitting the 
functionality would be simpler, and more readable. That is, have 
"init_scroll_bar" always just read _use_scroll_bar, and then provide a 
setter function for _use_scroll_bar that calls init_scroll_bar if 
needed. Then, init_scroll_bar doesn't need the "3-way boolean," and the 
setter would only take a "True" or "False" as an argument.

>
> Comment:
> --------
>
> Why the x_loc/y_loc level window management? Isn't there already
> something which exists that can be used by Python to do this on
> a char. based screen?

Interesting. Perhaps our initial research wasn't quite deep enough. I'll 
look into it some, but I don't think rewriting at this stage will be useful.

>
> e.g.: http://excess.org/urwid/

Several of the more complex examples in their tutorial seem make use of 
either relative or absolute x/y coordinates. Certainly, they do a better 
job of abstracting some of it away then what was done here, but I can't 
envision any UI framework that doesn't provide the option of explicitly 
setting coordinates in some fashion.

>
> +-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=
>  
>
> Comment from code I deskcheck reviewed:
> +-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=+-=
>  
>
>
> I reviewed:
>
>     cmd/text-install/osol_install/text_install/date_time.py
>     cmd/text-install/osol_install/text_install/help_screen.py
>     cmd/text-install/osol_install/text_install/network_nic_configure.py
>     cmd/text-install/osol_install/text_install/network_nic_select.py
>     cmd/text-install/osol_install/text_install/network_type.py
>     cmd/text-install/osol_install/text_install/partition_edit_screen.py
>     cmd/text-install/osol_install/text_install/timezone.py
>     cmd/text-install/osol_install/text_install/timezone_locations.py
>     cmd/text-install/osol_install/text_install/timezone_regions.py
>
> General comments
> -------------------------------------------------------------------------------
>  
>
>
> Comment:
> --------
> Is this code supposted to be PEP8 ?

Yes (see below). This code should be PEP8 and pylint clean, or nearly 
so. I see scores mostly in the 9-10 range.

>
> e.g.:
> pylint --include-ids=y --rcfile=../../tools/env/install.pylintrc 
> help_screen.py
>     ...
>     Your code has been rated at 3.65/10
>
> pylint --include-ids=y --rcfile=../../tools/env/install.pylintrc 
> partition_edit_screen.py
>     ...
>     Your code has been rated at 0.75/10
>
> pylint --include-ids=y --rcfile=../../tools/env/install.pylintrc 
> network_nic_select.py
>     ...
>     Your code has been rated at -0.53/10
>
>
>
> Comment:
> --------
> Please add pydoc usable comments for each file.
>
> e.g.:
> % pydoc network_nic_configure.py
> no Python documentation found for 'network_nic_configure.py'

For this, and pylint, you'll need to run from the 
usr/src/cmd/text-install directory. Otherwise, both pydoc and pylint 
can't resolve the imports properly. Pylint will work properly if you add 
that directory to your PYTHONPATH, but pydoc will still get confused if 
you reference the file directly. However, you can set the PYTHONPATH, 
and then run "pydoc osol_install.text_install.network_nic_configure". I 
imagine that other caiman code that imports osol_install.<something> 
suffers similarly in a "clean" environment, but since I most of the code 
is installed on the system already, it can at least reference the latest 
release version. That brings up a good point, actually - one must be 
sure to set the PYTHONPATH appropriately so that when we run pylint 
before checkin, pylint is checking the updated versions of imported 
modules, not the installed versions.

>
>
> Comment:
> --------
>
> This is a comment I made during the code walkthrough sessions. I think
> the manipulation of the x & y coordinates should be done at a lower
> level. Pehaps a text_install/CoursePosition class could be defined.
> Maybe not worth it. But since it came up in the walkthrough sessions
> I thought I would note it.

Do you see "CoursePosition" as a simple (x, y) "Point" type class, or 
something more complex? Are you referring to the manipulation in the 
screen code of, for example "y_loc += <something>"? I sort of see the 
problem you're poking at, but I'm not sure what the solution might look 
like yet.

>
>
>
> cmd/text-install/osol_install/text_install/date_time.py
> -------------------------------------------------------------------------------
>  
>
>
> Comment:
> --------
> It seems you may be reinventing the wheel here. his seems like basic 
> functionality
> to me.
>
> Perhaps exploring what Python base classes already exhist that could 
> handle
> more of the functionality defined in date_time.

The 'datetime' module is used in this file. Are there particular 
instances in this file that you think deserve extra attention?

>
> Comment:
> --------
> It also seems to me that the x & y courser manipulation seels like basic
> functionality that might be already available somewhere. It's low level
> functionality that seems to me should belong at a lower level.
>
> Comment:
> --------
>   I found these varible names not very indicative:
>   55     YYYY = _("(YYYY)")
>   YEAR maybe better

How about YEAR_FORMAT? Given the number of other variables in this file 
with "year" or "YEAR" in them, calling it just plain "YEAR" would be 
more ambiguous.

>
>   60     OFFSET = 3
>   OFFSET to what?

Answering the explicit question: Offset from the left side of the 
window. Most/all screens have an OFFSET variable, and the UI elements 
within the screens tend to be given OFFSET blank columns to their left.

To answer the implied question: Removing the usage of OFFSET, and 
instead doing something along the lines of adding a "border" (or 
"left/right/top/bottom_border") property to InnerWindow, would condense 
this and make it  more intelligent. (border/offset/padding, something 
along those lines).

>
> Comment:
> --------
>   61     YEAR_DIGITS = 4
>
> Comment:
> --------
>
>   84         self.year_edit = None
>   85         self.year_err = None
>   86         self.year_list = None
>
> _edit, _err, _list are repeated. Do you think it might be better to 
> put these in a
> dictionary with keys: edit, err and list?

There's a common paradigm in this and other code of "EditField inside of 
a ListItem, with an associated ErrorWindow". I think we can take your 
suggestion a step further and:
* Provide a common, easier way to construct an "EditField inside of a 
ListItem with an ErrorWindow" globject.
* Strip these down to just "self.year_field" or something similar. The 
year_list and year_err fields are rarely directly used, and if they're 
needed, they could be referenced by, for example, 
self.year_field.list_item and self.year_field.error_win, respectively.

>
> Comment:
> --------
>  178         self.edit_area.columns = 3
>
> Hardcoding things like this raises a flag for maintenance issues.
> Would   60     OFFSET = 3 work here?

OFFSET wouldn't be the right variable, but moving the hardcoded value to 
a class property would definitely be preferred.

>
> Comment:
> --------
>  151         y_loc += 1
> ....
>  260         self.center_win.add_text("(0-59)", y_loc, x_loc, 
> self.win_size_x - 3)
>
> The code between lines 151 and 260 looks repetitious. Would it make sense
> to create parameterized supporting code which could be invoked 
> multiple times
>
> to:
>
> As needed set things like:
>  self.error_area.y_loc
>  self.list_area.y_loc
>  self.list_area.columns
>  self.edit_area.columns
>  self.edit_area.x_loc
>
> invoke:
>     ErrorWindow()
>     ListItem()
>     EditField()

Agreed. Part of this could be stripped down when the unified 
"EditField/ListItem/ErrorWindow" concept from above is in place.

>
> comment:
> --------
>
>  326 def get_days_in_month(month_edit, year_edit, date_time):
>
> Could calendar.py  monthrange be leveraged here?

It is - see lines 347 and 350. The extra logic handles cases not covered 
(for example, the user hasn't finished inputting the month or year yet, 
so we need to have intelligent defaults given the remaining known data).

>
> comment:
> --------
>  345             if (len(cur_year) == 4 and year_valid(year_edit)):
>
> Could calendar.py  isleap be leveraged here?

This is checking to see if the user has input a valid year yet, e.g., 
they could be halfway through typing "2010" and so there would only be a 
"20" in the field. We don't actually want to look up the monthrange for 
the year "20" in this case. However, it looks like the call to 
year_valid is unnecessary and potentially toxic.

>
> cmd/text-install/osol_install/text_install/help_screen.py
> -------------------------------------------------------------------------------
>  
>
>
> Comment:
> --------
>
> 67         self.help_info = []
> 68         self.help_dict = None
>
> Does it makes sense to set these empty and to None when:
>     73         self.setup_help_data()
>     will fill them in?

Yes. Pylint and pydoc prefer variables to be 'announced' in the __init__ 
function.

>
> Comment:
> --------
>
>   92             "NICSelect": ("network_manual.txt",
>   ...
>   94             "NICConfigure": ("network_manual.txt",
>
> Are both of these supposed to have the same helpfile: 
> "network_manual.txt"?
>
> Maybe yes eh?

Yes. The one file contains the help text for both screens (the first 
screen is not terribly complicated).

>
>
> Comment:
> --------
>
>   96             "TimeZoneRegions":  ("timezone.txt", _("Time Zone")),
>   97             "TimeZoneLocations": ("timezone.txt", _("Time Zone")),
>   98             "TimeZone": ("timezone.txt", _("Time Zone")),
>
> Are all of these supposed to have the same header? I could see maybe the
> same help file but should the headers be different?
>
> Maybe no eh?

Given that the text is the same, I think the headers should remain the same.

>
> Comment:
> --------
>  105         if self.is_x86:
>  130         if self.is_x86:
>
> Could/Should these two conditionals be combined?

Yeah they can. Should they? It's a readability issue, and the 
performance difference would be unnoticeable if combined. Keeping the 
help_info appends grouped and the help_dict entries grouped seems 
preferable.

>
> Comment:
> --------
>  202             help_text = self.get_help_topic(info[0])
> ...
>  207             help_topic = info[0]
>
> I see an inconsistency:
>
> help_text is set using get_help_topic yet help_topic is not. Is this 
> wrong
> or is the named backwards?

I'll have to defer to Sue on this one.

>
> cmd/text-install/osol_install/text_install/network_nic_configure.py
> -------------------------------------------------------------------------------
>  
>
>
> Comment:
> --------
>
>  101             find_defaults = self.nic.find_defaults
>
> Why is it necessarey to have this in a try/except block? You control
> self.nic.find_defaults.
>
> This may be a Python thing I just don't understand yet.

No, it's wrong. It's a remnant of the original version of NetworkInfo, 
for which this was the easier way to write things. The more appropriate 
route would be to either add find_defaults to NetworkInfo.__init__ 
(defaulting to True), or to change 100-103 to:

find_defaults = getattr(self.nic, "find_defaults", True)

>
> Comment:
> --------
>
>  157         self.center_win.activate_object(0)
>
> What does the "0" represent? Could a defintion be created for index 0 so
> an indicative name could be seen here?

The 0 represents the first item in the list. We could do 
"self.center_win.activate_object(self.ip_field)", which is *currently* 
the first item in the list, but setting it to 0 here (and on other 
screens) simply means "default to 0". Perhaps, though, 
activate_object()'s first parameter should be optional, and default to 
the "first item," instead.

>
> Comment:
> --------
>
>  168         list_item.data_obj = label
>
> Could the ListItem constructor set this even though it is in 
> inner_window?

InnerWindow.__init__ doesn't do anything with "data_obj" either, though 
perhaps it should. Although in a more general sense, the data_obj field 
is rather odd when I look at it again - it's used to generically link 
some "data object" to the field for later manipulation. It's used mostly 
for ListItems, to return the actual Python object associated with the 
selected list item. It's also used in DiskWindow as a way to associate a 
specific field with a specific partition (or slice) during editing.

I'm open to suggestions on making this concept/need simpler, more 
intuitive, and less "hacky."

>
> Comment:
> --------
>
>  170             validate = incremental_validate
> Is an arguement needed to incremental_validate?

No. I want to pass in the function itself, not the result of the 
function. EditField will call the function after each keystroke.


>
> Comment:
> --------
>
> 238 def incremental_validate(edit_field):
>
> I find this name misleading. incremental_validate what?

An IP address. So I suppose "incremental_validate_IP" would be better, yes?

>
> Comment:
> --------
>
> 222 def validate_ip(edit_field):
> 238 def incremental_validate(edit_field):
>
> Wouldn't these be better defined in ../profile/ip_address.py ?

The "grunt work" is done in ip_address.py (IPAddress.convert_address and 
IPAddress.incremental_check are called by these functions). The 
functions here catch errors, and raise an error with a (potentially 
translated) error message pertinent to the UI context in which the error 
occurred.

>
> Comment:
> --------
>
> Support for IPv6?

Not at this time.

>
> cmd/text-install/osol_install/text_install/network_nic_select.py
> -------------------------------------------------------------------------------
>  
>
>
> Looks good.  No new comments.
>
> cmd/text-install/osol_install/text_install/network_type.py
> -------------------------------------------------------------------------------
>  
>
>
> Comment:
> --------
>
> 149         if self.install_profile.no_install_mode:
>
>
> I think it would be valuabel to add a comment describing what
> no_install_mode is -  manual vs no_instal

This check won't be in the final version, once the manual networking 
pieces are available in the backend (it's in here in the meantime so 
that QE can continue writing tests against the manual network config 
screens).

"no_install_mode" itself is explained in text-install.py and referenced 
in install_progress.py.

>
> Comment:
> --------
>
> 184     def validate(self):
>
> Can you add a comment that this function overrides BaseScreen.validate?
> This applies to all functions which override base class functions.

I'm not convinced that this is the best way to document such a thing. 
 From my perspective, I think methods from subclasses are generally 
assumed to either override base class functions or provide extended 
functionality beyond the base class. On the other hand, assumptions tend 
to cause confusion.

The pydoc for NICConfigure does a decent job of conglomerating the 
necessary information - it shows the docstring for validate_loop() 
(coming from BaseScreen), which calls itself out as the caller of 
validate, and validate as coming from NICConfigure.

I guess my main concern is that adding it to the comment of each 
function that overrides another function seems like overkill, and seems 
like there should be a more automated way to make those connections obvious.

>
> cmd/text-install/osol_install/text_install/partition_edit_screen.py
> -------------------------------------------------------------------------------
>  
>
>
> Comment:
> --------
>
>   81         self.slice_mode = slice_mode
>
> If this is this x86 specific would the name self.slice_mode_x86 be 
> helpul?

"self.x86_slice_mode", but yes, I agree adding the 'x86' portion makes 
it more helpful.

>
> Comment:
> --------
>
>   85         if self.slice_mode: # x86, Slice within a partition
> ...
>   90         elif self.is_x86: # x86, Partition on disk
> ...
>   94         else: # SPARC (Slice on disk)
>
> Does this logic miss a possible error case where it's not slice_mode or
> is_x86 or SPARC?
>
> Suggestion:
>
>     if self.slice_mode: # x86, Slice within a partition
> ...
>     elif self.is_x86: # x86, Partition on disk
> ...
>     elif self.is_sparc: <- would need to add this
> ...
>     else:
>         handle error/exception

I don't quite follow. The only potential scenarios are:
x86 partitions
x86 slices
SPARC slices

What other scenario were you thinking might occur?

>
>
> Comment:
> --------
>
>  122     def _show(self):
> and
>  214     def validate(self):
>
> Can you add a comment that this function overrides BaseScreen's?
>
> This applies to all functions which override base class functions.
>
> Comment:
> --------
>
>  139             logging.error('not skipping slice')
>
> Is this a: "all is well" message? If so it could end up confusing the 
> user.

This is an errant debugging message. It'll be removed.

>
>
> Comment:
> --------
>
>  143             except AttributeError:
>
> Whey doesn't this raise or report an error? Please add a comment 
> describing
> this.

In looking at this code again, I'm not sure why I don't re-raise and 
fail here. I'll remove the try/except around this (or possibly re-raise 
a more informative error message), as if this situation occurs, 
something is broken.

>
> Comment:
> --------
>
>  220         if self.is_x86 and not self.slice_mode:
>
> Is a condition to handle SPARC needed here?

The "else" case covers slice editing for both x86 and SPARC in this 
particular instance.

>
> cmd/text-install/osol_install/text_install/timezone.py
> -------------------------------------------------------------------------------
>  
>
>
> Comment:
> --------
>
>  132                 if len(item[2]) > 0:
> ...
>  135                 elif len(item[1]) > 0:
>
> Why not use this?
>
>   if item[2]:
> ...
>   elif item[1]:
> ...
>
> cmd/text-install/osol_install/text_install/timezone_locations.py
> -------------------------------------------------------------------------------
>  
>
>
> Comment:
> --------
>
>  142                 if len(item[2]) > 0:
> ...
>  145                 elif len(item[1]) > 0:
>
> Why not use this?
>
>   if item[2]:
> ...
>   elif item[1]:
> ...
>
>
> cmd/text-install/osol_install/text_install/timezone_regions.py
> -------------------------------------------------------------------------------
>  
>
>
>  116                 if len(item[2]) > 0:
> ...
>  119                 elif len(item[1]) > 0:
>
> Why not use this?
>
>   if item[2]:
> ...
>   elif item[1]:
> ...

Good idea on all 3 counts.

>
> Comment:
> --------
>
> No other new comments, except:
>
> The code in timezone.py,  timezone_locations.py and timezone_regions.py
> seem to have a lot in common. Would developing a common base class, for
> shared code, make sense?

Indeed it would. We'll get on it!

>
>
>
>
>

Reply via email to