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

Enable strict type checking #7497

Merged
merged 34 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b7037ec
Align types of linked_properties
philippjfr Nov 14, 2024
6e2479b
Begin typing everything
philippjfr Nov 15, 2024
d887943
More typing
philippjfr Nov 15, 2024
19b786f
More fixes
philippjfr Nov 15, 2024
e051df1
Add Tabulator types
philippjfr Nov 15, 2024
95e0b52
More types
philippjfr Nov 15, 2024
750a217
Small fix
philippjfr Nov 15, 2024
9e602c9
More types
philippjfr Nov 15, 2024
396ad6d
More types
philippjfr Nov 16, 2024
71912de
Upgrade type definitions and apply pyupgrade
philippjfr Nov 16, 2024
52bef7c
More updates
philippjfr Nov 16, 2024
b865a10
Update type imports for generics
philippjfr Nov 16, 2024
d9e1f1f
Add more types
philippjfr Nov 16, 2024
949b37c
More minor fixes
philippjfr Nov 16, 2024
6e38a3c
More types
philippjfr Nov 17, 2024
2158148
More types
philippjfr Nov 17, 2024
5264b2f
More types
philippjfr Nov 17, 2024
60b9eb4
More types
philippjfr Nov 17, 2024
ef2fd79
Fix up type error
philippjfr Nov 17, 2024
4b8da9b
Fix tests
philippjfr Nov 17, 2024
04ca6fe
Apply suggestions from code review
philippjfr Nov 17, 2024
19d68bf
Fix up type
philippjfr Nov 17, 2024
5218def
fix textual tests
philippjfr Nov 17, 2024
c867531
Merge branch 'main' into linked_props_types
philippjfr Nov 18, 2024
1a7f4d1
Fix JupyterServerContext
philippjfr Nov 18, 2024
197ff5a
Back out of JupyterServerContext
philippjfr Nov 18, 2024
daa8493
Address review comments
philippjfr Nov 18, 2024
060f415
revert version upgrade
philippjfr Nov 18, 2024
46c1107
Apply suggestions from code review
philippjfr Dec 2, 2024
770be06
Resolve review comments
philippjfr Dec 2, 2024
8c7443a
Small fix
philippjfr Dec 2, 2024
875aeca
Fix types
philippjfr Dec 2, 2024
b8253e3
Another fix
philippjfr Dec 2, 2024
16bd060
Merge branch 'main' into linked_props_types
philippjfr Dec 2, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ jobs:
environments: ${{ matrix.environment }}
- name: Test Type
run: |
pixi run -e ${{ matrix.environment }} test-type || echo "Failed"
pixi run -e ${{ matrix.environment }} test-type

result_test_suite:
name: result:test
Expand Down
36 changes: 19 additions & 17 deletions doc/generate_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,39 +57,40 @@ def write_file(name, text, opts):
"""Write the output file for module/package <name>."""
if opts.dryrun:
return
fname = os.path.join(opts.destdir, "%s.%s" % (name, opts.suffix))
fname = os.path.join(opts.destdir, f"{name}.{opts.suffix}")
if not opts.force and os.path.isfile(fname):
print('File %s already exists, skipping.' % fname)
print(f'File {fname} already exists, skipping.')
else:
print('Creating file %s.' % fname)
print(f'Creating file {fname}.')
f = open(fname, 'w')
f.write(text)
f.close()

def format_heading(level, text):
"""Create a heading of <level> [1, 2 or 3 supported]."""
underlining = ['=', '-', '~', ][level-1] * len(text)
return '%s\n%s\n\n' % (text, underlining)
return f'{text}\n{underlining}\n\n'

def format_directive(module, package=None):
"""Create the automodule directive and add the options."""
directive = '.. automodule:: %s\n' % makename(package, module)
module_name = makename(package, module)
directive = f'.. automodule:: %s{module_name}'
for option in OPTIONS:
directive += ' :%s:\n' % option
directive += f' :{option}:\n'
return directive

def create_module_file(package, module, opts):
"""Build the text of the file and write the file."""

text = format_heading(1, '%s Module' % module)
text += format_heading(2, ':mod:`%s` Module' % module)
text = format_heading(1, f'{module} Module')
text += format_heading(2, f':mod:`{module}` Module')
text += format_directive(module, package)
write_file(makename(package, module), text, opts)

def create_package_file(root, master_package, subroot, py_files, opts, subs):
"""Build the text of the file and write the file."""
package = os.path.split(root)[-1]
text = format_heading(1, '%s.%s Package' % (master_package, package))
text = format_heading(1, f'{master_package}.{package} Package')
text += '\n---------\n\n'
# add each package's module
for py_file in py_files:
Expand All @@ -99,9 +100,9 @@ def create_package_file(root, master_package, subroot, py_files, opts, subs):
py_file = os.path.splitext(py_file)[0]
py_path = makename(subroot, py_file)
if is_package:
heading = ':mod:`%s` Package' % package
heading = f':mod:`{package}` Package'
else:
heading = ':mod:`%s` Module' % py_file
heading = f':mod:`{py_file}` Module'
text += format_heading(2, heading)
text += '\n\n'
text += format_directive(is_package and subroot or py_path, master_package)
Expand All @@ -113,8 +114,9 @@ def create_package_file(root, master_package, subroot, py_files, opts, subs):
if subs:
text += format_heading(2, 'Subpackages')
text += '.. toctree::\n\n'
subpackage_name = makename(master_package, subroot)
for sub in subs:
text += ' %s.%s\n' % (makename(master_package, subroot), sub)
text += f' {subpackage_name}.{sub}\n'
text += '\n'

