Skip to content

implement type-hints for all our functions #42

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

Closed
wants to merge 15 commits into from

Conversation

igalic
Copy link
Collaborator

@igalic igalic commented Aug 28, 2017

as a first step, we'll ad mypy static analyzer to check those.
This should give us extra (offline) guarantees about those types.

@igalic
Copy link
Collaborator Author

igalic commented Aug 28, 2017

this first attempt at #39, is currently failing to bootstrap:

libiocage/cli/__init__.py:38: error: Module has no attribute "_verify_python3_env"
libiocage/cli/__init__.py:102: error: Unexpected keyword argument "message" for "version_option"
/home/igalic/.pyenv/versions/3.6.1/lib/mypy/typeshed/third_party/2and3/click/decorators.pyi:174: note: "version_option" defined here
 ǃ  ~/s/t/libiocage  ╍╍ type-hints 

@gronke
Copy link
Member

gronke commented Aug 28, 2017

Do we need to add an entry to requirements.txt?

@igalic
Copy link
Collaborator Author

igalic commented Aug 28, 2017

new set of errors:

libiocage/lib/helpers.py:52: error: Invalid tuple literal type
libiocage/lib/Jail.py:67: error: Name 'libzfs' is not defined
libiocage/lib/Jail.py:68: error: Invalid type "libiocage.lib.Host"
libiocage/lib/Jail.py:69: error: Invalid type "libiocage.lib.Logger"
libiocage/cli/__init__.py:38: error: Module has no attribute "_verify_python3_env"
libiocage/cli/__init__.py:102: error: Unexpected keyword argument "message" for "version_option"
/home/igalic/.pyenv/versions/3.6.1/lib/mypy/typeshed/third_party/2and3/click/decorators.pyi:174: note: "version_option" defined here

i am working speculatively here, so your help would be greatly appreciated!

@igalic
Copy link
Collaborator Author

igalic commented Aug 28, 2017

@gronke: Do we need to add an entry to requirements.txt?

i don't think so: it's not a run-time requirement, only for test, hence an entry in test_requires(), but not in requirements.txt

