Typing at PyCon USA 2025

Hi Folks!

We’re about a week away from PyCon USA in Pittsburgh next week!

Since PyCon is a good time for folks who are present to meet, discuss typing topics, and kick off projects I thought it would be good to have a thread where people can post about typing-related talks, events, or breakout rooms.


I wanted to start by reminding everyone that @carljm and I will be hosting the Typing Summit from 2-6pm on Friday May 16 in room 319.

Anyone who wants to hear about work in the typing community is welcome to join! You can see more details including the agenda at

9 Likes

2-6pm! Let’s not have everyone arriving halfway through :laughing:

3 Likes

It would also be good to include the date here, unless it’s every day!

3 Likes

2-6pm on Friday May 16, the first day of the main conference! It’s all on the linked web page :slight_smile:

2 Likes

Hi folks, looking forward to seeing everyone at the Typing Summit this year. A few topics on my mind that I would love to have longer discussions on. I plan to grab a breakout room where we can discuss these further.

  • Typing Survey for 2025: I’m hoping we can do this again over the summer. What questions would you like to see included in this year’s survey? How do we get more participation from non typing-enthusiasts.
  • Improving Ecosystem Types: We’ve made steady progress typing Pandas and Numpy. How do we get more community involvement? @yangdanny97 @MarcoGorelli @jorenham
  • Type Stubs Plan by PyCon 2026: A plan for a plan. At the 2026 Typing Summit, can we have a plan to make the ecosystem of stubs more sustainable for maintainers and consistent for developers?
    • What is the long term plan for typeshed?
    • Has sentiment among library authors moved from “I don’t want types” to “I don’t have the energy to add/maintain types”? If so, how can we make supporting types/type checking easier?

I’m afraid I won’t be able to attend in person this year. Is there any way I could participate remotely?

1 Like

If possible that would be awesome, I’d also be very interested in taking part remotely!

Unfortunately remote participation at summits is not an option this year. We will do our best to share slides, notes, and recordings.

If there are follow-up topics where a wider discussion would be helpful, I’m happy to schedule them for upcoming typing meetups!

1 Like

For folks at PyCon, I thought it might be useful to have a discord server we can use just for the event, especially for folks trying to meet up in open spaces and such

Feel free to join, it’s just for informal discussions and finding folks you’d like to meet up with

I reserved Room 315 at 3:00PM ET tomorrow for the discussion. - PyCon US 2025. I will also create a zoom link if others want to join, I’m not sure how the format will work but it’s worth a try!

1 Like

Three open space typing discussions happening Saturday (05/17/2025):

  • 10:00am-11:00am @ Room 316: Ty,
  • 03:00pm-04:00pm @ Room 315: Python stubs and survey
  • 04:00pm-05:00pm @ Room 321: Pyrefly
4 Likes

@jorenham here is a zoom link: Launch Meeting - Zoom. Idk how well the VC will work for the room format, but it’s worth a try if you want to join and talk about the work on Numpy.

1 Like

I’m in the call :slight_smile:

2 Likes

For anyone who wasn’t able to make the open space about typing adoption, typeshed, and working with package maintainers I took notes here (and anyone is free to add clarifications or correct errors):

7 Likes

Thanks for sharing the notes.
I’m honored and thankful to see the micropython-stubs mentioned here.

Thanks for posting the notes!

I just wanted to comment on

A note: Pandas stubs intentionally diverge from the implementation to use more restrictive types we think are more useful in practice, e.g. columns can be anything but we stay int | str in the stubs

pandas column names can’t quite be anything, they need to be hashable. E.g. trying to use a list raises at runtime:

In [24]: df = pd.DataFrame({[1, 2]: [1,2,3]})
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[24], line 1
----> 1 df = pd.DataFrame({[1, 2]: [1,2,3]})

TypeError: unhashable type: 'list'

In the type stubs, Hashable is typically used

Is there an example where int | str is used? If so, that probably needs correct - thanks :folded_hands:

That error does not come from pandas. It is the dict constructor:

>>> {[1, 2]: [1,2,3]}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
1 Like

Right, thanks!

Sure, here’s an example of it coming from pandas:

In [32]: df = pd.DataFrame({'a': [1,2,3], 'b': [4,5,6]})

In [33]: df.rename(columns={'a': 'c', 'b': 'd'})
Out[33]:
   c  d
0  1  4
1  2  5
2  3  6

In [34]: df.rename(columns={'a': 'c', 'b': ['d']})
Out[34]: ---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
File ~/scratch/.venv/lib/python3.12/site-packages/IPython/core/formatters.py:770, in PlainTextFormatter.__call__(self, obj)
    763 stream = StringIO()
    764 printer = pretty.RepresentationPrinter(stream, self.verbose,
    765     self.max_width, self.newline,
    766     max_seq_length=self.max_seq_length,
    767     singleton_pprinters=self.singleton_printers,
    768     type_pprinters=self.type_printers,
    769     deferred_pprinters=self.deferred_printers)
--> 770 printer.pretty(obj)
    771 printer.flush()
    772 return stream.getvalue()

File ~/scratch/.venv/lib/python3.12/site-packages/IPython/lib/pretty.py:411, in RepresentationPrinter.pretty(self, obj)
    400                         return meth(obj, self, cycle)
    401                 if (
    402                     cls is not object
    403                     # check if cls defines __repr__
   (...)    409                     and callable(_safe_getattr(cls, "__repr__", None))
    410                 ):
--> 411                     return _repr_pprint(obj, self, cycle)
    413     return _default_pprint(obj, self, cycle)
    414 finally:

File ~/scratch/.venv/lib/python3.12/site-packages/IPython/lib/pretty.py:786, in _repr_pprint(obj, p, cycle)
    784 """A pprint that just redirects to the normal repr function."""
    785 # Find newlines and replace them with p.break_()
--> 786 output = repr(obj)
    787 lines = output.splitlines()
    788 with p.group():

File ~/scratch/.venv/lib/python3.12/site-packages/pandas/core/frame.py:1214, in DataFrame.__repr__(self)
   1211     return buf.getvalue()
   1213 repr_params = fmt.get_dataframe_repr_params()
-> 1214 return self.to_string(**repr_params)

File ~/scratch/.venv/lib/python3.12/site-packages/pandas/util/_decorators.py:333, in deprecate_nonkeyword_arguments.<locals>.decorate.<locals>.wrapper(*args, **kwargs)
    327 if len(args) > num_allow_args:
    328     warnings.warn(
    329         msg.format(arguments=_format_argument_list(allow_args)),
    330         FutureWarning,
    331         stacklevel=find_stack_level(),
    332     )
--> 333 return func(*args, **kwargs)

File ~/scratch/.venv/lib/python3.12/site-packages/pandas/core/frame.py:1394, in DataFrame.to_string(self, buf, columns, col_space, header, index, na_rep, formatters, float_format, sparsify, index_names, justify, max_rows, max_cols, show_dimensions, decimal, line_width, min_rows, max_colwidth, encoding)
   1375 with option_context("display.max_colwidth", max_colwidth):
   1376     formatter = fmt.DataFrameFormatter(
   1377         self,
   1378         columns=columns,
   (...)   1392         decimal=decimal,
   1393     )
-> 1394     return fmt.DataFrameRenderer(formatter).to_string(
   1395         buf=buf,
   1396         encoding=encoding,
   1397         line_width=line_width,
   1398     )

File ~/scratch/.venv/lib/python3.12/site-packages/pandas/io/formats/format.py:962, in DataFrameRenderer.to_string(self, buf, encoding, line_width)
    959 from pandas.io.formats.string import StringFormatter
    961 string_formatter = StringFormatter(self.fmt, line_width=line_width)
--> 962 string = string_formatter.to_string()
    963 return save_to_buffer(string, buf=buf, encoding=encoding)

File ~/scratch/.venv/lib/python3.12/site-packages/pandas/io/formats/string.py:29, in StringFormatter.to_string(self)
     28 def to_string(self) -> str:
---> 29     text = self._get_string_representation()
     30     if self.fmt.should_show_dimensions:
     31         text = f"{text}{self.fmt.dimensions_info}"

File ~/scratch/.venv/lib/python3.12/site-packages/pandas/io/formats/string.py:44, in StringFormatter._get_string_representation(self)
     41 if self.fmt.frame.empty:
     42     return self._empty_info_line
---> 44 strcols = self._get_strcols()
     46 if self.line_width is None:
     47     # no need to wrap around just print the whole frame
     48     return self.adj.adjoin(1, *strcols)

File ~/scratch/.venv/lib/python3.12/site-packages/pandas/io/formats/string.py:35, in StringFormatter._get_strcols(self)
     34 def _get_strcols(self) -> list[list[str]]:
---> 35     strcols = self.fmt.get_strcols()
     36     if self.fmt.is_truncated:
     37         strcols = self._insert_dot_separators(strcols)

File ~/scratch/.venv/lib/python3.12/site-packages/pandas/io/formats/format.py:476, in DataFrameFormatter.get_strcols(self)
    472 def get_strcols(self) -> list[list[str]]:
    473     """
    474     Render a DataFrame to a list of columns (as lists of strings).
    475     """
--> 476     strcols = self._get_strcols_without_index()
    478     if self.index:
    479         str_index = self._get_formatted_index(self.tr_frame)

File ~/scratch/.venv/lib/python3.12/site-packages/pandas/io/formats/format.py:729, in DataFrameFormatter._get_strcols_without_index(self)
    727     str_columns = [[label] for label in self.header]
    728 else:
--> 729     str_columns = self._get_formatted_column_labels(self.tr_frame)
    731 if self.show_row_idx_names:
    732     for x in str_columns:

File ~/scratch/.venv/lib/python3.12/site-packages/pandas/io/formats/format.py:811, in DataFrameFormatter._get_formatted_column_labels(self, frame)
    808     dtypes = self.frame.dtypes
    809     need_leadsp = dict(zip(fmt_columns, map(is_numeric_dtype, dtypes)))
    810     str_columns = [
--> 811         [" " + x if not self._get_formatter(i) and need_leadsp[x] else x]
    812         for i, x in enumerate(fmt_columns)
    813     ]
    814 # self.str_columns = str_columns
    815 return str_columns

File ~/scratch/.venv/lib/python3.12/site-packages/pandas/io/formats/format.py:774, in DataFrameFormatter._get_formatter(self, i)
    772 if is_integer(i) and i not in self.columns:
    773     i = self.columns[i]
--> 774 return self.formatters.get(i, None)

TypeError: unhashable type: 'list'

Anyway, I think the intention is that the type annotation for column names, even in the stubs, is meant to be accurate

What the pandas stubs often do is to not type deprecated or discouraged behaviour

1 Like

Here is the video with the sound mixed in and edited to remove transitions: https://www.youtube.com/watch?v=7uixlNTOY4s

6 Likes

Thanks one more time to all those who presented at the Typing Summit this year, and a big thanks @lolpack for the recordings!!

For anyone who wants to refer back to talks, or was unable to attend (we do still expect to have recordings soon), here are the materials presented that I have so far:

3 Likes