write_file(makename(master_package, subroot), text, opts)
Expand All @@ -123,9 +125,9 @@ def create_modules_toc_file(master_package, modules, opts, name='modules'):
"""
Create the module's index.
"""
text = format_heading(1, '%s Modules' % opts.header)
text = format_heading(1, f'{opts.header} Modules')
text += '.. toctree::\n'
text += ' :maxdepth: %s\n\n' % opts.maxdepth
text += f' :maxdepth: {opts.maxdepth}\n\n'

modules.sort()
prev_module = ''
Expand All @@ -134,7 +136,7 @@ def create_modules_toc_file(master_package, modules, opts, name='modules'):
if module.startswith(prev_module + '.'):
continue
prev_module = module
text += ' %s\n' % module
text += f' {module}\n'

write_file(name, text, opts)

Expand Down Expand Up @@ -261,9 +263,9 @@ def main():
excludes = normalize_excludes(rootpath, excludes)
recurse_tree(rootpath, excludes, opts)
else:
print('%s is not a valid output destination directory.' % opts.destdir)
print(f'{opts.destdir} is not a valid output destination directory.')
else:
print('%s is not a valid directory.' % rootpath)
print(f'{rootpath} is not a valid directory.')


if __name__ == '__main__':
Expand Down
2 changes: 1 addition & 1 deletion examples/apps/django/sliders/sinewave.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class SineWave(param.Parameterized):
y_range = param.Range(default=(-2.5,2.5),bounds=(-10,10))

