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

Remove all builtins.unicode references #13272

Merged
merged 5 commits into from
Jul 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions docs/source/mypy_daemon.rst
Original file line number Diff line number Diff line change
Expand Up @@ -228,11 +228,6 @@ command.
Only allow some fraction of types in the suggested signature to be ``Any`` types.
The fraction ranges from ``0`` (same as ``--no-any``) to ``1``.

.. option:: --try-text

Try also using ``unicode`` wherever ``str`` is inferred. This flag may be useful
for annotating Python 2/3 straddling code.

.. option:: --callsites

Only find call sites for a given function instead of suggesting a type.
Expand Down
4 changes: 0 additions & 4 deletions mypy/dmypy/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,6 @@ def __init__(self, prog: str) -> None:
type=float,
help="Allow anys in types if they go above a certain score (scores are from 0-1)",
)
p.add_argument(
"--try-text", action="store_true", help="Try using unicode wherever str is inferred"
)
p.add_argument(
"--callsites", action="store_true", help="Find callsites instead of suggesting a type"
)
Expand Down Expand Up @@ -525,7 +522,6 @@ def do_suggest(args: argparse.Namespace) -> None:
no_errors=args.no_errors,
no_any=args.no_any,
flex_any=args.flex_any,
try_text=args.try_text,
use_fixme=args.use_fixme,
max_guesses=args.max_guesses,
)
Expand Down
8 changes: 2 additions & 6 deletions mypy/exprtotype.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,9 @@ def expr_to_unanalyzed_type(
column=expr.column,
)
elif isinstance(expr, StrExpr):
return parse_type_string(
expr.value, "builtins.str", expr.line, expr.column, assume_str_is_unicode=True
)
return parse_type_string(expr.value, "builtins.str", expr.line, expr.column)
elif isinstance(expr, BytesExpr):
return parse_type_string(
expr.value, "builtins.bytes", expr.line, expr.column, assume_str_is_unicode=False
)
return parse_type_string(expr.value, "builtins.bytes", expr.line, expr.column)
elif isinstance(expr, UnaryExpr):
typ = expr_to_unanalyzed_type(expr.expr, options, allow_new_syntax)
if isinstance(typ, RawExpressionType):
Expand Down
85 changes: 7 additions & 78 deletions mypy/fastparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,11 +331,7 @@ def parse_type_ignore_tag(tag: Optional[str]) -> Optional[List[str]]:


def parse_type_comment(
type_comment: str,
line: int,
column: int,
errors: Optional[Errors],
assume_str_is_unicode: bool = True,
type_comment: str, line: int, column: int, errors: Optional[Errors]
) -> Tuple[Optional[List[str]], Optional[ProperType]]:
"""Parse type portion of a type comment (+ optional type ignore).

Expand Down Expand Up @@ -366,44 +362,21 @@ def parse_type_comment(
ignored = None
assert isinstance(typ, ast3_Expression)
converted = TypeConverter(
errors,
line=line,
override_column=column,
assume_str_is_unicode=assume_str_is_unicode,
is_evaluated=False,
errors, line=line, override_column=column, is_evaluated=False
).visit(typ.body)
return ignored, converted


def parse_type_string(
expr_string: str,
expr_fallback_name: str,
line: int,
column: int,
assume_str_is_unicode: bool = True,
expr_string: str, expr_fallback_name: str, line: int, column: int
) -> ProperType:
"""Parses a type that was originally present inside of an explicit string,
byte string, or unicode string.
"""Parses a type that was originally present inside of an explicit string.

For example, suppose we have the type `Foo["blah"]`. We should parse the
string expression "blah" using this function.

If `assume_str_is_unicode` is set to true, this function will assume that
`Foo["blah"]` is equivalent to `Foo[u"blah"]`. Otherwise, it assumes it's
equivalent to `Foo[b"blah"]`.

The caller is responsible for keeping track of the context in which the
type string was encountered (e.g. in Python 3 code, Python 2 code, Python 2
code with unicode_literals...) and setting `assume_str_is_unicode` accordingly.
"""
try:
_, node = parse_type_comment(
expr_string.strip(),
line=line,
column=column,
errors=None,
assume_str_is_unicode=assume_str_is_unicode,
)
_, node = parse_type_comment(expr_string.strip(), line=line, column=column, errors=None)
if isinstance(node, UnboundType) and node.original_str_expr is None:
node.original_str_expr = expr_string
node.original_str_fallback = expr_fallback_name
Expand Down Expand Up @@ -1743,14 +1716,12 @@ def __init__(
errors: Optional[Errors],
line: int = -1,
override_column: int = -1,
assume_str_is_unicode: bool = True,
is_evaluated: bool = True,
) -> None:
self.errors = errors
self.line = line
self.override_column = override_column
self.node_stack: List[AST] = []
self.assume_str_is_unicode = assume_str_is_unicode
self.is_evaluated = is_evaluated

def convert_column(self, column: int) -> int:
Expand Down Expand Up @@ -1921,22 +1892,7 @@ def visit_Constant(self, n: Constant) -> Type:
return UnboundType("None", line=self.line)
if isinstance(val, str):
# Parse forward reference.
if (n.kind and "u" in n.kind) or self.assume_str_is_unicode:
return parse_type_string(
n.s,
"builtins.unicode",
self.line,
n.col_offset,
assume_str_is_unicode=self.assume_str_is_unicode,
)
else:
return parse_type_string(
n.s,
"builtins.str",
self.line,
n.col_offset,
assume_str_is_unicode=self.assume_str_is_unicode,
)
return parse_type_string(n.s, "builtins.str", self.line, n.col_offset)
if val is Ellipsis:
# '...' is valid in some types.
return EllipsisType(line=self.line)
Expand Down Expand Up @@ -1990,34 +1946,7 @@ def visit_Num(self, n: Num) -> Type:

# Str(string s)
def visit_Str(self, n: Str) -> Type:
# Note: we transform these fallback types into the correct types in
# 'typeanal.py' -- specifically in the named_type_with_normalized_str method.
# If we're analyzing Python 3, that function will translate 'builtins.unicode'
# into 'builtins.str'. In contrast, if we're analyzing Python 2 code, we'll
# translate 'builtins.bytes' in the method below into 'builtins.str'.

# Do a getattr because the field doesn't exist in 3.8 (where
# this method doesn't actually ever run.) We can't just do
# an attribute access with a `# type: ignore` because it would be
# unused on < 3.8.
kind: str = getattr(n, "kind") # noqa

if "u" in kind or self.assume_str_is_unicode:
return parse_type_string(
n.s,
"builtins.unicode",
self.line,
n.col_offset,
assume_str_is_unicode=self.assume_str_is_unicode,
)
else:
return parse_type_string(
n.s,
"builtins.str",
self.line,
n.col_offset,
assume_str_is_unicode=self.assume_str_is_unicode,
)
return parse_type_string(n.s, "builtins.str", self.line, n.col_offset)

# Bytes(bytes s)
def visit_Bytes(self, n: Bytes) -> Type:
Expand Down
26 changes: 3 additions & 23 deletions mypy/plugins/ctypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,6 @@
)


def _get_bytes_type(api: "mypy.plugin.CheckerPluginInterface") -> Instance:
"""Return the type corresponding to bytes on the current Python version.

This is bytes in Python 3, and str in Python 2.
"""
return api.named_generic_type(
"builtins.bytes" if api.options.python_version >= (3,) else "builtins.str", []
)


def _get_text_type(api: "mypy.plugin.CheckerPluginInterface") -> Instance:
"""Return the type corresponding to Text on the current Python version.

This is str in Python 3, and unicode in Python 2.
"""
return api.named_generic_type(
"builtins.str" if api.options.python_version >= (3,) else "builtins.unicode", []
)


