Skip to content
This repository was archived by the owner on Feb 22, 2020. It is now read-only.

Inquisitive Investigators #5

Merged
merged 187 commits into from
Jan 26, 2020
Merged

Conversation

Den4200
Copy link
Member

@Den4200 Den4200 commented Jan 17, 2020

No description provided.

lemonsaurus pushed a commit that referenced this pull request Jan 26, 2020
lemonsaurus pushed a commit that referenced this pull request Jan 26, 2020
Fixes Issue #5.  Makes paths agnostitic to os.
lemonsaurus pushed a commit that referenced this pull request Jan 26, 2020
Most of enigma configs. Not much testing. Any reconfigurations should go towards master branch unless very significant.
lemonsaurus pushed a commit that referenced this pull request Jan 26, 2020
Background images and animation
lemonsaurus pushed a commit that referenced this pull request Jan 26, 2020
lemonsaurus pushed a commit that referenced this pull request Jan 26, 2020
lemonsaurus pushed a commit that referenced this pull request Jan 26, 2020
Adds config load + save for lat/lon from geoip, closes #1
@lemonsaurus
Copy link
Member

Lint failing:

./inquisitive-investigators/rex_explorer/footer/footer.py:9:1: F403 'from .commands import *' used; unable to detect undefined names
./inquisitive-investigators/rex_explorer/footer/footer.py:90:17: F405 'AboutPopup' may be undefined, or defined from star imports: .commands
./inquisitive-investigators/rex_explorer/footer/footer.py:101:17: F405 'EditPopup' may be undefined, or defined from star imports: .commands
./inquisitive-investigators/rex_explorer/footer/footer.py:112:17: F405 'PhotoPopup' may be undefined, or defined from star imports: .commands
./inquisitive-investigators/rex_explorer/footer/footer.py:123:17: F405 'CopyPopup' may be undefined, or defined from star imports: .commands
./inquisitive-investigators/rex_explorer/footer/footer.py:134:17: F405 'Mkdir' may be undefined, or defined from star imports: .commands
./inquisitive-investigators/rex_explorer/footer/footer.py:145:17: F405 'CreatePopup' may be undefined, or defined from star imports: .commands
./inquisitive-investigators/rex_explorer/footer/footer.py:176:17: F405 'RenamePopup' may be undefined, or defined from star imports: .commands
./inquisitive-investigators/rex_explorer/footer/footer.py:187:17: F405 'DeletePopup' may be undefined, or defined from star imports: .commands
./inquisitive-investigators/rex_explorer/footer/footer.py:198:17: F405 'QuitPopup' may be undefined, or defined from star imports: .commands
./inquisitive-investigators/rex_explorer/footer/commands.py:12:1: F401 'kivy.properties.StringProperty' imported but unused
./inquisitive-investigators/rex_explorer/footer/commands.py:27:24: F821 undefined name 'Footer'
./inquisitive-investigators/rex_explorer/footer/commands.py:99:29: F821 undefined name 'Footer'
./inquisitive-investigators/rex_explorer/footer/commands.py:126:29: F821 undefined name 'Footer'
./inquisitive-investigators/rex_explorer/footer/commands.py:227:29: F821 undefined name 'Footer'
./inquisitive-investigators/rex_explorer/footer/commands.py:302:29: F821 undefined name 'Footer'
./inquisitive-investigators/rex_explorer/terminal/terminal.py:13:1: F401 '.termio.TerminalInput' imported but unused
./inquisitive-investigators/rex_explorer/core/main.py:11:1: E402 module level import not at top of file
./inquisitive-investigators/rex_explorer/core/main.py:12:1: E402 module level import not at top of file
./inquisitive-investigators/rex_explorer/core/main.py:13:1: E402 module level import not at top of file
./inquisitive-investigators/rex_explorer/core/main.py:15:1: E402 module level import not at top of file
./inquisitive-investigators/rex_explorer/core/main.py:16:1: E402 module level import not at top of file
./inquisitive-investigators/rex_explorer/core/main.py:16:1: F401 '..footer.footer.Footer' imported but unused
./inquisitive-investigators/rex_explorer/core/main.py:17:1: E402 module level import not at top of file
./inquisitive-investigators/rex_explorer/core/main.py:17:1: F401 '..terminal.terminal.Terminal' imported but unused
./inquisitive-investigators/rex_explorer/core/main.py:18:1: E402 module level import not at top of file
./inquisitive-investigators/rex_explorer/core/main.py:18:1: F401 '..manager.browser.FileBrowser' imported but unused
./inquisitive-investigators/rex_explorer/core/main.py:19:1: E402 module level import not at top of file
./inquisitive-investigators/rex_explorer/core/main.py:20:1: E402 module level import not at top of file
./inquisitive-investigators/rex_explorer/core/main.py:21:1: E402 module level import not at top of file
./inquisitive-investigators/rex_explorer/utils/utils.py:51:14: F821 undefined name 'RV'
./inquisitive-investigators/rex_explorer/manager/browser.py:11:1: F401 'kivy.uix.recycleview.views._cached_views' imported but unused
./inquisitive-investigators/rex_explorer/manager/browser.py:11:1: F401 'kivy.uix.recycleview.views._view_base_cache' imported but unused
./inquisitive-investigators/rex_explorer/manager/browser.py:12:19: W291 trailing whitespace
./inquisitive-investigators/rex_explorer/manager/browser.py:14:2: E261 at least two spaces before inline comment
./inquisitive-investigators/rex_explorer/manager/browser.py:20:1: F401 '.file.NewFile' imported but unused
./inquisitive-investigators/rex_explorer/manager/file.py:43:1: W293 blank line contains whitespace
./inquisitive-investigators/rex_explorer/manager/file.py:47:18: W291 trailing whitespace
./inquisitive-investigators/rex_explorer/photo_viewer/image.py:9:1: W293 blank line contains whitespace
./inquisitive-investigators/rex_explorer/photo_viewer/viewer.py:9:1: F401 '.image.DynamicImage' imported but unused
./inquisitive-investigators/rex_explorer/photo_viewer/viewer.py:14:1: E302 expected 2 blank lines, found 1
./inquisitive-investigators/rex_explorer/editor/editorIO.py:4:1: F401 'kivy.uix.scatterlayout.ScatterLayout' imported but unused
./inquisitive-investigators/rex_explorer/editor/save.py:8:29: F821 undefined name 'EditorIO'
./inquisitive-investigators/rex_explorer/editor/editor.py:13:1: F401 '.editorIO.EditorIO' imported but unused