def __init__(self, **params):
super(SineWave, self).__init__(**params)
super().__init__(**params)
x, y = self.sine()
self.cds = ColumnDataSource(data=dict(x=x, y=y))
self.plot = figure(height=400, width=400,
Expand Down
2 changes: 1 addition & 1 deletion examples/apps/django_multi_apps/gbm/pn_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class GBM(param.Parameterized):
refresh = pn.widgets.Button(name="Refresh", button_type='primary')

def __init__(self, **params):
super(GBM, self).__init__(**params)
super().__init__(**params)

# update the plot for every changes
# @param.depends('mean', 'volatility', 'maturity', 'n_observations', 'n_simulations', watch=True)
Expand Down
2 changes: 1 addition & 1 deletion examples/apps/django_multi_apps/sliders/pn_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class SineWave(param.Parameterized):
y_range = param.Range(default=(-2.5, 2.5), bounds=(-10, 10))

def __init__(self, **params):
super(SineWave, self).__init__(**params)
super().__init__(**params)
x, y = self.sine()
self.cds = ColumnDataSource(data=dict(x=x, y=y))
self.plot = figure(height=400, width=400,
Expand Down
2 changes: 1 addition & 1 deletion examples/apps/django_multi_apps/stockscreener/pn_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class StockScreener(param.Parameterized):
def __init__(self, df, **params):
start = dt.date(year=df.index[0].year, month=df.index[0].month, day=df.index[0].day)
end = dt.date(year=df.index[-1].year, month=df.index[-1].month, day=df.index[-1].day)
super(StockScreener, self).__init__(df=df, start=start, **params)
super().__init__(df=df, start=start, **params)
self.param.start.bounds = (start, end)
columns = list(self.df.columns)
self.param.index.objects = columns
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class StockScreener(param.Parameterized):
From = pn.widgets.DateSlider()

def __init__(self, df, **params):
super(StockScreener, self).__init__(**params)
super().__init__(**params)
# init df
self.df = df
self.start_date = dt.datetime(year=df.index[0].year, month=df.index[0].month, day=df.index[0].day)
Expand Down
2 changes: 1 addition & 1 deletion examples/apps/fastApi/sliders/sinewave.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class SineWave(param.Parameterized):
y_range = param.Range(default=(-2.5, 2.5), bounds=(-10, 10))

def __init__(self, **params):
super(SineWave, self).__init__(**params)
super().__init__(**params)
x, y = self.sine()
self.cds = ColumnDataSource(data=dict(x=x, y=y))
self.plot = figure(height=400, width=400,
Expand Down
2 changes: 1 addition & 1 deletion examples/apps/fastApi_multi_apps/sliders/sinewave.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class SineWave(param.Parameterized):
y_range = param.Range(default=(-2.5, 2.5), bounds=(-10, 10))

def __init__(self, **params):
super(SineWave, self).__init__(**params)
super().__init__(**params)
x, y = self.sine()
self.cds = ColumnDataSource(data=dict(x=x, y=y))
self.plot = figure(height=400, width=400,
Expand Down
2 changes: 1 addition & 1 deletion examples/apps/fastApi_multi_apps/sliders2/sinewave.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class SineWave(param.Parameterized):
y_range = param.Range(default=(-2.5, 2.5), bounds=(-10, 10))

def __init__(self, **params):
super(SineWave, self).__init__(**params)
super().__init__(**params)
x, y = self.sine()
self.cds = ColumnDataSource(data=dict(x=x, y=y))
self.plot = figure(height=400, width=400,
Expand Down
2 changes: 1 addition & 1 deletion panel/__main__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import sys


def main():
def main() -> None:
from panel.command import main as _main

# Main entry point (see setup.py)
Expand Down
46 changes: 33 additions & 13 deletions panel/_param.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
from __future__ import annotations

from typing import (
Any, Literal, TypeAlias, cast,
)

from bokeh.core.enums import enumeration
from param import Parameter, _is_number

AlignmentType = Literal["auto", "start", "center", "end"]
Alignment = enumeration(AlignmentType)
MarginType: TypeAlias = int | tuple[int, int] | tuple[int, int, int, int]


class Align(Parameter):
"""
Expand All @@ -8,16 +19,20 @@ class Align(Parameter):
to the (vertical, horizontal) alignment.
"""

def __init__(self, default='start', **params):
def __init__(
self,
default: AlignmentType | tuple[AlignmentType, AlignmentType] = "start",
**params: Any
):
super().__init__(default=default, **params)
self._validate(default)

def _validate(self, val):
def _validate(self, val: Any) -> None:
self._validate_value(val, self.allow_None)

def _validate_value(self, val, allow_None, valid=('auto', 'start', 'center', 'end')):
if ((val is None and allow_None) or val in valid or
(isinstance(val, tuple) and len(val) == 2 and all(v in valid for v in val))):
def _validate_value(self, val: Any, allow_None: bool) -> None:
if ((val is None and allow_None) or val in Alignment or
(isinstance(val, tuple) and len(val) == 2 and all(v in Alignment for v in val))):
return
raise ValueError(
f"Align parameter {self.name!r} must be one of 'start', "
Expand All @@ -36,10 +51,10 @@ def __init__(self, default=None, allow_None=True, **params):
super().__init__(default=default, allow_None=allow_None, **params)
self._validate(default)

def _validate(self, val):
def _validate(self, val: Any) -> None:
self._validate_value(val, self.allow_None)

def _validate_value(self, val, allow_None):
def _validate_value(self, val: Any, allow_None: bool) -> None:
if (val is None and allow_None) or val == 'auto' or _is_number(val):
return
raise ValueError(
Expand All @@ -60,7 +75,7 @@ def __init__(self, default=None, allow_None=True, **params):
super().__init__(default=default, allow_None=allow_None, **params)
self._validate(default)

def _validate_value(self, val, allow_None):
def _validate_value(self, val: Any, allow_None: bool) -> None:
if val is None and allow_None:
return
if not isinstance(val, (tuple, int)):
Expand All @@ -69,7 +84,7 @@ def _validate_value(self, val, allow_None):
f'tuple values, not values of not {type(val)!r}.'
)

def _validate_length(self, val):
def _validate_length(self, val: Any) -> None:
if not isinstance(val, tuple) or len(val) in (2, 4):
return
raise ValueError(
Expand All @@ -78,18 +93,23 @@ def _validate_length(self, val):
'(top, right, bottom, left).'
)

def _validate(self, val):
def _validate(self, val: Any) -> None:
self._validate_value(val, self.allow_None)
self._validate_length(val)

@classmethod
def serialize(cls, value):
def serialize(cls, value: MarginType) -> Literal['null'] | list[int] | int:
if value is None:
return 'null'
return list(value) if isinstance(value, tuple) else value

@classmethod
def deserialize(cls, value):
def deserialize(cls, value: Literal['null'] | list[int] | int) -> MarginType | None:
if value == 'null':
return None
return tuple(value) if isinstance(value, list) else value
elif isinstance(value, list):
n = len(value)
if (n < 2 or n > 5):
philippjfr marked this conversation as resolved.
Show resolved Hide resolved
raise ValueError(f'Cannot deserialize list of length {n}.')
return cast(MarginType, tuple(value))
philippjfr marked this conversation as resolved.
Show resolved Hide resolved
return value
7 changes: 4 additions & 3 deletions panel/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from base64 import urlsafe_b64encode
from functools import partial
from typing import ClassVar

import tornado

Expand Down Expand Up @@ -101,13 +102,13 @@ class OAuthLoginHandler(tornado.web.RequestHandler, OAuth2Mixin):
'grant_type': 'authorization_code'
}

_access_token_header = None
_access_token_header: ClassVar[str | None] = None

_state_cookie = None
_state_cookie: ClassVar[str | None] = None

_error_template = ERROR_TEMPLATE

_login_endpoint = '/login'
_login_endpoint: ClassVar[str] = '/login'

@property
def _SCOPE(self):
Expand Down
Loading
Loading