def _find_simplecdata_base_arg(
tp: Instance, api: "mypy.plugin.CheckerPluginInterface"
) -> Optional[ProperType]:
Expand Down Expand Up @@ -221,9 +201,9 @@ def array_value_callback(ctx: "mypy.plugin.AttributeContext") -> Type:
if isinstance(tp, AnyType):
types.append(AnyType(TypeOfAny.from_another_any, source_any=tp))
elif isinstance(tp, Instance) and tp.type.fullname == "ctypes.c_char":
types.append(_get_bytes_type(ctx.api))
types.append(ctx.api.named_generic_type("builtins.bytes", []))
elif isinstance(tp, Instance) and tp.type.fullname == "ctypes.c_wchar":
types.append(_get_text_type(ctx.api))
types.append(ctx.api.named_generic_type("builtins.str", []))
else:
ctx.api.msg.fail(
'Array attribute "value" is only available'
Expand All @@ -245,7 +225,7 @@ def array_raw_callback(ctx: "mypy.plugin.AttributeContext") -> Type:
or isinstance(tp, Instance)
and tp.type.fullname == "ctypes.c_char"
):
types.append(_get_bytes_type(ctx.api))
types.append(ctx.api.named_generic_type("builtins.bytes", []))
else:
ctx.api.msg.fail(
'Array attribute "raw" is only available'
Expand Down
2 changes: 1 addition & 1 deletion mypy/stubgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def args_str(self, args: Iterable[Type]) -> str:
The main difference from list_str is the preservation of quotes for string
arguments
"""
types = ["builtins.bytes", "builtins.unicode"]
types = ["builtins.bytes", "builtins.str"]
res = []
for arg in args:
arg_str = arg.accept(self)
Expand Down
28 changes: 0 additions & 28 deletions mypy/suggestions.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,6 @@ def __init__(
json: bool,
no_errors: bool = False,
no_any: bool = False,
try_text: bool = False,
flex_any: Optional[float] = None,
use_fixme: Optional[str] = None,
max_guesses: Optional[int] = None,
Expand All @@ -262,7 +261,6 @@ def __init__(

self.give_json = json
self.no_errors = no_errors
self.try_text = try_text
self.flex_any = flex_any
if no_any:
self.flex_any = 1.0
Expand Down Expand Up @@ -401,12 +399,6 @@ def get_default_arg_types(self, fdef: FuncDef) -> List[Optional[Type]]:
for arg in fdef.arguments
]

def add_adjustments(self, typs: List[Type]) -> List[Type]:
if not self.try_text or self.manager.options.python_version[0] != 2:
Copy link
Member

Choose a reason for hiding this comment

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

It looks like whole --try-text argument (Try using unicode wherever str is inferred, according to help) is not very useful now. So can probably be deleted (together with tests).

return typs
translator = StrToText(self.named_type)
return dedup(typs + [tp.accept(translator) for tp in typs])

def get_guesses(
self,
is_method: bool,
Expand All @@ -420,7 +412,6 @@ def get_guesses(
This focuses just on the argument types, and doesn't change the provided return type.
"""
options = self.get_args(is_method, base, defaults, callsites, uses)
options = [self.add_adjustments(tps) for tps in options]

# Take the first `max_guesses` guesses.
product = itertools.islice(itertools.product(*options), 0, self.max_guesses)
Expand Down Expand Up @@ -775,8 +766,6 @@ def score_type(self, t: Type, arg_pos: bool) -> int:
return 10
if isinstance(t, CallableType) and (has_any_type(t) or is_tricky_callable(t)):
return 10
if self.try_text and isinstance(t, Instance) and t.type.fullname == "builtins.str":
return 1
return 0

def score_callable(self, t: CallableType) -> int:
Expand Down Expand Up @@ -909,23 +898,6 @@ def visit_callable_type(self, t: CallableType) -> str:
return f"Callable[{arg_str}, {t.ret_type.accept(self)}]"


class StrToText(TypeTranslator):
def __init__(self, named_type: Callable[[str], Instance]) -> None:
self.text_type = named_type("builtins.unicode")

def visit_type_alias_type(self, t: TypeAliasType) -> Type:
exp_t = get_proper_type(t)
if isinstance(exp_t, Instance) and exp_t.type.fullname == "builtins.str":
return self.text_type
return t.copy_modified(args=[a.accept(self) for a in t.args])

def visit_instance(self, t: Instance) -> Type:
if t.type.fullname == "builtins.str":
return self.text_type
else:
return super().visit_instance(t)


TType = TypeVar("TType", bound=Type)


Expand Down
2 changes: 0 additions & 2 deletions mypy/test/testfinegrained.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,6 @@ def maybe_suggest(self, step: int, server: Server, src: str, tmp_dir: str) -> Li
callsites = "--callsites" in flags
no_any = "--no-any" in flags
no_errors = "--no-errors" in flags
try_text = "--try-text" in flags
m = re.match("--flex-any=([0-9.]+)", flags)
flex_any = float(m.group(1)) if m else None
m = re.match(r"--use-fixme=(\w+)", flags)
Expand All @@ -304,7 +303,6 @@ def maybe_suggest(self, step: int, server: Server, src: str, tmp_dir: str) -> Li
json=json,
no_any=no_any,
no_errors=no_errors,
try_text=try_text,
flex_any=flex_any,
use_fixme=use_fixme,
callsites=callsites,
Expand Down
15 changes: 2 additions & 13 deletions mypy/typeanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,7 @@ def analyze_literal_param(self, idx: int, arg: Type, ctx: Context) -> Optional[L
return [
LiteralType(
value=arg.original_str_expr,
fallback=self.named_type_with_normalized_str(arg.original_str_fallback),
fallback=self.named_type(arg.original_str_fallback),
line=arg.line,
column=arg.column,
)
Expand Down Expand Up @@ -1210,7 +1210,7 @@ def analyze_literal_param(self, idx: int, arg: Type, ctx: Context) -> Optional[L
return None

# Remap bytes and unicode into the appropriate type for the correct Python version
fallback = self.named_type_with_normalized_str(arg.base_type_name)
fallback = self.named_type(arg.base_type_name)
assert isinstance(fallback, Instance)
return [LiteralType(arg.literal_value, fallback, line=arg.line, column=arg.column)]
elif isinstance(arg, (NoneType, LiteralType)):
Expand Down Expand Up @@ -1357,17 +1357,6 @@ def anal_var_def(self, var_def: TypeVarLikeType) -> TypeVarLikeType:
def anal_var_defs(self, var_defs: Sequence[TypeVarLikeType]) -> List[TypeVarLikeType]:
return [self.anal_var_def(vd) for vd in var_defs]

def named_type_with_normalized_str(self, fully_qualified_name: str) -> Instance:
"""Does almost the same thing as `named_type`, except that we immediately
unalias `builtins.bytes` and `builtins.unicode` to `builtins.str` as appropriate.
"""
python_version = self.options.python_version
if python_version[0] == 2 and fully_qualified_name == "builtins.bytes":
fully_qualified_name = "builtins.str"
if python_version[0] >= 3 and fully_qualified_name == "builtins.unicode":
fully_qualified_name = "builtins.str"
return self.named_type(fully_qualified_name)

def named_type(
self,
fully_qualified_name: str,
Expand Down
4 changes: 0 additions & 4 deletions mypy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2406,10 +2406,6 @@ def value_repr(self) -> str:
# Note: 'builtins.bytes' only appears in Python 3, so we want to
# explicitly prefix with a "b"
return "b" + raw
elif fallback_name == "builtins.unicode":
# Similarly, 'builtins.unicode' only appears in Python 2, where we also
# want to explicitly prefix
return "u" + raw
else:
# 'builtins.str' could mean either depending on context, but either way
# we don't prefix: it's the "native" string. And of course, if value is
Expand Down