@@ -60,19 +62,24 @@ class Jail:
release (stored in `zpool/iocage/base/<RELEASE>)
"""

def __init__(self, data={}, zfs=None, host=None, logger=None, new=False):
def __init__(self,
data: Union[str, dict]={},
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this a union? It is never a string, but always a dict.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

because that's exactly what the pydoc comment below says

Copy link
Contributor

Choose a reason for hiding this comment

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

lol, coffee. You're right, sorry!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah, but, we should still figure out if we want to simplify that

as i have done with the execs that would've allowed Union[str, List[str]]

Copy link
Collaborator Author

@igalic igalic left a comment

Choose a reason for hiding this comment

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

how to check fully.qualified.class.names?

def __init__(self, data={}, zfs=None, host=None, logger=None, new=False):
def __init__(self,
data: Union[str, dict]={},
zfs: Optional[libzfs.ZFS]=None,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i can't verify this on linux ☹

libiocage/lib/Jail.py:67: error: Name 'libzfs' is not defined

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

which means we won't be able to verify this on Travis…

Copy link
Member

Choose a reason for hiding this comment

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

Indeed that's a problem. Can we provide a Typing file for libzfs?

data: Union[str, dict]={},
zfs: Optional[libzfs.ZFS]=None,
host: Optional[libiocage.lib.Host]=None,
logger: Optional[libiocage.lib.Logger]=None,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

for these two, i'm getting

libiocage/lib/Jail.py:68: error: Invalid type "libiocage.lib.Host"
libiocage/lib/Jail.py:69: error: Invalid type "libiocage.lib.Logger"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

new data! this is a module, not a type

how do i access the actual type, or the class?

Copy link
Member

@gronke gronke Aug 30, 2017

Choose a reason for hiding this comment

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

libiocage.lib.Host.Host 🌮

Python interprets the file itself as module. Within that module there's the Host class.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

but that's uglt 😅

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I know! The other option is to put everything in one file. Let's quickly forget that.

Yet another solution is to mess with sys.path, but @william-gr taught me this is a no-go for libraries and bad practice everywhere else.

I think lib/__init__.py is an appropriate solution: The public exposed classes are available as libiocage.Jail, libiocage.Release, etc when importing the directory (for development) or importing globally installed libiocage.

Copy link
Collaborator Author

@igalic igalic left a comment

Choose a reason for hiding this comment

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

how to handle multiple return values?

if isinstance(command, str):
command = [command]
def exec(command, logger=None, ignore_error=False) -> (
subprocess.Popen, str, str,):
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this is… wrong, apparently:

libiocage/lib/helpers.py:52: error: Invalid tuple literal type

@igalic igalic force-pushed the type-hints branch 3 times, most recently from 796b72e to 680a198 Compare August 31, 2017 08:09
@igalic
Copy link
Collaborator Author

igalic commented Aug 31, 2017

UPDATE!!
after generating types interfaces for the classes missing them (see: truenas/py-libzfs#4 , vstakhov/libucl#168 & foutaise/texttable#22 ), i now have the following set of errors:

libiocage/lib/helpers.py:52: error: Invalid tuple literal type
libiocage/lib/Jail.py:138: error: Incompatible types in assignment (expression has type "RCConf", variable has type None)
libiocage/lib/Jail.py:161: error: Incompatible types in assignment (expression has type Type[NullFSBasejailStorage], variable has type Type[ZFSBasejailStorage])
libiocage/lib/Jail.py:538: error: Argument 1 to "append" of "list" has incompatible type "Network"; expected "str"
libiocage/lib/Jail.py:542: error: "str" has no attribute "teardown"
libiocage/lib/Jail.py:730: error: Value of type None is not indexable
libiocage/lib/Jail.py:736: error: Value of type None is not indexable
libiocage/lib/Jail.py:782: error: Incompatible types in assignment (expression has type "str", variable has type None)
libiocage/lib/Jail.py:796: error: "str" has no attribute "mountpoint"
libiocage/lib/Jail.py:852: error: Type[Dict[Any, Any]] has no attribute "__dir__"
libiocage/lib/Distribution.py:110: error: Need type annotation for variable
libiocage/lib/Distribution.py:115: error: Incompatible types in assignment (expression has type List[str], variable has type "str")
libiocage/lib/Distribution.py:128: error: "Distribution" has no attribute "host"
libiocage/cli/__init__.py:38: error: Module has no attribute "_verify_python3_env"
libiocage/cli/__init__.py:103: error: Unexpected keyword argument "message" for "version_option"
/usr/local/lib/mypy/typeshed/third_party/2and3/click/decorators.pyi:174: note: "version_option" defined here

Copy link
Collaborator Author

@igalic igalic left a comment

Choose a reason for hiding this comment

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

our different Basejail Storage thingies are all… wrong…ish.

libiocage.lib.NullFSBasejailStorage.NullFSBasejailStorage,
libiocage.lib.ZFSBasejailStorage.ZFSBasejailStorage,
None,
] = None
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I have no idea what i'm doing

] = None

if self.config["basejail_type"] == "standalone":
backend = libiocage.lib.StandaloneJailStorage.StandaloneJailStorage
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

libiocage/lib/Jail.py:163: error: Incompatible types in assignment (expression has type Type[StandaloneJailStorage], variable has type "Union[StandaloneJailStorage, NullFSBasejailStorage, ZFSBasejailStorage, None]")

Copy link
Member

Choose a reason for hiding this comment

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

Why is it type Type[StandaloneJailStorage], but not type "Type[Union[StandaloneJailStorage, ...."

] = None

if self.config["basejail_type"] == "standalone":
backend = libiocage.lib.StandaloneJailStorage.StandaloneJailStorage

if self.config["basejail_type"] == "zfs":
backend = libiocage.lib.ZFSBasejailStorage.ZFSBasejailStorage
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

libiocage/lib/Jail.py:166: error: Incompatible types in assignment (expression has type Type[ZFSBasejailStorage], variable has type "Union[StandaloneJailStorage, NullFSBasejailStorage, ZFSBasejailStorage, None]")

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

for line 169, we get:

libiocage/lib/Jail.py:169: error: Incompatible types in assignment (expression has type Type[NullFSBasejailStorage], variable has type "Union[StandaloneJailStorage, NullFSBasejailStorage, ZFSBasejailStorage, None]")

and finally, for line 172, we get:

libiocage/lib/Jail.py:172: error: Too many arguments for "apply"

@@ -2,7 +2,7 @@
# Run pep8 on all .py files in all subfolders

tmpafter=$(mktemp)
find ./libiocage/ -name \*.py -exec flake8 --ignore=E203,W391 {} + | grep -v "./libiocage/__init__.py" > ${tmpafter}
find ./libiocage/ -name \*.py -exec flake8 --ignore=E203,E241,W391 {} + | grep -v "./libiocage/__init__.py" > ${tmpafter}
Copy link
Member

Choose a reason for hiding this comment

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

What is E241 good for? The documentation says E241 (*) | multiple spaces after ‘,’, but I can't spot why we need to ignore this rule.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree. I added the ignore for spaces after : so we shouldn't need to add another.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

without this,

./libiocage/lib/Jail.py:72:23: E241 multiple spaces after ':'
./libiocage/lib/Jail.py:73:22: E241 multiple spaces after ':'
./libiocage/lib/Jail.py:74:23: E241 multiple spaces after ':'
./libiocage/lib/Jail.py:76:22: E241 multiple spaces after ':'

i've basically just followed @skarekrow's lead of how to indent… structures.

as a first step, we'll ad mypy static analyzer to check those.
This should give us extra (offline) guarantees about those types.
in the process i also found a few instances where we were mutating input
parameters — unnecessarily so.

n.b.: libiocage.lib.Foo is the module, libiocage.lib.Foo.Foo is the
actual class that we want
explicitly, with Tuple[foo, bar], not implicitly with (foo, bar,)
@igalic
Copy link
Collaborator Author

igalic commented Sep 1, 2017

i'd like to close this pr.
it was a good learning experience, but it's a complete mess, especially after rebasing #37
i've opened #54, where i'll try to do this over, and, more gradually…

@igalic igalic closed this Sep 1, 2017
@igalic igalic deleted the type-hints branch September 3, 2017 19:19
Sign up for free to 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