diff --git a/panel/io/embed.py b/panel/io/embed.py index 15fb7e397a..ad7e78edb9 100644 --- a/panel/io/embed.py +++ b/panel/io/embed.py @@ -319,12 +319,12 @@ def is_embeddable(object): if len(cross_product) > max_states: if config._doc_build: return - param.main.param.warning('The cross product of different application ' - 'states is very large to explore (N=%d), consider ' - 'reducing the number of options on the widgets or ' - 'increase the max_states specified in the function ' - 'to remove this warning' % - len(cross_product)) + param.main.param.warning( + 'The cross product of different application states is very large ' + f'to explore (N={len(cross_product)}), consider reducing the number ' + 'of options on the widgets or increase the max_states specified ' + 'in the function to remove this warning.' + ) nested_dict = lambda: defaultdict(nested_dict) state_dict = nested_dict() diff --git a/panel/io/server.py b/panel/io/server.py index 238d99120d..0a9bf39ad4 100644 --- a/panel/io/server.py +++ b/panel/io/server.py @@ -107,9 +107,9 @@ def _origin_url(url: str) -> str: def _server_url(url: str, port: int) -> str: if url.startswith("http"): - return '%s:%d%s' % (url.rsplit(':', 1)[0], port, "/") + return f"{url.rsplit(':', 1)[0]}:{port}/" else: - return 'http://%s:%d%s' % (url.split(':')[0], port, "/") + return f"http://{url.split(':')[0]}:{port}/" def async_execute(func: Callable[..., None]) -> None: """ diff --git a/panel/layout/base.py b/panel/layout/base.py index 51d3ac0871..692315c6db 100644 --- a/panel/layout/base.py +++ b/panel/layout/base.py @@ -70,10 +70,11 @@ def __repr__(self, depth: int = 0, max_depth: int = 10) -> str: spacer = '\n' + (' ' * (depth+1)) cls = type(self).__name__ params = param_reprs(self, ['objects']) - objs = ['[%d] %s' % (i, obj.__repr__(depth+1)) for i, obj in enumerate(self)] + objs = [f'[{i}] {obj.__repr__(depth+1)}' for i, obj in enumerate(self)] if not params and not objs: return super().__repr__(depth+1) - elif not params: + + if not params: template = '{cls}{spacer}{objs}' elif not objs: template = '{cls}({params})' @@ -81,7 +82,8 @@ def __repr__(self, depth: int = 0, max_depth: int = 10) -> str: template = '{cls}({params}){spacer}{objs}' return template.format( cls=cls, params=', '.join(params), - objs=str(spacer).join(objs), spacer=spacer) + objs=str(spacer).join(objs), spacer=spacer + ) #---------------------------------------------------------------- # Callback API @@ -393,34 +395,40 @@ def __contains__(self, obj: Viewable) -> bool: def __setitem__(self, index: int | slice, panes: Iterable[Any]) -> None: new_objects = list(self) + name = type(self).__name__ if not isinstance(index, slice): start, end = index, index+1 if start > len(self.objects): - raise IndexError('Index %d out of bounds on %s ' - 'containing %d objects.' % - (end, type(self).__name__, len(self.objects))) + raise IndexError( + f'Index {end} out of bounds on {name} containing ' + f'{len(self.objects)} objects.' + ) panes = [panes] else: start = index.start or 0 end = len(self) if index.stop is None else index.stop if index.start is None and index.stop is None: if not isinstance(panes, list): - raise IndexError('Expected a list of objects to ' - f'replace the objects in the {type(self).__name__}, ' - f'got a {type(panes).__name__} type.') + raise IndexError( + 'Expected a list of objects to replace the ' + f'objects in the {name}, got a ' + f'{type(panes).__name__} type.' + ) expected = len(panes) new_objects = [None]*expected # type: ignore end = expected elif end > len(self.objects): - raise IndexError('Index %d out of bounds on %s ' - 'containing %d objects.' % - (end, type(self).__name__, len(self.objects))) + raise IndexError( + f'Index {end} out of bounds on {name} containing ' + f'{len(self.objects)} objects.' + ) else: expected = end-start if not isinstance(panes, list) or len(panes) != expected: - raise IndexError('Expected a list of %d objects to set ' - 'on the %s to match the supplied slice.' % - (expected, type(self).__name__)) + raise IndexError( + f'Expected a list of {expected} objects to set ' + f'on the {name} to match the supplied slice.' + ) for i, pane in zip(range(start, end), panes): new_objects[i] = pane @@ -445,8 +453,10 @@ def clone(self, *objects: Any, **params: Any) -> ListLike: else: objects = self.objects elif 'objects' in params: - raise ValueError(f"A {type(self).__name__}'s objects should be supplied either " - "as arguments or as a keyword, not both.") + raise ValueError( + f"A {type(self).__name__}'s objects should be supplied either " + "as arguments or as a keyword, not both." + ) p = dict(self.param.values(), **params) del p['objects'] return type(self)(*objects, **p) @@ -645,11 +655,13 @@ def __radd__(self, other: Iterable[Any]) -> NamedListLike: def __setitem__(self, index: int | slice, panes: Iterable[Any]) -> None: new_objects = list(self) + name = type(self).__name__ if not isinstance(index, slice): if index > len(self.objects): - raise IndexError('Index %d out of bounds on %s ' - 'containing %d objects.' % - (index, type(self).__name__, len(self.objects))) + raise IndexError( + f'Index {index} out of bounds on {name} ' + f'containing {len(self.objects)} objects.' + ) start, end = index, index+1 panes = [panes] else: @@ -657,23 +669,28 @@ def __setitem__(self, index: int | slice, panes: Iterable[Any]) -> None: end = len(self.objects) if index.stop is None else index.stop if index.start is None and index.stop is None: if not isinstance(panes, list): - raise IndexError('Expected a list of objects to ' - f'replace the objects in the {type(self).__name__}, ' - f'got a {type(panes).__name__} type.') + raise IndexError( + 'Expected a list of objects to replace ' + f'the objects in the {name}, got a ' + f'{type(panes).__name__} type.' + ) expected = len(panes) new_objects = [None]*expected # type: ignore self._names = [None]*len(panes) end = expected else: expected = end-start - if end > len(self.objects): - raise IndexError('Index %d out of bounds on %s ' - 'containing %d objects.' % - (end, type(self).__name__, len(self.objects))) + nobjs = len(self.objects) + if end > nobjs: + raise IndexError( + f'Index {end} out of bounds on {name} ' + 'containing {nobjs} objects.' + ) if not isinstance(panes, list) or len(panes) != expected: - raise IndexError('Expected a list of %d objects to set ' - 'on the %s to match the supplied slice.' % - (expected, type(self).__name__)) + raise IndexError( + f'Expected a list of {expected} objects to set ' + f'on the {name} to match the supplied slice.' + ) for i, pane in zip(range(start, end), panes): new_objects[i], self._names[i] = self._to_object_and_name(pane) self.objects = new_objects @@ -694,9 +711,10 @@ def clone(self, *objects: Any, **params: Any) -> NamedListLike: if objects: overrides = objects elif 'objects' in params: - raise ValueError('Tabs objects should be supplied either ' - 'as positional arguments or as a keyword, ' - 'not both.') + raise ValueError( + 'Tabs objects should be supplied either as positional ' + 'arguments or as a keyword, not both.' + ) elif 'objects' in params: overrides = params.pop('objects') else: diff --git a/panel/layout/grid.py b/panel/layout/grid.py index 44c3fb02d0..d4dae9b349 100644 --- a/panel/layout/grid.py +++ b/panel/layout/grid.py @@ -554,12 +554,14 @@ def __setitem__(self, index, obj): continue if old_obj not in objects: objects.append(old_obj) - overlapping += ' (%d, %d): %s\n\n' % (yidx, xidx, old_obj) - overlap_text = ('Specified region overlaps with the following ' - 'existing object(s) in the grid:\n\n'+overlapping+ - 'The following shows a view of the grid ' - '(empty: 0, occupied: 1, overlapping: 2):\n\n'+ - str(grid.astype('uint8'))) + overlapping += f' ({yidx}, {xidx}: {old_obj}\n\n' + overlap_text = ( + 'Specified region overlaps with the following ' + 'existing object(s) in the grid:\n\n'+overlapping+ + 'The following shows a view of the grid ' + '(empty: 0, occupied: 1, overlapping: 2):\n\n'+ + str(grid.astype('uint8')) + ) if self.mode == 'error': raise IndexError(overlap_text) elif self.mode == 'warn': diff --git a/panel/layout/tabs.py b/panel/layout/tabs.py index 5a2e66333b..9d753dcffb 100644 --- a/panel/layout/tabs.py +++ b/panel/layout/tabs.py @@ -161,10 +161,11 @@ def _get_objects(self, model, old_objects, doc, root, comm=None): from ..pane.base import RerenderError, panel new_models, old_models = [], [] if len(self._names) != len(self): - raise ValueError('Tab names do not match objects, ensure ' - 'that the Tabs.objects are not modified ' - 'directly. Found %d names, expected %d.' % - (len(self._names), len(self))) + raise ValueError( + 'Tab names do not match objects, ensure that the ' + 'Tabs.objects are not modified directly. ' + f'Found {len(self._names)} names, expected {len(self)}.' + ) for i, (name, pane) in enumerate(zip(self._names, self)): pane = panel(pane, name=name) self.objects[i] = pane diff --git a/panel/pane/vtk/synchronizable_serializer.py b/panel/pane/vtk/synchronizable_serializer.py index 9f0c35db82..ec9788de7d 100644 --- a/panel/pane/vtk/synchronizable_serializer.py +++ b/panel/pane/vtk/synchronizable_serializer.py @@ -725,7 +725,7 @@ def genericMapperSerializer(parent, mapper, mapperId, context, depth): for port in range(mapper.GetNumberOfInputPorts()): # Glyph3DMapper can define input data objects on 2 ports (input, source) dataObject = mapper.GetInputDataObject(port, 0) if dataObject: - dataObjectId = '%s-dataset-%d' % (mapperId, port) + dataObjectId = f'{mapperId}-dataset-{port}' if parent.IsA('vtkActor') and not mapper.IsA('vtkTexture'): # vtk-js actors can render only surfacic datasets # => we ensure to convert the dataset in polydata diff --git a/panel/pipeline.py b/panel/pipeline.py index aa475b983a..da1d067052 100644 --- a/panel/pipeline.py +++ b/panel/pipeline.py @@ -239,7 +239,7 @@ def __repr__(self): else: cls_name = stage.__name__ params = ', '.join(param_reprs(stage)) - repr_str += '\n [%d] %s: %s(%s)' % (i, name, cls_name, params) + repr_str += f'\n [{i}] {name}: {cls_name}({params})' return repr_str def __str__(self): diff --git a/panel/reactive.py b/panel/reactive.py index 7fc101cec2..f95ed0a7d3 100644 --- a/panel/reactive.py +++ b/panel/reactive.py @@ -2048,7 +2048,7 @@ def _get_template(self) -> tuple[str, list[str], Mapping[str, list[tuple[str, li for parent, child_name in self._parser.children.items(): if (parent, child_name) in self._parser.looped: for i, _ in enumerate(getattr(self, child_name)): - html = html.replace('${%s[%d]}' % (child_name, i), '') + html = html.replace(f'${{{child_name}[{i}]}}', '') else: html = html.replace(f'${{{child_name}}}', '') return html, parser.nodes, p_attrs diff --git a/panel/tests/io/test_embed.py b/panel/tests/io/test_embed.py index 85f590ac36..8c351f0999 100644 --- a/panel/tests/io/test_embed.py +++ b/panel/tests/io/test_embed.py @@ -442,7 +442,7 @@ def link(target, event): assert event1['kind'] == 'ModelChanged' assert event1['attr'] == 'text' assert event1['model'] == model.children[0].children[0].ref - assert event1['new'] == '%d' % values[k] + assert event1['new'] == f'{values[k]:.0f}' assert event2['kind'] == 'ModelChanged' assert event2['attr'] == 'text' diff --git a/panel/tests/test_param.py b/panel/tests/test_param.py index 18dfb99b91..dcd9a7f6a8 100644 --- a/panel/tests/test_param.py +++ b/panel/tests/test_param.py @@ -1147,11 +1147,11 @@ class View(param.Parameterized): @param.depends('a') def view(self): - return Div(text='%d' % self.a) + return Div(text=str(int(self.a))) @param.depends('b.param') def subobject_view(self): - return Div(text='%d' % self.b.a) + return Div(text=str(int(self.b.a))) @param.depends('a') def mpl_view(self): @@ -1166,7 +1166,7 @@ def test_get_param_function_pane_type(): test = View() def view(a): - return Div(text='%d' % a) + return Div(text=str(int(a))) assert PaneBase.get_pane_type(view) is not ParamFunction assert PaneBase.get_pane_type(param.depends(test.param.a)(view)) is ParamFunction @@ -1177,7 +1177,7 @@ def test_param_function_pane(document, comm): @param.depends(test.param.a) def view(a): - return Div(text='%d' % a) + return Div(text=str(int(a))) pane = panel(view) inner_pane = pane._pane @@ -1218,7 +1218,7 @@ def test_param_function_pane_defer_load(document, comm): @param.depends(test.param.a) def view(a): - return Div(text='%d' % a) + return Div(text=str(int(a))) pane = panel(view, defer_load=True) inner_pane = pane._pane diff --git a/panel/tests/util.py b/panel/tests/util.py index 212b84a4f5..1d351321ac 100644 --- a/panel/tests/util.py +++ b/panel/tests/util.py @@ -468,7 +468,7 @@ def http_serve_directory(directory=".", port=0): httpd.timeout = 0.5 httpd.server_bind() - address = "http://%s:%d" % (httpd.server_name, httpd.server_port) + address = f"http://{httpd.server_name}:{httpd.server_port}" httpd.server_activate() diff --git a/panel/tests/widgets/test_slider.py b/panel/tests/widgets/test_slider.py index a588805b5a..45c2cbb448 100644 --- a/panel/tests/widgets/test_slider.py +++ b/panel/tests/widgets/test_slider.py @@ -480,7 +480,7 @@ def test_discrete_slider_disabled(document, comm): def test_discrete_date_slider(document, comm): - dates = {'2016-01-0%d' % i: datetime(2016, 1, i) for i in range(1, 4)} + dates = {f'2016-01-0{i:d}' % i: datetime(2016, 1, i) for i in range(1, 4)} discrete_slider = DiscreteSlider(name='DiscreteSlider', value=dates['2016-01-02'], options=dates)