@lemonsaurus lemonsaurus merged commit d7b3150 into python-discord:master Jan 26, 2020
lemonsaurus pushed a commit that referenced this pull request Jan 26, 2020
Copy link

@inclement inclement left a comment

Choose a reason for hiding this comment

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

Summary

A well structured project producing a nice cohesive gui from well structured code that combines a range of different functionalities.

Version control

Commit quality isn't all that great: many commits only have brief, non-descriptive short messages. It looks like most (all?) commits are from two people, both of whom contributed significantly and with a similar style.

General content and code quality

The code is well divided into different modules, both for Python and kv files. Within these, the code quality is generally good, with content divided into appropriate short functions and concerns well separated. The contributions from both primary developers seem well merged, and code style is consistent throughout the project.

The code is in general good, idiomatic Python. Including type hints is a modern touch. There are good attempts to abstract out constants, although there could be more of this, e.g. to pull style information (app colours etc.) from some central source that can be easily updated. There are sporadic docstrings, but usually not very specific.

It's nice to see a range of interactions covered by the code - some sophisticated text and keyboard handling, complex gui control flow managing multiple interactive widgets displayed simultaneously, and various gui mechanisms like popups (with different content) integrated nicely.

Some things worth more attention are:

  • There isn't enough documentation. Including some docstrings is good, and in some cases the type hints cover slightly for what would otherwise have to be documented, but there are still plenty of places that would benefit from a clearer description of what's going on. This also applies to the general structure of the app, although it's good that you've split things into multiple submodules you do want to try to be clear about how this has been done, for the benefit of future contributors.
  • Similarly with comments, you've generally done a good job keeping methods short and fairly clear, but there are plenty of places where non-obvious things are done that could be clarified.
  • There's some questionable control flow, things like returning in the middle of a function that otherwise appears to operate normally. This kind of thing makes things hard to follow. I've commented on a couple of examples.
  • It's low-hanging fruit, but I have to call out the # This file was planned for use, but we ran out of time - you could have deleted it as easily as making that comment :p

Use of Kivy

The code makes very good, varied use of Kivy. Many different widget types (and Behavior mixins) are used to different purposes, and combined well to make a pleasant and well structured user interface that seems to behave well during different types of interactions. The keyboard handling is a nice touch demonstrating a good understanding of how to handle a combination of hotkeys and text input in different places. It's perhaps a small thing, but the consistent loading of small kv files for each python file is a good app structure.

