Skip to content
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

ocap discipline aided by static typing #24

Open
wants to merge 29 commits into
base: master
Choose a base branch
from

Conversation

dckc
Copy link
Contributor

@dckc dckc commented Sep 21, 2016

I'd like to get your take on this approach with static type annotations.

  • pros:
    • provided essential clues for me to get my head around the code
    • it should provide auto-complete and the like in intellij (or even emacs, if I bothered to set it up)
  • cons:
    • they represent a maintenance burden
      • the tools are getting better, but this style is not widely adopted in the python community
    • They perhaps clutter up the code.
    • They can give a false sense of security. For a while I just followed my nose through the mypy error messages with flycheck. With rust or haskell or scala, this is a nearly foolproof approach to refactoring. Not so with mypy, especially since it's silent by default in many cases where it can't tell whether the code is well-typed.

I could perhaps remove them once I'm done doing the ocap style stuff.

Meanwhile, a couple noteable bits of progress:

  • 76eaed3 is an automated bulk-edit: pathlib_edit.py changes open(path, 'rb') to path.open('rb') and os.path.join(self._path, 'configure') to self._path / 'configure' etc. I was OK to do it by hand for the first few files, but my eyes started to glaze over while doing it for catalog.py.
    • I tried to rebase my other edits on top of it, but that got unmanageable, so I did a merge. Even that was pretty hairy. I'm somewhat new to git.
    • the results are incorrect in the cases such as config.DIR_RESOURCES / filename but I'm not sure how I want to address that config stuff yet.
  • db99f02 is my first working unit test, building up to a handful of such tests in 0ba5835
    • The good news is: applying ocap discipline does result in testable code as intended.
    • The bad news is: testing found bugs introduced in refactoring that weren't found by mypy.

edit tool is [pathlib_edit.py][1]

Two tweaks in repository.py were done manually.

[1]: https://gist.github.com/dckc/40c8caf4c1dc0027ac0d3b1fdbb251d2
  - 4 space indentation
  - 79 characater line length
While get_data(), like import, is actually runtime I/O,
we consider access to design-time constants as if it
were access to any other static data (string, integer, ...).
  - no powerful imports: os, subprocess, ...
    - copyfileobj is powerless: file access is passed in
    - PurePosixPath for syntax manipulation is also powerless
  - use PathExt rather than strings for access to files
    - allfiles KLUDGE: navigation thru absolute paths
    - PathTFix.__truediv__ Self type work-around (for p / sub)
    - cast .iterdir() result because our Self type work-around
      isn't smart enough
    - open() -> path.open()
  - pass urlopen, subprocess, random to Distfile as a distfile.Access
    - simplify, export UrlopenFn: always returns BinaryIO
    - util.RunCommand class represents subprocess interface
    - declare type for util.diff mkPopen arg
  - Distfile.__init__() static types (e.g. Hash) help with refactoring
    - complete static types for all Distfile methods
  - log.warning() is only declared to take a str. hm.
  - DiffCreator gets subprocess
  - BuildDirectory gets platform
  - FileHandle etc. get an Access (subprocess etc.)
    - add check_output to RunCommand interface
  - Builder interface common to HostBuilder and TargetBuilder
  - refactor allpath KLUDGE using PathExt.platform() and
    config.config_path_fn
    - use single-assignment idiom for tar vs bsdtar
  - prune resource_directory
    - restore DIR_RESOURCES but only as a PurePath for use with check_call()
  - Distfile needs a RandomT
  - never mind PathTFix generic Self
    It didn't work -- turned into Any -- and hid a few type errors.
  - static types rather than **kwargs for op_distfile etc.
  - NamedTuple rather than dict for deferred package info
  - types for version (sometimes a class), checksum (always str)
    - class AnyVersion reifies type common to SimpleVersion, FullVersion
  - master_sites, patches are Set[str], not List[str]
  - move `build_depends = set()` to else branch to help mypy
  - clarify builder.Access name
  - prune more resource_directory dead code
  - two blank lines before class, def
  - 4 space indent
  - 79 character line limit
  - unused: SimpleVersion, lib_depends, files
  - two lines before class
  - spaces around / and after :
  - }); formatting
run with `py.test`, for example
add __init__.py for use with pkgutil.get_data

perhaps a bit of a kludge? but a harmless one
and move test_suite into `src` dir
@EdSchouten
Copy link
Member

I like statically typed languages a lot. I was actually not aware that Python supported this kind of stuff. That said, this is something that needs explicit tooling to validate, right? On my Mac:

Python 3.5.2 (default, Aug 16 2016, 05:35:40) 
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def a(x: int, y: int) -> int:
...     return x + y
... 
>>> a([1, 2], [3, 4])
[1, 2, 3, 4]

We should eventually consider writing some kind of hook for this to disallow changes that break the typing.

Anyway, you've got the green light from my side to work on this. I'd love to get something like this upstreamed. Feel free to come up with a set of changes that only include the static typing (no style changes or ocap related changes) and I'll make sure it lands. Thanks for working on this!

@dckc
Copy link
Contributor Author

dckc commented Sep 23, 2016

The type declarations are indeed ignored at runtime. Static type-checking is done by other tools such as mypy.

Adding static type declarations in a separate branch... hmm... I guess I could try that, though I couldn't test them, and recent experience shows I don't get them right without testing. The ocap changes are necessary for unit testing.

@dckc
Copy link
Contributor Author

dckc commented Jan 1, 2018

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.

2 participants