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

Tab completion in interactive shell not working since Python version 3.8 #1604

Closed
CelestialGuru opened this issue Feb 3, 2022 · 52 comments
Closed
Labels

Comments

@CelestialGuru
Copy link

CelestialGuru commented Feb 3, 2022

Tab autocomplete in python interactive shell unavailable when using Python versions 3.9, 3.10 or 3.11.

Python documents this feature: https://docs.python.org/3.11/tutorial/interactive.html#tab-completion-and-history-editing. (Docs here are the same in all versions of Python)

Setup

  • Faker version: 17.3.0
  • OS: Debian GNU/Linux 11 (bullseye)
OS versions
PS C:\Users\User> docker run -it --rm python:3.8 cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

PS C:\Users\User> docker run -it --rm python:3.9 cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

PS C:\Users\User> docker run -it --rm python:3.10 cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

PS C:\Users\User> docker run -it --rm python:3.11 cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

What used to work

# pip install faker=="17.3.0"
# python
>>> import faker
>>> fake = faker.Faker()
>>> fake.

Type [TAB] once or twice and you see this:

Display all 280 possibilities? (y or n)
fake.aba(                             fake.generator_attrs                  fake.pyfloat(
fake.add_provider(                    fake.get_arguments(                   fake.pyint(
fake.address(                         fake.get_formatter(                   fake.pyiterable(
... I've removed a whole bunch for brevity's sake.
fake.free_email(                      fake.psv(                             fake.zipcode_in_state(
fake.free_email_domain(               fake.pybool(                          fake.zipcode_plus4(
fake.future_date(                     fake.pydecimal(
fake.future_datetime(                 fake.pydict(
>>> fake.

What's broken

In Python 3.9, 3.10, and 3.11:

# pip install faker=="17.3.0"
# python
>>> import faker
>>> fake = faker.Faker()
>>> fake.

Type [TAB] once or twice and nothing happens.

@CelestialGuru
Copy link
Author

I've noticed that if I start typing a letter or two, autocomplete will start to work:

>>> fake.a
fake.aba()                     fake.address()                 fake.am_pm()                   fake.ascii_company_email()     fake.ascii_free_email()
fake.add_provider(             fake.administrative_unit()     fake.android_platform_token()  fake.ascii_email()             fake.ascii_safe_email()
>>> fake.b
fake.bank_country()     fake.bban()             fake.binary(            fake.boolean(           fake.bothify(           fake.bs()               fake.building_number()
>>> fake.c
fake.cache_pattern               fake.city_prefix()               fake.company_email()             fake.country_code(               fake.credit_card_security_code(  fake.currency()                  fake.current_country_code()
fake.catch_phrase()              fake.city_suffix()               fake.company_suffix()            fake.credit_card_expire(         fake.cryptocurrency()            fake.currency_code()
fake.century()                   fake.color(                      fake.coordinate(                 fake.credit_card_full(           fake.cryptocurrency_code()       fake.currency_name()
fake.chrome(                     fake.color_name()                fake.country()                   fake.credit_card_number(         fake.cryptocurrency_name()       fake.currency_symbol(
fake.city()                      fake.company()                   fake.country_calling_code()      fake.credit_card_provider(       fake.csv(                        fake.current_country()
>>> fake.d
fake.date(                     fake.date_of_birth(            fake.date_this_year(           fake.date_time_between_dates(  fake.date_time_this_year(      fake.dga(
fake.date_between(             fake.date_this_century(        fake.date_time(                fake.date_time_this_century(   fake.day_of_month()            fake.domain_name(
fake.date_between_dates(       fake.date_this_decade(         fake.date_time_ad(             fake.date_time_this_decade(    fake.day_of_week()             fake.domain_word()
fake.date_object(              fake.date_this_month(          fake.date_time_between(        fake.date_time_this_month(     fake.del_arguments(            fake.dsv(
>>> fake.e
fake.ean(    fake.ean13(  fake.ean8(   fake.ein()   fake.email(
>>> fake.e

So a workaround would be to just start typing a single letter before before hitting TAB, but I just want to see ALL attributes available at once.

@fcurella
Copy link
Collaborator

fcurella commented Feb 4, 2022

Could it possibly be an issue o Python 38 that got fixed in 3.9?

Either way, I'm not sure what we could do to fix this. I'm open to any ideas.

@CelestialGuru
Copy link
Author

I thought that if an object had too many attributes, that new versions of Python would not show all those attributes when you hit tab. Below I show that an object with ~17k attributes, in new version of Python, will still work as expected when you hit tab.

>>> import string
>>> Foo = type("Foo", (), {f"{a}{b}{c}":0 for a in string.ascii_lowercase for b in string.ascii_lowercase for c in string.ascii_lowercase})
>>> foo = Foo()
>>> len(dir(foo))
17602
>>> foo. <tab> # I'm not going to show the output, but all 17,602 of them appear

So why then, does tab completion not work?

@CelestialGuru
Copy link
Author

Can anyone else replicate this?

I showed you how to run this in docker, so hopefully it should be easy enough to duplicate. (The issue can be demonstrated outside of docker btw)

@mondeja
Copy link
Contributor

mondeja commented Feb 9, 2022

In Ubuntu 20.04 I can't replicate it with Python3.9 installed using APT from default repositories, but Python3.10 installed from deadsnakes PPA has this problem.

@Dragon1573
Copy link

Summary

  1. IntelliCode and Kite-AI Auto-completion not working in VSCode.

    Screenshot (Click to expand)
  2. Python Docs unavailable both in VSCode IntelliCode and Kite Copilot.

    Screenshots (Click to expand)
  3. Auto-completion available as it should in IPython, however …

    Screenshot

Environments

  • Windows 10 Professional 21H2 (19044.1566)
  • Miniconda3, installed via winget.exe
    • conda 4.11.0
    • virutalenv 20.4.6
    • Python 3.9.7
      • Faker 13.0.0
      • IPython 8.1.0
  • Microsoft Visual Studio Code 1.65.0 (system setup)
  • Kite Engine 1.2021.610.0
    • VSCode Plugin Installed
    • Vim Plugin Installed

Steps to reproduce

  1. Setup Python 3.9 or later version

    winget install Python.Python.3
  2. Install the latest version of Faker

  3. Installed the latest version of Microsoft Visual Studio Code

    winget install Microsoft.VisualStudioCode
  4. Open an empty folder as a VSCode workspace, and create an empty *.py file

  5. Type in the following snippet

    from faker import Faker
    
    fake = Faker(locale='en_US')
    fake.
  6. Invoke auto-completion (mostly Ctrl + Space) after the dot, check if all available methods are listed.

Expected Behavior

  1. All available methods should be listed, as it's shown in IPython Console.
  2. Python Docs are automatically fetched from local (or remote) when cursor on any one of Faker's class, instance or method.

Actual Behavior

As I mentioned before in "Summary" section.

Notes

Kite Engine and IntelliCode for VSCode are enabled and ready. It's not Kite or VSCode's fault.

Screenshot (Click to expand)

@Dragon1573
Copy link

In Ubuntu 20.04 I can't replicate it with Python3.9 installed using APT from default repositories.

I'm using Docker Desktop for Windows with WSL2 backend. I followed the steps as what @CelestialGuru did before. When I type in a few characters it CAN auto-complete for me, but if I left it empty and invoke Tab just after the dot, nothing pop up.

Console Logs (too long, click to expand)
root@63d26b38d382:/# python
Python 3.9.10 (main, Mar  2 2022, 04:23:34)
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from faker import Faker
>>> from pprint import pprint
>>> faker = Faker(locale="en_US")
>>> pprint(dir(faker))
['__annotations__',
 '__class__',
 '__deepcopy__',
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattr__',
 '__getattribute__',
 '__getitem__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__le__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__setstate__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 '_factories',
 '_factory_map',
 '_locales',
 '_map_provider_method',
 '_select_factory',
 '_unique_proxy',
 '_weights',
 'aba',
 'add_provider',
 'address',
 'administrative_unit',
 'am_pm',
 'android_platform_token',
 'ascii_company_email',
 'ascii_email',
 'ascii_free_email',
 'ascii_safe_email',
 'bank_country',
 'bban',
 'binary',
 'boolean',
 'bothify',
 'bs',
 'building_number',
 'cache_pattern',
 'catch_phrase',
 'century',
 'chrome',
 'city',
 'city_prefix',
 'city_suffix',
 'color',
 'color_name',
 'company',
 'company_email',
 'company_suffix',
 'coordinate',
 'country',
 'country_calling_code',
 'country_code',
 'credit_card_expire',
 'credit_card_full',
 'credit_card_number',
 'credit_card_provider',
 'credit_card_security_code',
 'cryptocurrency',
 'cryptocurrency_code',
 'cryptocurrency_name',
 'csv',
 'currency',
 'currency_code',
 'currency_name',
 'currency_symbol',
 'current_country',
 'current_country_code',
 'date',
 'date_between',
 'date_between_dates',
 'date_object',
 'date_of_birth',
 'date_this_century',
 'date_this_decade',
 'date_this_month',
 'date_this_year',
 'date_time',
 'date_time_ad',
 'date_time_between',
 'date_time_between_dates',
 'date_time_this_century',
 'date_time_this_decade',
 'date_time_this_month',
 'date_time_this_year',
 'day_of_month',
 'day_of_week',
 'del_arguments',
 'dga',
 'domain_name',
 'domain_word',
 'dsv',
 'ean',
 'ean13',
 'ean8',
 'ein',
 'email',
 'factories',
 'file_extension',
 'file_name',
 'file_path',
 'firefox',
 'first_name',
 'first_name_female',
 'first_name_male',
 'first_name_nonbinary',
 'fixed_width',
 'format',
 'free_email',
 'free_email_domain',
 'future_date',
 'future_datetime',
 'generator_attrs',
 'get_arguments',
 'get_formatter',
 'get_providers',
 'hex_color',
 'hexify',
 'hostname',
 'http_method',
 'iana_id',
 'iban',
 'image',
 'image_url',
 'internet_explorer',
 'invalid_ssn',
 'ios_platform_token',
 'ipv4',
 'ipv4_network_class',
 'ipv4_private',
 'ipv4_public',
 'ipv6',
 'isbn10',
 'isbn13',
 'iso8601',
 'items',
 'itin',
 'job',
 'json',
 'language_code',
 'language_name',
 'last_name',
 'last_name_female',
 'last_name_male',
 'last_name_nonbinary',
 'latitude',
 'latlng',
 'lexify',
 'license_plate',
 'linux_platform_token',
 'linux_processor',
 'local_latlng',
 'locale',
 'locales',
 'localized_ean',
 'localized_ean13',
 'localized_ean8',
 'location_on_land',
 'longitude',
 'mac_address',
 'mac_platform_token',
 'mac_processor',
 'md5',
 'military_apo',
 'military_dpo',
 'military_ship',
 'military_state',
 'mime_type',
 'month',
 'month_name',
 'msisdn',
 'name',
 'name_female',
 'name_male',
 'name_nonbinary',
 'nic_handle',
 'nic_handles',
 'null_boolean',
 'numerify',
 'opera',
 'paragraph',
 'paragraphs',
 'parse',
 'password',
 'past_date',
 'past_datetime',
 'phone_number',
 'port_number',
 'postalcode',
 'postalcode_in_state',
 'postalcode_plus4',
 'postcode',
 'postcode_in_state',
 'prefix',
 'prefix_female',
 'prefix_male',
 'prefix_nonbinary',
 'pricetag',
 'profile',
 'provider',
 'providers',
 'psv',
 'pybool',
 'pydecimal',
 'pydict',
 'pyfloat',
 'pyint',
 'pyiterable',
 'pylist',
 'pyset',
 'pystr',
 'pystr_format',
 'pystruct',
 'pytimezone',
 'pytuple',
 'random',
 'random_choices',
 'random_digit',
 'random_digit_not_null',
 'random_digit_not_null_or_empty',
 'random_digit_or_empty',
 'random_element',
 'random_elements',
 'random_int',
 'random_letter',
 'random_letters',
 'random_lowercase_letter',
 'random_number',
 'random_sample',
 'random_uppercase_letter',
 'randomize_nb_elements',
 'rgb_color',
 'rgb_css_color',
 'ripe_id',
 'safari',
 'safe_color_name',
 'safe_domain_name',
 'safe_email',
 'safe_hex_color',
 'secondary_address',
 'seed',
 'seed_instance',
 'seed_locale',
 'sentence',
 'sentences',
 'set_arguments',
 'set_formatter',
 'sha1',
 'sha256',
 'simple_profile',
 'slug',
 'ssn',
 'state',
 'state_abbr',
 'street_address',
 'street_name',
 'street_suffix',
 'suffix',
 'suffix_female',
 'suffix_male',
 'suffix_nonbinary',
 'swift',
 'swift11',
 'swift8',
 'tar',
 'text',
 'texts',
 'time',
 'time_delta',
 'time_object',
 'time_series',
 'timezone',
 'tld',
 'tsv',
 'unique',
 'unix_device',
 'unix_partition',
 'unix_time',
 'upc_a',
 'upc_e',
 'uri',
 'uri_extension',
 'uri_page',
 'uri_path',
 'url',
 'user_agent',
 'user_name',
 'uuid4',
 'weights',
 'windows_platform_token',
 'word',
 'words',
 'year',
 'zip',
 'zipcode',
 'zipcode_in_state',
 'zipcode_plus4']
>>> faker.c
faker.cache_pattern               faker.company_suffix(             faker.cryptocurrency_code(
faker.catch_phrase(               faker.coordinate(                 faker.cryptocurrency_name(
faker.century(                    faker.country(                    faker.csv(
faker.chrome(                     faker.country_calling_code(       faker.currency(
faker.city(                       faker.country_code(               faker.currency_code(
faker.city_prefix(                faker.credit_card_expire(         faker.currency_name(
faker.city_suffix(                faker.credit_card_full(           faker.currency_symbol(
faker.color(                      faker.credit_card_number(         faker.current_country(
faker.color_name(                 faker.credit_card_provider(       faker.current_country_code(
faker.company(                    faker.credit_card_security_code(
faker.company_email(              faker.cryptocurrency(
>>> faker.        # Invoke TAB several times, but nothing happened.

@github-actions
Copy link

github-actions bot commented Jun 7, 2022

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Jun 7, 2022
@invokermain
Copy link

invokermain commented Jun 9, 2022

I see the same problem on Python 3.9 in PyCharm. I wonder if this is just due to the high level of dynamism in Faker? I.e. attributes are added in via __getattribute__ so static type checkers cannot resolve them?

But makes the library a pain to use as not discoverable via IDE.

image
These are the attributes I see on faker instance.

@tony
Copy link
Contributor

tony commented Jul 18, 2022

I just filed a duplicate (missed this one) in #1684

Here's my completions as of faker 13.15.0, example:

from faker import Faker

def test_faker(faker: Faker):
    assert isinstance(faker.name(), str)

This example above is based on Pytest Fixture's examples, annotating with faker.Faker (as is common, see GitHub Search):

image

@github-actions
Copy link

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Oct 17, 2022
@tony
Copy link
Contributor

tony commented Oct 17, 2022

Everybody wants completions for faker

edit: I don't believe anybody specifically doesn't want it 😃

@Dragon1573
Copy link

I found that there are plenties of providers in faker.providers and all of them have functional auto-completion. Is it possible to use these providers on our own instead of using the "Proxy Class" faker.Faker? How can we use it?

image

@github-actions github-actions bot removed the stale label Oct 18, 2022
@KaylaHood
Copy link
Contributor

I'm just commenting to say that I'd greatly appreciate this feature as well. I'd imagine it would be trivial to add a mypy stub or similar to declare all of the many provider's attributes as members of the base Faker class. I'm trying to write the stub file myself, I'll try to remember to report back if it works.

@KaylaHood
Copy link
Contributor

KaylaHood commented Nov 3, 2022

Well, it didn't take long for me to find the issue that's causing our autocomplete not to work. Unfortunately it's not as easy to solve as I'd hoped.

faker.proxy line 79:

def __dir__(self):
  attributes = set(super(Faker, self).__dir__())
  for factory in self.factories:
    attributes |= {attr for attr in dir(factory) if not attr.startswith("_")}
  return sorted(attributes)

Because of self.factories (aka faker.proxy.Faker().factories) only being known at runtime (it varies with the parameters provided to faker.proxy.Faker.__init__), the result of faker.proxy.Faker().__dir__() can't be determined without actually instantiating the Faker class.

I know that MyPy can provide type hints/autocompletion even for generated classes (I can't remember where I've seen it before - I think the AWS API library boto3 is an example). There has to be a way to get dynamic type hints even with the generated factories.

Edit: I had forgotten that boto3's type hints are actually quite cumbersome to use. Due to its heavy use of generated classes (I digress, but why did they choose to make them dynamic???) the mypy type hints have to be imported manually (from the ugly-named mypy_boto3_* packages) unless you're using an IDE that supports dynamic type hints (such as VSCode with PyLance, PyCharm, IntelliJ with the Mypy plugin, etc).
Because of the ugliness of these type hints, I'd love to see an alternative solution to the dynamic class typing problem.

@tony
Copy link
Contributor

tony commented Nov 3, 2022

@KaylaHood You are correct in factories and metaclasses masking completions due to being reliant on runtime.

If you accomplish anything it'd be nice to see where it goes. But it may be too runtime-heavy to get completion and typings for.

@KaylaHood
Copy link
Contributor

KaylaHood commented Nov 11, 2022

@tony well I seem to have made something helpful but objectively not very Pythonic.
https://github.com/KaylaHood/faker-stubs

I wrote a little script that makes heavy use of the standard lib inspect package to generate a stub for Faker's proxy.py file so that auto-completion for faker.Faker() instances will contain every provider method for every locale.
It works for my use case (Windows 10, Python 3.9), but I didn't spend time testing it for other platforms.

You have to run the stub generator every time you install/upgrade Faker; I can see it getting tedious very quickly.
If you use poetry or some other python package management tool you could write a post-build script that automates the download and execution of my stub generation script.

NOTE: the automated stub generation solution I just described should NEVER be used for a production or client-facing application. You don't know me! I could change my stub generation script to be a data miner! (I wouldn't, but y'know what I mean) If you would like to incorporate it into your product, then consider forking my repo to your own github/artifactory/server/etc and then use your cloned version of my script in your product's build pipeline.

Hopefully you find it useful!

@fcurella
Copy link
Collaborator

We could integrate @KaylaHood 's script in our CI build and run it before every release, but that would still not cover community providers that users have installed on their own.

On one hand, that'd be better than nothing. On the other, it may set the wrong expectation on users.

@KaylaHood
Copy link
Contributor

@fcurella if y'all do incorporate my script, please feel free to refactor it and optimize it. I did very little optimization, I approached this with more of an "MVP" mindset :-)

I agree with your last point, incorporating my stubs could confuse users who utilize their own providers or who select a specific locale.
The problem of external providers can easily be resolved by extending my stub generator script to have a configurable list of provider packages to scan.
The locale problem is much harder because locales are selected at runtime. To fix the auto-completion for locale-restricted Faker instances, there'd need to be major renovations done to the locale selection mechanism.

@Dragon1573
Copy link

@KaylaHood I try your repo and it works great on my device! Thank you!

Environments

  • Microsoft Windows 11 Professional 22H2
  • Ubuntu 22.04 LTS on WSL2
  • Microsoft Visual Studio Code v1.73.1 (system setup)
  • Python v3.10.7
  • Poetry v1.2.2
  • Faker v15.3.1

Screenshots

image

@tony
Copy link
Contributor

tony commented Nov 12, 2022

This is a night and day difference.

Environment

Instructions

mkdir -p ~/projects/python; cd ~/projects/python
git clone https://github.com/joke2k/faker
git clone https://github.com/KaylaHood/faker-stubs

cd ~/projects/python/faker
virtualenv .venv
. .venv/bin/activate
pip install -e .
python ../faker-stubs/generate_stub.py

You should now see this with git status:

❯ git status
On branch master
Your branch is up to date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        faker/proxy.pyi

If the faker/proxy.pyi stub is there, you will be able to see typings if you open any file, e.g. tests/test_proxy.py

Before (via here)

from faker import Faker

def test_faker(faker: Faker):
    assert isinstance(faker.name(), str)

image

With faker-stubs @ 77d25e7

image

image

Locale / faker constructor

re: locales

from faker import Faker

fake = Faker(locale="en")

Expected no arguments to "Faker" constructor (Pyright reportGeneralTypeIssues)

If the constructor itself allowed locale, we'd get around this particular one. Though we wouldn't have locale-specific ones.

image

@KaylaHood
Copy link
Contributor

KaylaHood commented Nov 13, 2022

@tony

If the constructor itself allowed locale, we'd get around this particular one. Though we wouldn't have locale-specific ones.

Thanks for pointing this out, I made a quick fix for this:
https://github.com/KaylaHood/faker-stubs/tree/3e5c7260539564dd60bc71d83b8cd596d5fd6506

I had forgotten to include the mangled methods from the Faker class (__init__, __deepcopy__, etc). Now the __init__ method's signature will include the optional locale argument (as well as the other optional args).

Edit: use this version of my faker-stubs script instead: https://github.com/KaylaHood/faker-stubs/tree/d555b36a4deeeaccdecdfb5a90cda134dbb38605
I fixed the docstrings in the stubs so now the docstrings will populate in the auto-completion results.
I also realized certain provider functions have the same name as some member variables (example: country_code). I added logic that removes those conflicting member variables from the stub in favor of the provider function.

@tony
Copy link
Contributor

tony commented Nov 13, 2022

@KaylaHood Follow up to #1604 (comment) + #1604 (comment)

Environment

New docstring completions + locale kwarg

This looks good.

I had forgotten to include the mangled methods from the Faker class (__init__, __deepcopy__, etc). Now the __init__ method's signature will include the optional locale argument (as well as the other optional args).

Got it and this looks good (screenshot 1)

I fixed the docstrings in the stubs so now the docstrings will populate in the auto-completion results.

Roger that, and this looks good (screenshot 1)

image
Above: Screenshot 1

Provider functions v. member names

I also realized certain provider functions have the same name as some member variables (example: country_code). I added logic that removes those conflicting member variables from the stub in favor of the provider function.

Good catch here as well

Before, with faker-stubs @ 77d25e7

image

With faker-stubs @ d555b36:

image

With faker-stubs @ 5161681:

image

With faker-stubs @ 5c7ffc2:

image

Side note, re: **config: Any

**config: Any on the faker side permits anything,

**config: Any,

I've never used any **config kwargs, so I'm not sure what this is used for. If it's something deterministic, there's new PEPs and backported support available:

@github-actions
Copy link

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Feb 12, 2023
@github-actions
Copy link

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label May 31, 2023
@tony
Copy link
Contributor

tony commented May 31, 2023

I'm still interested.

@gryznar
Copy link

gryznar commented May 31, 2023

Me too! It is a big caveat for me, that there is no any type hints for possible data. Mimesis offers that, so if there is comparison, lack of annotations is much bigger deal

@github-actions
Copy link

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Aug 31, 2023
@edgarrmondragon
Copy link
Contributor

I think this is still relevant

@tony
Copy link
Contributor

tony commented Aug 31, 2023

@fcurella Fine to keep open

@github-actions github-actions bot removed the stale label Sep 1, 2023
@Viicos
Copy link
Contributor

Viicos commented Oct 17, 2023

@fcurella Would you be open to have a PR implementing the generation of a stub file like @KaylaHood did? This would generate a single proxy.pyi file that would be shipped in next versions. We could make sure the file is generated again each time a provider implements a new method.

If so, I can open a PR with a script inspired by @KaylaHood's work

@fcurella
Copy link
Collaborator

fcurella commented Oct 18, 2023 via email

@tony
Copy link
Contributor

tony commented Oct 18, 2023

Minor deconfliction / air traffic control:

@fcurella Would you be open to have a PR implementing the generation of a stub file like @KaylaHood did? This would generate a single proxy.pyi file that would be shipped in next versions. We could make sure the file is generated again each time a provider implements a new method.

If so, I can open a PR with a script inspirede by @KaylaHood's work

@Viicos This would be a good idea. There hasn't been movement on this in some time.

@KaylaHood Is this something you want a chance at PR'ing? If so, it wouldn't hurt to. Just want to make sure you don't lose credit for the effort at https://github.com/KaylaHood/faker-stubs.

@KaylaHood
Copy link
Contributor

KaylaHood commented Oct 25, 2023

@tony thanks for giving me a heads up! I made a quick PR: #1939

FYI I had to put the generate_stubs.py script somewhere other than the faker/ directory because it will try to import faker.typing instead of the standard lib's typing module. Do you know if it's possible to force absolute import resolution in such a case? If so, I can move the generate_stubs.py script back into the faker directory.

@bandophahita
Copy link

I've been working to help cleanup generate_stubs.py for #1939, and I gotta admit it's far more complex than I had originally thought. I was able to generate a proxy.pyi that works for all the providers, but I realized it was missing the Generator methods. Adding them became problematic due to forward ref annotations.

The script will also stop working properly the moment anyone uses from __future__ import annotations in a any of the modules. I'll keep banging on it...

@Viicos
Copy link
Contributor

Viicos commented Jan 20, 2024

I've been working to help cleanup generate_stubs.py for #1939, and I gotta admit it's far more complex than I had originally thought. I was able to generate a proxy.pyi that works for all the providers, but I realized it was missing the Generator methods. Adding them became problematic due to forward ref annotations.

The script will also stop working properly the moment anyone uses from __future__ import annotations in a any of the modules. I'll keep banging on it...

Sorry for not being active on this subject, I'm missing some time currently.

I'm not sure I understand why forward refs are an issue in a stub file? Type checkers treat them as having from __future__ import annotations by default.


I believe something built with Libcst or similar would be more robust. I'll see if I can come up with something soon

@bandophahita
Copy link

bandophahita commented Jan 20, 2024

The current iteration of generate_stub.py uses inspect.signature to gather the annotations as objects. This works when the module doesn't have from __future__ import annotations which unfortunately sets the annotations to strings. This hinders the scripts ability to set the proper imports in the proxy.pyi

I'm still investigating another solution but typing.get_type_hints() looks promising.

@Viicos
Copy link
Contributor

Viicos commented Jan 20, 2024

Ah ok I see, yes typing.get_type_hints will actually try to resolve forward annotations when possible.

@bandophahita
Copy link

I was able to get the generate_stub.py working to generate all the methods for Faker. It even appears to handle future annotations.

The only issue I'm seeing is one of convenience; I have no idea how get the stub generation to utilize type aliases.

# from proxy.pyi

    def simple_profile(
        self, sex: Optional[Literal["M", "F"]] = ...
    ) -> Dict[str, Union[str, datetime.date, Literal["M", "F"]]]: ...

vs

# from profile/__init__.py

    def simple_profile(self, sex: Optional[SexLiteral] = None) -> Dict[str, Union[str, date, SexLiteral]]:

If there is a trick to substituting those, I'm unaware of it.

@Viicos
Copy link
Contributor

Viicos commented Jan 23, 2024

The only way would be to parse the AST/CST I believe

@bandophahita
Copy link

bandophahita commented Jan 23, 2024

The only way would be to parse the AST/CST I believe

I suspect you're right. What has me confused is @KaylaHood had a few of the aliases in her version of the pyi. I could never get her version nor any of my iterations to do that. I'd love to know how she did that.

def color(self, hue: Optional[HueType] = ..., luminosity: Optional[str] = ..., color_format: str = ...) -> str:

With that said, what would you like to do from here? Since folks (myself included) are chomping at the bit to see a pyi file added to the library, shall I submit another PR for the updated changes?

@Viicos
Copy link
Contributor

Viicos commented Jan 23, 2024

With that said, what would you like to do from here? Since folks (myself included) are chomping at the bit to see a pyi file added to the library, shall I submit another PR for the updated changes?

I think getting feedback from @MarcelWilson and @KaylaHood would be great. Sadly I don't have much time to review your work that is supposed to fix the missing imports in the initial PR, but having this script to generate stubs using inspect is in my opinion a great first step. In the following months, I might get some time to write something involving ast/cst parsing

@bandophahita
Copy link

I think getting feedback from @MarcelWilson and @KaylaHood would be great.

I am @MarcelWilson. It's my work account. This is my personal account. Sorry for the confusion.

@MarcelWilson
Copy link

I think getting feedback from @MarcelWilson and @KaylaHood would be great.

Wonderful update. Couldn't have done better myself. 😂

Copy link

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Apr 23, 2024
Copy link

github-actions bot commented May 7, 2024

This issue was closed because it has been inactive for 14 days since being marked as stale.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale May 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests