【问题标题】:Type hinting on a context manager processing paths上下文管理器处理路径上的类型提示
【发布时间】:2019-03-09 18:34:31
【问题描述】:

代码(在@juanpa.arrivillaga 的帮助下修复:

"""Helpers that can be used for context management."""

import logging
import os
from contextlib import contextmanager
from pathlib import Path
from typing import Union, Iterator, Optional

_LOGGER = logging.getLogger(__name__)


@contextmanager
def working_directory(temporary_path: Union[Path, str], initial_path: Optional[Union[Path, str]] = None) -> Iterator[None]:
    """Changes working directory, and returns to `initial_path` on exit. It's needed for PRAW for example,
    because it looks for praw.ini in Path.cwd(), but that file could be kept in a different directory.

    `initial_path` can be used for example to change working directory relative to the script path, or
    to end up in a different directory than Path.cwd() of the calling script.

    Inspiration: https://stackoverflow.com/questions/41742317/how-can-i-change-directory-with-python-pathlib
    """
    _LOGGER.debug('Working directory of the calling script: %s', Path.cwd())
    _LOGGER.debug('temporary_path = %s', temporary_path)
    _LOGGER.debug('initial_path = %s', initial_path)

    if not isinstance(temporary_path, (Path, str)):
        raise TypeError('"temporary_path" is not of type `Path` or `str`')

    if initial_path is None:
        initial_path = Path.cwd()
    else:
        initial_path = Path(initial_path).absolute()
        if not initial_path.is_dir():
            initial_path = initial_path.parent

    try:
        os.chdir(initial_path / temporary_path)
        _LOGGER.debug('Temporarily changed working directory to: %s', Path.cwd())
        yield
    finally:
        os.chdir(initial_path)

我所做的输入注释是否正确?

另外,有没有更 Pythonic 的方式来编写这个函数?你会改变什么?我也会在 CodeReview 中发布。

【问题讨论】:

  • @juanpa.arrivillaga ...但是这些行迫使initial_path成为Pathif initial_path is not Path.cwd():initial_path = Path(initial_path).absolute()
  • 不,绝对不会。如果if initial_path is not Path.cwd()false 会怎样(顺便说一句,它将永远是false)。只需转换函数顶部的 Path 对象即可。你的if 甚至没有else
  • 你是对的@juanpa.arrivillaga,你是个天才

标签: python python-3.x mypy


【解决方案1】:

打字很好,你只是在你的代码中有由 mypy 揭示的错误。如果initial_pathtemporary_path 都是str,那么这将失败。这就是它抱怨的原因。

您只在一个没有else 的分支中转换为Path(不好的做法,IMO),所以当您到达线路时:

initial_path / temporary_path 可能这两个都是str

注意,mypy 不知道这一点,但if initial_path is not Path.cwd() 不正确。这个陈述永远是假的。不要将事物与is 进行比较,除非您指的是对象身份,在这种情况下,您不需要。

考虑:

>>> from pathlib import Path
>>> Path().cwd() is  Path().cwd()
False

只要做:

def working_directory(
    temporary_path: Union[Path, str],
    initial_path: Union[Path, str] = Path.cwd()
) -> Iterator[None]:
    temporary_path = Path(temporary_path)
    initial_path = Path(initial_path)

在函数的开头。

【讨论】:

  • 根据this answer,在这种情况下,上下文管理器的正确类型提示是def working_directory(...) -> ContextManager[Iterator[None]],其中ContextManager是从typing模块导入的
猜你喜欢
  • 2018-09-18
  • 2021-07-09
  • 1970-01-01
  • 1970-01-01
  • 2020-06-07
  • 1970-01-01
  • 2016-05-30
  • 2012-01-01
  • 1970-01-01
相关资源
最近更新 更多