ronantakizawa/codereview-bench huggingface dataset:
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/graspop.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import (
    traverse_obj,
)


class GraspopIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.graspop\.be/(?P<lang>fr|nl)/(?P<id>[0-9]+)/(?P<title>.*)/'
    _TESTS = [{
        'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/',
        'info_dict': {
            'id': '101556',
            'ext': 'mp4',
            'title': 'Thy Art Is Murder',
            'description': 'Thy Art Is Murder @ Graspop',
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.*\.jpg',
            'formats': 'count:4',
        },
        'params': {
            'nocheckcertificate': True,
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)

        # e.g. https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/
        # e.g. https://tv.proximus.be/MWC/videocenter/festivals/101556/stream
        metadata = self._download_json(f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)

Review comment (suggestion):
```suggestion
from ..utils import url_or_none
from ..utils.traversal import traverse_obj
```

Code after:
from .common import InfoExtractor
from ..utils import update_url, url_or_none
from ..utils.traversal import traverse_obj


class GraspopIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.graspop\.be/[a-z]{2}/(?P<id>\d+)/'
    _TESTS = [{
        'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/',
        'info_dict': {
            'id': '101556',
            'ext': 'mp4',
            'title': 'Thy Art Is Murder',
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.+\.jpg',
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        metadata = self._download_json(
            f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)

        return {
            'id': video_id,
            'formats': self._extract_m3u8_formats(
                # Downgrade manifest request to avoid incomplete certificate chain error
                update_url(metadata['source']['assetUri'], scheme='http'), video_id, 'mp4'),
            **traverse_obj(metadata, {
                'title': ('name', {str}),
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/graspop.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import (
    traverse_obj,
)


class GraspopIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.graspop\.be/(?P<lang>fr|nl)/(?P<id>[0-9]+)/(?P<title>.*)/'
    _TESTS = [{
        'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/',
        'info_dict': {
            'id': '101556',
            'ext': 'mp4',
            'title': 'Thy Art Is Murder',
            'description': 'Thy Art Is Murder @ Graspop',
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.*\.jpg',
            'formats': 'count:4',
        },
        'params': {
            'nocheckcertificate': True,
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)

        # e.g. https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/
        # e.g. https://tv.proximus.be/MWC/videocenter/festivals/101556/stream
        metadata = self._download_json(f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)
        band_name = metadata.get('name')
        asset_uri = traverse_obj(metadata, ('source', 'assetUri'))
        poster = traverse_obj(metadata, ('source', 'poster'))

        formats = self._extract_m3u8_formats(asset_uri, video_id=video_id, ext='mp4')

        return {
            'id': video_id,
            'title': band_name,
            'description': f'{band_name} @ Graspop',
            'thumbnail': poster,
            'formats': formats,

Review comment (suggestion):
```suggestion
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.+\.jpg',
```

Code after:
from .common import InfoExtractor
from ..utils import update_url, url_or_none
from ..utils.traversal import traverse_obj


class GraspopIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.graspop\.be/[a-z]{2}/(?P<id>\d+)/'
    _TESTS = [{
        'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/',
        'info_dict': {
            'id': '101556',
            'ext': 'mp4',
            'title': 'Thy Art Is Murder',
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.+\.jpg',
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        metadata = self._download_json(
            f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)

        return {
            'id': video_id,
            'formats': self._extract_m3u8_formats(
                # Downgrade manifest request to avoid incomplete certificate chain error
                update_url(metadata['source']['assetUri'], scheme='http'), video_id, 'mp4'),
            **traverse_obj(metadata, {
                'title': ('name', {str}),
                'thumbnail': ('source', 'poster', {url_or_none}),
            }),
        }
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/graspop.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import (
    traverse_obj,
)


class GraspopIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.graspop\.be/(?P<lang>fr|nl)/(?P<id>[0-9]+)/(?P<title>.*)/'
    _TESTS = [{
        'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/',
        'info_dict': {
            'id': '101556',
            'ext': 'mp4',
            'title': 'Thy Art Is Murder',
            'description': 'Thy Art Is Murder @ Graspop',
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.*\.jpg',
            'formats': 'count:4',
        },
        'params': {
            'nocheckcertificate': True,
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)

        # e.g. https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/
        # e.g. https://tv.proximus.be/MWC/videocenter/festivals/101556/stream
        metadata = self._download_json(f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)
        band_name = metadata.get('name')
        asset_uri = traverse_obj(metadata, ('source', 'assetUri'))
        poster = traverse_obj(metadata, ('source', 'poster'))

        formats = self._extract_m3u8_formats(asset_uri, video_id=video_id, ext='mp4')

        return {
            'id': video_id,
            'title': band_name,
            'description': f'{band_name} @ Graspop',
            'thumbnail': poster,
            'formats': formats,
        }


Review comment (refactor):
Is this required for this site? I hope not. But if yes, then we should use `http` URLs for all requests. If it's only needed for your local configuration, then remove this and make use of `test/local_parameters.json` for running the tests

Code after:
from .common import InfoExtractor
from ..utils import update_url, url_or_none
from ..utils.traversal import traverse_obj


class GraspopIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.graspop\.be/[a-z]{2}/(?P<id>\d+)/'
    _TESTS = [{
        'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/',
        'info_dict': {
            'id': '101556',
            'ext': 'mp4',
            'title': 'Thy Art Is Murder',
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.+\.jpg',
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        metadata = self._download_json(
            f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)

        return {
            'id': video_id,
            'formats': self._extract_m3u8_formats(
                # Downgrade manifest request to avoid incomplete certificate chain error
                update_url(metadata['source']['assetUri'], scheme='http'), video_id, 'mp4'),
            **traverse_obj(metadata, {
                'title': ('name', {str}),
                'thumbnail': ('source', 'poster', {url_or_none}),
            }),
        }
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/graspop.py (Python)

Code before:
)


class GraspopIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.graspop\.be/(?P<lang>fr|nl)/(?P<id>[0-9]+)/(?P<title>.*)/'
    _TESTS = [{
        'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/',
        'info_dict': {
            'id': '101556',
            'ext': 'mp4',
            'title': 'Thy Art Is Murder',
            'description': 'Thy Art Is Murder @ Graspop',
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.*\.jpg',
            'formats': 'count:4',
        },
        'params': {
            'nocheckcertificate': True,
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)

        # e.g. https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/
        # e.g. https://tv.proximus.be/MWC/videocenter/festivals/101556/stream
        metadata = self._download_json(f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)
        band_name = metadata.get('name')
        asset_uri = traverse_obj(metadata, ('source', 'assetUri'))
        poster = traverse_obj(metadata, ('source', 'poster'))

        formats = self._extract_m3u8_formats(asset_uri, video_id=video_id, ext='mp4')

        return {
            'id': video_id,
            'title': band_name,
            'description': f'{band_name} @ Graspop',
            'thumbnail': poster,
            'formats': formats,
        }


Review comment (refactor):
line too long
```suggestion
        metadata = self._download_json(
            f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)
```

Code after:


class GraspopIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.graspop\.be/[a-z]{2}/(?P<id>\d+)/'
    _TESTS = [{
        'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/',
        'info_dict': {
            'id': '101556',
            'ext': 'mp4',
            'title': 'Thy Art Is Murder',
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.+\.jpg',
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        metadata = self._download_json(
            f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)

        return {
            'id': video_id,
            'formats': self._extract_m3u8_formats(
                # Downgrade manifest request to avoid incomplete certificate chain error
                update_url(metadata['source']['assetUri'], scheme='http'), video_id, 'mp4'),
            **traverse_obj(metadata, {
                'title': ('name', {str}),
                'thumbnail': ('source', 'poster', {url_or_none}),
            }),
        }
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/graspop.py (Python)

Code before:
            'formats': 'count:4',
        },
        'params': {
            'nocheckcertificate': True,
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)

        # e.g. https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/
        # e.g. https://tv.proximus.be/MWC/videocenter/festivals/101556/stream
        metadata = self._download_json(f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)
        band_name = metadata.get('name')
        asset_uri = traverse_obj(metadata, ('source', 'assetUri'))
        poster = traverse_obj(metadata, ('source', 'poster'))

        formats = self._extract_m3u8_formats(asset_uri, video_id=video_id, ext='mp4')

        return {
            'id': video_id,
            'title': band_name,
            'description': f'{band_name} @ Graspop',
            'thumbnail': poster,
            'formats': formats,
        }


Review comment (refactor):
- we can inline all of this in the return
- we don't need to use `traverse_obj` for the m3u8 url if the subsequent `_extract_m3u8_formats` call is fatal; we can let the KeyError rip
- constructing the description like that doesn't seem useful to me

```suggestion
        return {
            'id': video_id,
            'formats': self._extract_m3u8_formats(metadata['source']['assetUri'], video_id, 'mp4'),
            **traverse_obj(metadata, {
                'title': ('name', {str}),
                'thumbnail': ('source', 'poster', {url_or_none}),
            }),
        }
```

Code after:
from .common import InfoExtractor
from ..utils import update_url, url_or_none
from ..utils.traversal import traverse_obj


class GraspopIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.graspop\.be/[a-z]{2}/(?P<id>\d+)/'
    _TESTS = [{
        'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/',
        'info_dict': {
            'id': '101556',
            'ext': 'mp4',
            'title': 'Thy Art Is Murder',
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.+\.jpg',
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        metadata = self._download_json(
            f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)

        return {
            'id': video_id,
            'formats': self._extract_m3u8_formats(
                # Downgrade manifest request to avoid incomplete certificate chain error
                update_url(metadata['source']['assetUri'], scheme='http'), video_id, 'mp4'),
            **traverse_obj(metadata, {
                'title': ('name', {str}),
                'thumbnail': ('source', 'poster', {url_or_none}),
            }),
        }
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/graspop.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import (
    traverse_obj,
)


class GraspopIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.graspop\.be/(?P<lang>fr|nl)/(?P<id>[0-9]+)/(?P<title>.*)/'
    _TESTS = [{
        'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/',
        'info_dict': {
            'id': '101556',
            'ext': 'mp4',
            'title': 'Thy Art Is Murder',
            'description': 'Thy Art Is Murder @ Graspop',
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.*\.jpg',
            'formats': 'count:4',
        },
        'params': {
            'nocheckcertificate': True,
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)

        # e.g. https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/
        # e.g. https://tv.proximus.be/MWC/videocenter/festivals/101556/stream
        metadata = self._download_json(f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)
        band_name = metadata.get('name')
        asset_uri = traverse_obj(metadata, ('source', 'assetUri'))
        poster = traverse_obj(metadata, ('source', 'poster'))

        formats = self._extract_m3u8_formats(asset_uri, video_id=video_id, ext='mp4')

        return {
            'id': video_id,
            'title': band_name,
            'description': f'{band_name} @ Graspop',
            'thumbnail': poster,
            'formats': formats,
        }

Review comment (refactor):
not needed. let the test script generate the test dict for you (as explained in the contributing guide's extractor template)

```suggestion
```

Code after:
from .common import InfoExtractor
from ..utils import update_url, url_or_none
from ..utils.traversal import traverse_obj


class GraspopIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.graspop\.be/[a-z]{2}/(?P<id>\d+)/'
    _TESTS = [{
        'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/',
        'info_dict': {
            'id': '101556',
            'ext': 'mp4',
            'title': 'Thy Art Is Murder',
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.+\.jpg',
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        metadata = self._download_json(
            f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)

        return {
            'id': video_id,
            'formats': self._extract_m3u8_formats(
                # Downgrade manifest request to avoid incomplete certificate chain error
                update_url(metadata['source']['assetUri'], scheme='http'), video_id, 'mp4'),
            **traverse_obj(metadata, {
                'title': ('name', {str}),
                'thumbnail': ('source', 'poster', {url_or_none}),
            }),
        }
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/graspop.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import url_or_none
from ..utils.traversal import traverse_obj


class GraspopIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.graspop\.be/[a-z]{2}/(?P<id>\d+)/'
    _TESTS = [{
        'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/',
        'info_dict': {
            'id': '101556',
            'ext': 'mp4',
            'title': 'Thy Art Is Murder',
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.+\.jpg',
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        metadata = self._download_json(
            f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)
        return {
            'id': video_id,
            'formats': self._extract_m3u8_formats(metadata['source']['assetUri'], video_id, 'mp4'),
            **traverse_obj(metadata, {
                'title': ('name', {str}),
                'thumbnail': ('source', 'poster', {url_or_none}),
            }),
        }


Review comment (refactor):
```suggestion
            'formats': self._extract_m3u8_formats(
                # switch to http to avoid incomplete certificate chain error
                metadata['source']['assetUri'].replace('https://', 'http://'), video_id, 'mp4'),
```

Code after:
from .common import InfoExtractor
from ..utils import update_url, url_or_none
from ..utils.traversal import traverse_obj


class GraspopIE(InfoExtractor):
    _VALID_URL = r'https?://vod\.graspop\.be/[a-z]{2}/(?P<id>\d+)/'
    _TESTS = [{
        'url': 'https://vod.graspop.be/fr/101556/thy-art-is-murder-concert/',
        'info_dict': {
            'id': '101556',
            'ext': 'mp4',
            'title': 'Thy Art Is Murder',
            'thumbnail': r're:https://cdn-mds\.pickx\.be/festivals/v3/global/original/.+\.jpg',
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        metadata = self._download_json(
            f'https://tv.proximus.be/MWC/videocenter/festivals/{video_id}/stream', video_id)

        return {
            'id': video_id,
            'formats': self._extract_m3u8_formats(
                # Downgrade manifest request to avoid incomplete certificate chain error
                update_url(metadata['source']['assetUri'], scheme='http'), video_id, 'mp4'),
            **traverse_obj(metadata, {
                'title': ('name', {str}),
                'thumbnail': ('source', 'poster', {url_or_none}),
            }),
        }
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/cbc.py (Python)

Code before:
import base64
import json
import re
import time
import urllib.parse
import xml.etree.ElementTree

from .common import InfoExtractor
from ..utils import (
    base_url,
    ExtractorError,
    float_or_none,
    int_or_none,
    join_nonempty,
    js_to_json,
    orderedSet,
    parse_iso8601,
    remove_end,
    smuggle_url,
    strip_or_none,
    traverse_obj,
    try_get,
    url_basename,
    urljoin,
)


class CBCIE(InfoExtractor):
    IE_NAME = 'cbc.ca'
    _VALID_URL = r'https?://(?:www\.)?cbc\.ca/(?!player/)(?:[^/]+/)+(?P<id>[^/?#]+)'
    _TESTS = [{
        # with mediaId
        'url': 'http://www.cbc.ca/22minutes/videos/clips-season-23/don-cherry-play-offs',
        'md5': '97e24d09672fc4cf56256d6faa6c25bc',
        'info_dict': {
            'id': '2682904050',

Review comment (refactor):
Uppercase comes first
```suggestion
    ExtractorError,
    base_url,
```

Code after:
import base64
import functools
import json
import re
import time
import urllib.parse
import xml.etree.ElementTree

from .common import InfoExtractor
from ..networking import HEADRequest
from ..utils import (
    ExtractorError,
    float_or_none,
    int_or_none,
    join_nonempty,
    js_to_json,
    mimetype2ext,
    orderedSet,
    parse_iso8601,
    replace_extension,
    smuggle_url,
    strip_or_none,
    traverse_obj,
    try_get,
    update_url,
    url_basename,
    url_or_none,
)


class CBCIE(InfoExtractor):
    IE_NAME = 'cbc.ca'
    _VALID_URL = r'https?://(?:www\.)?cbc\.ca/(?!player/)(?:[^/]+/)+(?P<id>[^/?#]+)'
    _TESTS = [{
        # with mediaId
        'url': 'http://www.cbc.ca/22minutes/videos/clips-season-23/don-cherry-play-offs',
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/bandcamp.py (Python)

Code before:
    }, {
        'url': 'https://nuclearwarnowproductions.bandcamp.com/music',
        'playlist_mincount': 399,
        'info_dict': {
            'id': 'nuclearwarnowproductions',
            'title': 'Discography of nuclearwarnowproductions',
        },
    }]

    def _extract_data_attr(self, webpage, video_id, attr, fatal=True):
        return self._parse_json(self._html_search_regex(
            fr'data-{attr}=(["\'])(\[.+?\])\1', webpage,
            attr + ' data', group=2), video_id, fatal=fatal)

    def _real_extract(self, url):
        uploader = self._match_id(url)
        webpage = self._download_webpage(url, uploader)

        matches = []
        if discography_data := (re.findall(r'<li data-item-id=["\'][^>]+>\s*<a href=["\'](?![^"\'/]*?/merch)([^"\']+)', webpage)
                                or re.findall(r'<div[^>]+trackTitle["\'][^"\']+["\']([^"\']+)', webpage)):
            matches += (urljoin(url, path) for path in discography_data)
        if music_grid := self._extract_data_attr(webpage, uploader, 'client-items', fatal=False):
            matches += (urljoin(url, album.get('page_url')) for album in music_grid)

        return self.playlist_from_matches(matches, uploader, f'Discography of {uploader}')


Review comment (suggestion):
and then do this
```suggestion
        return self.playlist_from_matches(
            self._yield_items(webpage), uploader, f'Discography of {uploader}',
            getter=functools.partial(urljoin, url))
```

Code after:
        'playlist_mincount': 7,
        'info_dict': {
            'id': 'coldworldofficial',
            'title': 'Discography of coldworldofficial',
        },
    }, {
        'url': 'https://nuclearwarnowproductions.bandcamp.com/music',
        'playlist_mincount': 399,
        'info_dict': {
            'id': 'nuclearwarnowproductions',
            'title': 'Discography of nuclearwarnowproductions',
        },
    }]

    def _yield_items(self, webpage):
        yield from (
            re.findall(r'<li data-item-id=["\'][^>]+>\s*<a href=["\'](?![^"\'/]*?/merch)([^"\']+)', webpage)
            or re.findall(r'<div[^>]+trackTitle["\'][^"\']+["\']([^"\']+)', webpage))

        yield from traverse_obj(webpage, (
            {functools.partial(get_element_html_by_id, 'music-grid')}, {extract_attributes},
            'data-client-items', {json.loads}, ..., 'page_url', {str}))

    def _real_extract(self, url):
        uploader = self._match_id(url)
        webpage = self._download_webpage(url, uploader)

        return self.playlist_from_matches(
            self._yield_items(webpage), uploader, f'Discography of {uploader}',
            getter=functools.partial(urljoin, url))