I think some of the splitting of functionality between kv files and Python files merits more explanation - there's nothing enforcing that on a technical level (this is Python after all), but it's a good example of where better documentation could make it clear where concerns are being left to kv and where they're left to Python. A good example would be for widgets where all the functionality is in the kv rule, so the Python side otherwise looks like a trivial class definition. This is a subtler point though that's perhaps partly subjective: it only becomes important in more advanced applications, and isn't something the Kivy documentation emphasises.

README

The README is short, but clear, and includes both installation and usage details. The use of pipenv is a pleasant way to ensure a consistent installation experience. I always like to see a screenshot.

The license of the code is not specified (although it this context it's understood to be inherited from the code jam).


def on_update(
self, browser_side: str,
state: int, files: List[str]

Choose a reason for hiding this comment

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

Pretty minor, but this would be clearer with 1 argument per line, especially with the type hints adding noise.

background_color = ColorProperty((0, 0, 0, 1))

font_name = StringProperty(FONT)
font_size = NumericProperty(12.5)

Choose a reason for hiding this comment

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

Using kivy.metrics.sp(12.5) would be better to guarantee similar results on screens with different dpis.

so key presses will work again.
"""
if self._keyboard is None:
self.config_keyboard()

Choose a reason for hiding this comment

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

I'm not sure the keyboard binding was working correctly for me when I tested it, but didn't check in detail, I could be wrong.

}

def __getitem__(self, items: Union[str, Tuple]) -> List[int]:
if isinstance(items, str) or isinstance(items, int):

Choose a reason for hiding this comment

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

This kind of thing is a bit weird, it might be okay but it's clearly working around some specific details of the way you intend this abstraction to be used. Things like this really benefit from documentation - what exactly is this expected to be indexed with, and why?

Choose a reason for hiding this comment

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

isinstance can take an iterable as a second attribute, so this could be if isinstance(items, (str, int)):

"""
if self.prev_selected is not None and self.selected.name == file.name:

self.selected.alpha = 0

Choose a reason for hiding this comment

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

Not to be too picky, but this is a nice example of where the stuff in the if block could be abstracted further to another method. It would be nice to reduce this kind of logic to just if self.prev_selected is not None and self.selected.name == file.name: self._unselect_current_item(). This also makes the control flow clearer, I didn't notice the function could return here until I paid attention to these details of the control structure.


def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.current_dir = str(Path.home())

Choose a reason for hiding this comment

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

Using Path.home() exposed some bugs you have: I have a broken symlink in my home dir, which crashes the app since the file parsing isn't robust enough! Something for a test suite to cover, perhaps ;-)

"""
Captures specific key presses
and executes accordingly.
"""

Choose a reason for hiding this comment

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

This is a good example of a function that merits some commented explanation - it does quite different things depending on the context, and it's hard to understand this only by looking at the code.

self.shell.stop()

if self.cursor_index() < self._cursor_pos:
return False

Choose a reason for hiding this comment

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

Quietly returning in the middle of a function is often an antipattern, I think that's the case here. It's easy to miss this if just looking to the bottom of the function to check what it does, and of course it isn't commented or documented elsewhere.

Copy link

@aeros aeros Feb 2, 2020

Choose a reason for hiding this comment

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

Quietly returning in the middle of a function is often an antipattern

Sorry, but I'd have to disagree with the above statement; I think that's an over-generalization. It's very often necessary or more efficient to have a return that's in the middle rather than the end, when some of the actions (but not all) need to be completed regardless of the return value.

It can sometimes be indicative of an anti-pattern or poor logical structure if it's not at all necessary or better to return in the middle of the function, but I don't think the early return itself is often an anti-pattern.

That being said, I think the docstring should definitely explain what situation causes the function to return false. But it doesn't have to explain every single return in the middle of the function. The reader can extract that information simply by reading over the code, and seeing where the returns are located.

This may not be the best example of average real-world code that requires early returns (due to complexity), but just for demonstration I was recently working on implementing a new feature in Python 3.9 for a new feature in the concurrent.futures module, specifically adding a new argument for the Executor.shutdown() method.

While implementing the feature for ProcessPoolExecutor, I had to familiarize myself with the inner workings of the function _queue_management_worker(), which has a total of 3 returns in the middle. There's also process_worker(), which has two returns in the middle.

If anyone is curious about the details, see https://github.com/python/cpython/blob/78c7183f470b60a39ac2dd0ad1a94d49d1e0b062/Lib/concurrent/futures/process.py

Note: The feature is currently a PR that's in it's final stages, so it's not yet official. Here's the the link if anyone is curious: python/cpython#18057.

Choose a reason for hiding this comment

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

Fair, maybe I overstated it here. I think it's perfectly reasonable to return in the middle of functions in many circumstances, but I also think it's overused and especially creeps in as a bad practice when making things in a rush - slipping in a return is always short-term-easier than restructuring to make the logic clearer :p.

Copy link
Member

@jb3 jb3 left a comment

Choose a reason for hiding this comment

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

Code is Pythonic in places of the project. There is a few issues with naming in places, such as a class called just F which I believe there has to be a better name for. There is also some useless code like saving data to a file and then opening the file again to get that data which while it is not a stylistic Python comment it is not a very Pythonic way of doing things. There are some odd class names such as DIRChoice over DirectoryChoice and Mkdir instead of MakeDirectory or similar. Uppercase variable names are use don occasion which should not be. Legacy syntax is used interchangeably (as mentioned below). There were a few areas where a newline was left after if statements which is a pet peeve of mine.

There are a couple of custom exceptions that have been implemented such as a InvalidBrowser error which is not needed because not only does it trigger regularly but it is almost guaranteed to never trigger as far as I can see. This error and the InvalidSelection error could most likely be replaced with ValueError or if that does not fit then RuntimeError.

In the rex_explorer/core/main.py file there were a lot of config options which could have been converted into a local config file to prevent messy code, as well as this the config options came before the rest of the imports which broke convention.

There was a large usage of legacy syntax for the super function which on it’s own would be okay for back compatibility but there was no need for that here and plus the modern syntax was also used interchangeably with it, an attempt should have been made to unify different syntactical changes to the best of your abilities.

There was a severe lack of documentation among most of the project and while some areas were documented pretty well, for example the utils file, the majority of the code was either documented insufficiently or not at all. There were very few comments as well apart from some commented out code which should not be there.

Usage of modules such as shlex was vey good, though usage could have done with some more comments and documentation explaining what was going on. The usage of a constants file was good, as was the usage of a paths file, but it should probably have been merged with the constants file. Documentation in the utility file was good, but some unused code was commented out and comments were missing.

Commit quality was good overall but certain commits could have done with some better descriptions, commits such as test, refactoring and update README.md & about.txt

README is excellent, contains a screenshot, installation steps for users and developers, licensing information, a summary of the project and overall gave a good introduction to the project.

Pros

  • Good use of shlex
  • Good use of Kivy language
  • Good use of a constants file
  • Good use of pathlib
  • Code was Pythonic and easy to follow in some files
  • Great README

Cons

  • Documentation missing on most functions and classes
  • Commented out code left in, comments with meaningful text left out
  • Some odd class naming
  • Legacy syntax and modern syntax used interchangably

pylint = "*"

[packages]
kivy = "*"
Copy link
Member

Choose a reason for hiding this comment

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

You should pin your dependencies to a specified version or at least to the next major update. This will prevent undefined behaviour for anyone using your project in future should breaking changes to dependencies be made.

## License

All projects will merged into our Code Jam repository, which uses the [MIT license](../LICENSE). Please make sure that if you add assets, the licenses of those assets are compatible with the MIT license.
# Rex Explorer - Inquisitive Investigators
Copy link
Member

Choose a reason for hiding this comment

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

Good readme.

@@ -0,0 +1,10 @@
# This file was planned for use, but we ran out of time
Copy link
Member

Choose a reason for hiding this comment

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

Should be removed in that case.

@@ -0,0 +1,67 @@
#:kivy 1.11.1
Copy link
Member

Choose a reason for hiding this comment

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

Good usage of Kivy language!

@@ -0,0 +1,56 @@
# This file was planned for use, but we ran out of time

from typing import Any, Dict, List, Union
Copy link
Member

Choose a reason for hiding this comment

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

Good import grouping.

from typing import Any, Tuple, Union
import os
import sys
import shlex
Copy link
Member

Choose a reason for hiding this comment

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

Good use of shlex

@@ -0,0 +1,44 @@
from typing import List, Tuple, Union
Copy link
Member

Choose a reason for hiding this comment

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

Good use of a constants file

@@ -0,0 +1,27 @@
from pathlib import Path

Copy link
Member

Choose a reason for hiding this comment

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

This could probably have been merged with the constants file, though the use of pathlib here is excellent.

)


def bytes_conversion(
Copy link
Member

Choose a reason for hiding this comment

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

Solid documentation.

t = 'DIR'

size = '-'
# size = ' '.join(
Copy link
Member

Choose a reason for hiding this comment

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

Unused code should not be commented out, it should be removed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants