Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2d5ef86
✨ Add shortdata stubs
AA-Turner Jun 1, 2021
4b951db
✨ Add data stubs
AA-Turner Jun 1, 2021
b678561
🚚 Move up a directory
AA-Turner Jun 1, 2021
760cfc0
🏷️ Ensure all have return types
AA-Turner Aug 23, 2021
5bd1ea2
🏷️ Start to add private function & variable types
AA-Turner Aug 23, 2021
b59f710
🏷️ More private function types -- `phonenumberutil`
AA-Turner Aug 26, 2021
fb20cfb
🔥 Remove alt_format_63.pyi
AA-Turner Aug 27, 2021
512151a
🎨 Types fixes and additions with retype
AA-Turner Aug 27, 2021
c8e03b8
🏷️ Update type checker exclusions
AA-Turner Aug 27, 2021
553c7a7
🏷️ Fix carrier code in some private functions
AA-Turner Aug 30, 2021
0dc8de2
🔥 Remove stubs for autogenerated files
AA-Turner Aug 30, 2021
60b2c7c
🏷️ Added types for `*data` submodules
AA-Turner Aug 30, 2021
d05cb2b
🏷️ Fixed overloaded types
AA-Turner Aug 31, 2021
ccb3ed6
🏷️ Replaced typing.Optional with PEP 604 union
AA-Turner Sep 1, 2021
e855809
🎨 Formatting tweaks
AA-Turner Sep 1, 2021
4d0f7d5
🚚 Move files to the python/ directory
AA-Turner Sep 1, 2021
977f5ce
🏷️ Replace typing.Union with PEP 604
AA-Turner Sep 1, 2021
4cfe589
🏷️ Replace `typing` abc imports with `collections.abc`
AA-Turner Sep 1, 2021
01c150f
🐛 Fixes from stubtest
AA-Turner Sep 1, 2021
66e3756
👷 Add `run_stubtest.py`
AA-Turner Sep 1, 2021
25ef122
👷 Add `typing.yml`
AA-Turner Sep 1, 2021
dc5aee2
🏷️ Add `py.typed`
AA-Turner Sep 1, 2021
2ca9e54
💚 Fix typing.yml
AA-Turner Sep 1, 2021
7003df3
🏷️ `region_code` may be None in `phonenumberutil.example_number_for_t…
AA-Turner Sep 1, 2021
04a8018
🔧 Update setup.py to include `.pyi` files
AA-Turner Sep 1, 2021
c44e96a
🏷️ Update `_BlockRange` equality types
AA-Turner Sep 2, 2021
7e754c0
♻️ Use `tempfile.NamedTemporaryFile`
AA-Turner Sep 2, 2021
0da6fd8
🏷️ Add `__all__` annotations
AA-Turner Sep 4, 2021
7d465cf
♻️ Correct method order
AA-Turner Sep 4, 2021
4173201
🔥 Remove unnecessary ` = ...`
AA-Turner Sep 4, 2021
3879d21
Generate .pyi files from metadata too
daviddrysdale Sep 2, 2021
1150c57
🏷️ Only override necessary elements
AA-Turner Sep 4, 2021
81f1b8d
👷 Add pure mypy runner
AA-Turner Sep 4, 2021
b7f4873
📝 Add a note about the stubs to the README
AA-Turner Sep 4, 2021
dbfa05e
🏷️ Fix various nits
AA-Turner Sep 5, 2021
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
45 changes: 45 additions & 0 deletions .github/workflows/typing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Test type stubs
on: [push, pull_request]

jobs:
stubtest:
name: Run stubtest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Set up latest Python 3
uses: actions/setup-python@v2
with:
python-version: 3

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install mypy types-protobuf

- name: Run mypy.stubtest
run: |
cd python
python run_stubtest.py

mypy:
name: Run mypy on stubs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Set up latest Python 3
uses: actions/setup-python@v2
with:
python-version: 3

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install mypy types-protobuf

- name: Run mypy
run: |
cd python
mypy --exclude pb2/ -p phonenumbers
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,16 @@ load of metadata will not cause a pause or memory exhaustion):
The `phonenumberslite` version of the package does not include the geocoding, carrier and timezone metadata,
which can be useful if you have problems installing the main `phonenumbers` package due to space/memory limitations.

Static Typing
-------------

The library includes a set of type [stub files](https://www.python.org/dev/peps/pep-0484/#stub-files) to support static
type checking by library users. These stub files signal the types that should be used, and may also be of use in IDEs
which have integrated type checking functionalities.

These files are written for Python 3, and as such type checking the library with these stubs on Python 2.5-2.7 is
unsupported.

Project Layout
--------------

Expand Down
1 change: 0 additions & 1 deletion python/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
recursive-include tests *.py
include HISTORY.md
include LICENSE
include testwrapper.py
82 changes: 82 additions & 0 deletions python/phonenumbers/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
from .asyoutypeformatter import AsYouTypeFormatter as AsYouTypeFormatter
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Are the X as X parts needed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is required, although looking at the docs it seems it might also be possible to put in __all__ -- though in other stub files I've seen it like this and thought it was the canonical approach

https://mypy.readthedocs.io/en/stable/config_file.html#confval-implicit_reexport (note the last line that implicit re-export is disabled for stubs -- the docs could be written more clearly here on the inverse of explicit re-exports)

from .phonemetadata import NumberFormat as NumberFormat
from .phonemetadata import PhoneMetadata as PhoneMetadata
from .phonemetadata import PhoneNumberDesc as PhoneNumberDesc
from .phonemetadata import REGION_CODE_FOR_NON_GEO_ENTITY as REGION_CODE_FOR_NON_GEO_ENTITY
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Maybe make the layout of the imports match __init__.py more closely?

Or is this (and the X as X parts) something tool-derived that's easier to leave as-is?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The from X import Y as Y was autogenerated, yes -- mypy.stubgen was able to infer a lot of stuff, but I had to manually correct a lot of types, and all private variables/class variables/functions I had to hand write, as stubgen didn't pick them up.

from .phonenumber import CountryCodeSource as CountryCodeSource
from .phonenumber import FrozenPhoneNumber as FrozenPhoneNumber
from .phonenumber import PhoneNumber as PhoneNumber
from .phonenumbermatcher import Leniency as Leniency
from .phonenumbermatcher import PhoneNumberMatch as PhoneNumberMatch
from .phonenumbermatcher import PhoneNumberMatcher as PhoneNumberMatcher
from .phonenumberutil import can_be_internationally_dialled as can_be_internationally_dialled
from .phonenumberutil import convert_alpha_characters_in_number as convert_alpha_characters_in_number
from .phonenumberutil import country_code_for_region as country_code_for_region
from .phonenumberutil import country_code_for_valid_region as country_code_for_valid_region
from .phonenumberutil import COUNTRY_CODE_TO_REGION_CODE as COUNTRY_CODE_TO_REGION_CODE
from .phonenumberutil import COUNTRY_CODES_FOR_NON_GEO_REGIONS as COUNTRY_CODES_FOR_NON_GEO_REGIONS
from .phonenumberutil import country_mobile_token as country_mobile_token
from .phonenumberutil import example_number as example_number
from .phonenumberutil import example_number_for_non_geo_entity as example_number_for_non_geo_entity
from .phonenumberutil import example_number_for_type as example_number_for_type
from .phonenumberutil import format_by_pattern as format_by_pattern
from .phonenumberutil import format_in_original_format as format_in_original_format
from .phonenumberutil import format_national_number_with_carrier_code as format_national_number_with_carrier_code
from .phonenumberutil import format_national_number_with_preferred_carrier_code as format_national_number_with_preferred_carrier_code
from .phonenumberutil import format_number as format_number
from .phonenumberutil import format_number_for_mobile_dialing as format_number_for_mobile_dialing
from .phonenumberutil import format_out_of_country_calling_number as format_out_of_country_calling_number
from .phonenumberutil import format_out_of_country_keeping_alpha_chars as format_out_of_country_keeping_alpha_chars
from .phonenumberutil import invalid_example_number as invalid_example_number
from .phonenumberutil import is_alpha_number as is_alpha_number
from .phonenumberutil import is_mobile_number_portable_region as is_mobile_number_portable_region
from .phonenumberutil import is_nanpa_country as is_nanpa_country
from .phonenumberutil import is_number_geographical as is_number_geographical
from .phonenumberutil import is_number_match as is_number_match
from .phonenumberutil import is_number_type_geographical as is_number_type_geographical
from .phonenumberutil import is_possible_number as is_possible_number
from .phonenumberutil import is_possible_number_for_type as is_possible_number_for_type
from .phonenumberutil import is_possible_number_for_type_with_reason as is_possible_number_for_type_with_reason
from .phonenumberutil import is_possible_number_string as is_possible_number_string
from .phonenumberutil import is_possible_number_with_reason as is_possible_number_with_reason
from .phonenumberutil import is_valid_number as is_valid_number
from .phonenumberutil import is_valid_number_for_region as is_valid_number_for_region
from .phonenumberutil import length_of_geographical_area_code as length_of_geographical_area_code
from .phonenumberutil import length_of_national_destination_code as length_of_national_destination_code
from .phonenumberutil import MatchType as MatchType
from .phonenumberutil import national_significant_number as national_significant_number
from .phonenumberutil import ndd_prefix_for_region as ndd_prefix_for_region
from .phonenumberutil import NON_DIGITS_PATTERN as NON_DIGITS_PATTERN
from .phonenumberutil import normalize_diallable_chars_only as normalize_diallable_chars_only
from .phonenumberutil import normalize_digits_only as normalize_digits_only
from .phonenumberutil import number_type as number_type
from .phonenumberutil import NumberParseException as NumberParseException
from .phonenumberutil import parse as parse
from .phonenumberutil import PhoneNumberFormat as PhoneNumberFormat
from .phonenumberutil import PhoneNumberType as PhoneNumberType
from .phonenumberutil import region_code_for_country_code as region_code_for_country_code
from .phonenumberutil import region_code_for_number as region_code_for_number
from .phonenumberutil import region_codes_for_country_code as region_codes_for_country_code
from .phonenumberutil import supported_calling_codes as supported_calling_codes
from .phonenumberutil import SUPPORTED_REGIONS as SUPPORTED_REGIONS
from .phonenumberutil import supported_types_for_non_geo_entity as supported_types_for_non_geo_entity
from .phonenumberutil import supported_types_for_region as supported_types_for_region
from .phonenumberutil import truncate_too_long_number as truncate_too_long_number
from .phonenumberutil import UNKNOWN_REGION as UNKNOWN_REGION
from .phonenumberutil import ValidationResult as ValidationResult
from .shortnumberinfo import connects_to_emergency_number as connects_to_emergency_number
from .shortnumberinfo import expected_cost as expected_cost
from .shortnumberinfo import expected_cost_for_region as expected_cost_for_region
from .shortnumberinfo import is_carrier_specific as is_carrier_specific
from .shortnumberinfo import is_carrier_specific_for_region as is_carrier_specific_for_region
from .shortnumberinfo import is_emergency_number as is_emergency_number
from .shortnumberinfo import is_possible_short_number as is_possible_short_number
from .shortnumberinfo import is_possible_short_number_for_region as is_possible_short_number_for_region
from .shortnumberinfo import is_sms_service_for_region as is_sms_service_for_region
from .shortnumberinfo import is_valid_short_number as is_valid_short_number
from .shortnumberinfo import is_valid_short_number_for_region as is_valid_short_number_for_region
from .shortnumberinfo import ShortNumberCost as ShortNumberCost
from .shortnumberinfo import SUPPORTED_SHORT_REGIONS as SUPPORTED_SHORT_REGIONS

__version__: str
__all__: list[str]
59 changes: 59 additions & 0 deletions python/phonenumbers/asyoutypeformatter.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from re import Pattern

from .phonemetadata import NumberFormat
from .phonemetadata import PhoneMetadata

_SEPARATOR_BEFORE_NATIONAL_NUMBER: str
_EMPTY_METADATA: PhoneMetadata
_NATIONAL_PREFIX_SEPARATORS_PATTERN: Pattern[str]
_ELIGIBLE_FORMAT_PATTERN: Pattern[str]
_MIN_LEADING_DIGITS_LENGTH: int
_DIGIT_PLACEHOLDER: str
_DIGIT_PATTERN: Pattern[str]

def _get_metadata_for_region(region_code: str) -> PhoneMetadata: ...

class AsYouTypeFormatter:
_default_country: str
_current_metadata: PhoneMetadata
_default_metadata: PhoneMetadata
_current_output: str
_accrued_input: str
_accrued_input_without_formatting: str
_formatting_template: str
_last_match_position: int
_current_formatting_pattern: str
_prefix_before_national_number: str
_should_add_space_after_national_prefix: bool
_extracted_national_prefix: str
_national_number: str
_able_to_format: bool
_input_has_formatting: bool
_position_to_remember: int
_original_position: int
_is_complete_number: bool
_is_expecting_country_calling_code: bool
_possible_formats: list[NumberFormat]
def __init__(self, region_code: str) -> None: ...
def _maybe_create_new_template(self) -> bool: ...
def _get_available_formats(self, leading_digits: str) -> None: ...
def _narrow_down_possible_formats(self, leading_digits: str) -> None: ...
def _create_formatting_template(self, num_format: NumberFormat) -> bool: ...
def _get_formatting_template(self, number_pattern: str, number_format: str) -> str: ...
def _clear(self) -> None: ...
def clear(self) -> None: ...
def input_digit(self, next_char: str, remember_position: bool = ...) -> str: ...
def _attempt_to_choose_pattern_with_prefix_extracted(self) -> str: ...
def _able_to_extract_longer_ndd(self) -> bool: ...
def _is_digit_or_leading_plus_sign(self, next_char: str) -> bool: ...
def _attempt_to_format_accrued_digits(self) -> str: ...
def get_remembered_position(self) -> int: ...
def _append_national_number(self, national_number: str) -> str: ...
def _attempt_to_choose_formatting_pattern(self) -> str: ...
def _input_accrued_national_number(self) -> str: ...
def _is_nanpa_number_with_national_prefix(self) -> bool: ...
def _remove_national_prefix_from_national_number(self) -> str: ...
def _attempt_to_extract_idd(self) -> bool: ...
def _attempt_to_extract_ccc(self) -> bool: ...
def _normalize_and_accrue_digits_and_plus_sign(self, next_char: str, remember_position: bool) -> str: ...
def _input_digit_helper(self, next_char: str) -> str: ...
8 changes: 8 additions & 0 deletions python/phonenumbers/carrier.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from .phonenumber import PhoneNumber

Comment thread
AA-Turner marked this conversation as resolved.
__all__: list[str]

def name_for_valid_number(numobj: PhoneNumber, lang: str, script: str | None = ..., region: str | None = ...) -> str: ...
def name_for_number(numobj: PhoneNumber, lang: str, script: str | None = ..., region: str | None = ...) -> str: ...
def safe_display_name(numobj: PhoneNumber, lang: str, script: str | None = ..., region: str | None = ...) -> str: ...
def _is_mobile(ntype: int) -> bool: ...
2 changes: 2 additions & 0 deletions python/phonenumbers/carrierdata/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CARRIER_DATA: dict[str, dict[str, str]]
CARRIER_LONGEST_PREFIX: int
9 changes: 9 additions & 0 deletions python/phonenumbers/data/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from ..phonemetadata import NumberFormat

_AVAILABLE_REGION_CODES: list[str]
_AVAILABLE_NONGEO_COUNTRY_CODES: list[int]

def _load_region(code: str | int) -> None: ...

_ALT_NUMBER_FORMATS: dict[int, list[NumberFormat]]
_COUNTRY_CODE_TO_REGION_CODE: dict[int, tuple[str, ...]]
8 changes: 8 additions & 0 deletions python/phonenumbers/geocoder.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from .phonenumber import PhoneNumber

Comment thread
AA-Turner marked this conversation as resolved.
__all__: list[str]

def country_name_for_number(numobj: PhoneNumber, lang: str, script: str | None = ..., region: str | None = ...) -> str: ...
def _region_display_name(region_code: str, lang: str, script: str | None = ..., region: str | None = ...) -> str: ...
def description_for_valid_number(numobj: PhoneNumber, lang: str, script: str | None = ..., region: str | None = ...) -> str: ...
def description_for_number(numobj: PhoneNumber, lang: str, script: str | None = ..., region: str | None = ...) -> str: ...
2 changes: 2 additions & 0 deletions python/phonenumbers/geodata/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GEOCODE_DATA: dict[str, dict[str, str]]
GEOCODE_LONGEST_PREFIX: int
1 change: 1 addition & 0 deletions python/phonenumbers/geodata/locale.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
LOCALE_DATA: dict[str, dict[str, str]]
147 changes: 147 additions & 0 deletions python/phonenumbers/phonemetadata.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
from collections.abc import Callable
import threading

from .util import ImmutableMixin
from .util import UnicodeMixin

REGION_CODE_FOR_NON_GEO_ENTITY: str

class NumberFormat(UnicodeMixin, ImmutableMixin):
pattern: str | None
format: str | None
leading_digits_pattern: list[str]
national_prefix_formatting_rule: str | None
national_prefix_optional_when_formatting: bool | None
domestic_carrier_code_formatting_rule: str | None
def __init__(
self,
pattern: str | None = ...,
format: str | None = ...,
leading_digits_pattern: list[str] | None = ...,
national_prefix_formatting_rule: str | None = ...,
national_prefix_optional_when_formatting: bool | None = ...,
domestic_carrier_code_formatting_rule: str | None = ...,
) -> None: ...
def merge_from(self, other: NumberFormat) -> None: ...
def __eq__(self, other: object) -> bool: ...
def __ne__(self, other: object) -> bool: ...
def __repr__(self) -> str: ...
def __unicode__(self) -> str: ...

class PhoneNumberDesc(UnicodeMixin, ImmutableMixin):
national_number_pattern: str | None
example_number: str | None
possible_length: tuple[int, ...]
possible_length_local_only: tuple[int, ...]
def __init__(
self,
national_number_pattern: str | None = ...,
example_number: str | None = ...,
possible_length: tuple[int, ...] | None = ...,
possible_length_local_only: tuple[int, ...] | None = ...,
) -> None: ...
def merge_from(self, other: PhoneNumberDesc) -> None: ...
def __eq__(self, other: object) -> bool: ...
def __ne__(self, other: object) -> bool: ...
def __repr__(self) -> str: ...
def __unicode__(self) -> str: ...

def _same_pattern(left: PhoneNumberDesc | None, right: PhoneNumberDesc | None) -> bool: ...

class PhoneMetadata(UnicodeMixin, ImmutableMixin):
_metadata_lock: threading.Lock
_region_available: dict[str, Callable[[str], None] | None]
_short_region_available: dict[str, Callable[[str], None] | None]
_country_code_available: dict[int, Callable[[int], None] | None]
_region_metadata: dict[str, PhoneMetadata]
_short_region_metadata: dict[str, PhoneMetadata]
_country_code_metadata: dict[int, PhoneMetadata]
general_desc: PhoneNumberDesc | None
fixed_line: PhoneNumberDesc | None
mobile: PhoneNumberDesc | None
toll_free: PhoneNumberDesc | None
premium_rate: PhoneNumberDesc | None
shared_cost: PhoneNumberDesc | None
personal_number: PhoneNumberDesc | None
voip: PhoneNumberDesc | None
pager: PhoneNumberDesc | None
uan: PhoneNumberDesc | None
emergency: PhoneNumberDesc | None
voicemail: PhoneNumberDesc | None
short_code: PhoneNumberDesc | None
standard_rate: PhoneNumberDesc | None
carrier_specific: PhoneNumberDesc | None
sms_services: PhoneNumberDesc | None
no_international_dialling: PhoneNumberDesc | None
id: str
country_code: int | None
international_prefix: str | None
preferred_international_prefix: str | None
national_prefix: str | None
preferred_extn_prefix: str | None
national_prefix_for_parsing: str | None
national_prefix_transform_rule: str | None
same_mobile_and_fixed_line_pattern: bool
number_format: list[NumberFormat]
intl_number_format: list[NumberFormat]
main_country_for_code: bool
leading_digits: str | None
leading_zero_possible: bool
mobile_number_portable_region: bool
short_data: bool
@classmethod
def metadata_for_region(cls, region_code: str, default: PhoneMetadata | None = ...) -> PhoneMetadata | None: ...
@classmethod
def short_metadata_for_region(cls, region_code: str, default: PhoneMetadata | None = ...) -> PhoneMetadata | None: ...
@classmethod
def metadata_for_nongeo_region(cls, country_code: int, default: PhoneMetadata | None = ...) -> PhoneMetadata | None: ...
@classmethod
def metadata_for_region_or_calling_code(cls, country_calling_code: int, region_code: str) -> PhoneMetadata | None: ...
@classmethod
def register_region_loader(cls, region_code: str, loader: Callable[[str], None]) -> None: ...
@classmethod
def register_short_region_loader(cls, region_code: str, loader: Callable[[str], None]) -> None: ...
@classmethod
def register_nongeo_region_loader(cls, country_code: int, loader: Callable[[int], None]) -> None: ...
@classmethod
def load_all(cls) -> None: ...
def __init__(
self,
id: str,
general_desc: PhoneNumberDesc | None = ...,
fixed_line: PhoneNumberDesc | None = ...,
mobile: PhoneNumberDesc | None = ...,
toll_free: PhoneNumberDesc | None = ...,
premium_rate: PhoneNumberDesc | None = ...,
shared_cost: PhoneNumberDesc | None = ...,
personal_number: PhoneNumberDesc | None = ...,
voip: PhoneNumberDesc | None = ...,
pager: PhoneNumberDesc | None = ...,
uan: PhoneNumberDesc | None = ...,
emergency: PhoneNumberDesc | None = ...,
voicemail: PhoneNumberDesc | None = ...,
short_code: PhoneNumberDesc | None = ...,
standard_rate: PhoneNumberDesc | None = ...,
carrier_specific: PhoneNumberDesc | None = ...,
sms_services: PhoneNumberDesc | None = ...,
no_international_dialling: PhoneNumberDesc | None = ...,
country_code: int | None = ...,
international_prefix: str | None = ...,
preferred_international_prefix: str | None = ...,
national_prefix: str | None = ...,
preferred_extn_prefix: str | None = ...,
national_prefix_for_parsing: str | None = ...,
national_prefix_transform_rule: str | None = ...,
number_format: list[NumberFormat] | None = ...,
intl_number_format: list[NumberFormat] | None = ...,
main_country_for_code: bool = ...,
leading_digits: str | None = ...,
leading_zero_possible: bool = ...,
mobile_number_portable_region: bool = ...,
short_data: bool = ...,
register: bool = ...,
) -> None: ...
def __eq__(self, other: object) -> bool: ...
def __ne__(self, other: object) -> bool: ...
def __repr__(self) -> str: ...
def __unicode__(self) -> str: ...
Loading