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 4 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
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
79 changes: 7 additions & 72 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,13 @@ 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
Copy link
Member

Choose a reason for hiding this comment

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

This now became unused


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
24 changes: 0 additions & 24 deletions mypy/suggestions.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,12 +401,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 +414,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 @@ -909,23 +902,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
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