Beispiel #1
0
class PyPiClient:
    def __init__(self, cache_path: "str"):
        self.client = PyPISimple()
        self.session = requests.Session()
        self.cache_path = cache_path

    @functools.lru_cache(maxsize=2)
    def list_projects(self):
        try:
            return self.load_cached_mirror()
        except:
            return list(self.client.get_projects())

    def new_projects(self):
        cached_projects = set(self.load_cached_mirror())
        found_projects = set(self.list_projects())

        return set.difference(cached_projects, found_projects)

    def download_mirror(self):
        projects = self.list_projects()

        with open(self.cache_path, 'w', encoding='utf-8-sig') as f:
            json.dump(projects, fp=f)

    def load_cached_mirror(self):
        with open(self.cache_path, 'r', encoding='utf-8-sig') as f:
            doc = json.load(fp=f)
        return doc

    @functools.lru_cache(maxsize=20)
    def extract_latest_project_file(self, project):
        project_files = self.client.get_project_files(project)
        max_version = packaging.version.parse('-1')
        max_file = None
        for project_file in project_files:
            if project_file.version is None:
                version = packaging.version.parse('0.0.0')
            else:
                version = packaging.version.parse(project_file.version)
            if project_file.package_type in ('sdist', 'wheel') and (
                    version > max_version or (version == max_version)
                    and project_file.package_type == 'wheel'):
                max_file, max_version = project_file, version
        if not max_file:
            raise MissingFilesError('Missing files?')
        return max_version, max_file

    @functools.lru_cache(maxsize=20)
    def extract_setup_py(self, project):
        version, project_file = self.extract_latest_project_file(project)
        response = self.session.get(project_file.url, stream=True, timeout=10)
        fp = io.BytesIO(response.content)

        if project_file.filename.endswith(
                '.zip') or project_file.filename.endswith('.whl'):
            zf = zipfile.ZipFile(fp)
            if project_file.filename.endswith('.zip'):
                nameinfos = list(
                    [ni for ni in zf.namelist() if ni.endswith('/setup.py')])
                if nameinfos:
                    return ('setup.py', version, zf.read(nameinfos[0]))
                raise MissingSetupError()
            else:
                nameinfos = list(
                    [ni for ni in zf.namelist() if ni.endswith('/METADATA')])
                if nameinfos:
                    return ('metadata', version, zf.read(nameinfos[0]))
                raise MissingManifestError()
        else:
            tf = tarfile.open(fileobj=fp)
            nameinfos = list(ni for ni in tf.getnames()
                             if ni.endswith('/setup.py'))
            if nameinfos:
                data = tf.extractfile(nameinfos[0])
                return ('setup.py', version, data.read())
            raise MissingSetupError()
Beispiel #2
0
def test_session(content_type):
    session_dir = join(dirname(__file__), 'data', 'session01')
    with open(join(session_dir, 'simple.html')) as fp:
        responses.add(
            method=responses.GET,
            url='https://test.nil/simple/',
            body=fp.read(),
            content_type=content_type,
        )
    responses.add(
        method=responses.GET,
        url='https://test.nil/simple/',
        body='This URL should only be requested once.',
        status=500,
    )
    with open(join(session_dir, 'in-place.html')) as fp:
        responses.add(
            method=responses.GET,
            url='https://test.nil/simple/in-place/',
            body=fp.read(),
            content_type=content_type,
        )
    responses.add(
        method=responses.GET,
        url='https://test.nil/simple/nonexistent/',
        body='Does not exist',
        status=404,
    )

    simple = PyPISimple('https://test.nil/simple/')
    assert list(simple.get_projects()) == ['in_place', 'foo', 'BAR']
    assert simple.get_project_url(
        'IN.PLACE') == 'https://test.nil/simple/in-place/'

    assert simple.get_project_files('IN.PLACE') == [
        DistributionPackage(
            filename='in_place-0.1.1-py2.py3-none-any.whl',
            project='in_place',
            version='0.1.1',
            package_type='wheel',
            url=
            "https://files.pythonhosted.org/packages/34/81/2baaaa588ee1a6faa6354b7c9bc365f1b3da867707cd136dfedff7c06608/in_place-0.1.1-py2.py3-none-any.whl#sha256=e0732b6bdc2f1bfc4e1b96c1de2fbbd053bb2a9534547474a0485baa339bfa97",
            requires_python=None,
            has_sig=False,
            yanked=None,
        ),
        DistributionPackage(
            filename='in_place-0.1.1.tar.gz',
            project='in_place',
            version='0.1.1',
            package_type='sdist',
            url=
            "https://files.pythonhosted.org/packages/b9/ba/f1c67fb32c37ba4263326ae4ac6fd00b128025c9289b2fb31a60a0a22f90/in_place-0.1.1.tar.gz#sha256=ffa729fd0b818ac750aa31bafc886f266380e1c8557ba38f70f422d2f6a77e23",
            requires_python=None,
            has_sig=False,
            yanked=None,
        ),
        DistributionPackage(
            filename='in_place-0.2.0-py2.py3-none-any.whl',
            project='in_place',
            version='0.2.0',
            package_type='wheel',
            url=
            "https://files.pythonhosted.org/packages/9f/46/9f5679f3b2068e10b33c16a628a78b2b36531a9df08671bd0104f11d8461/in_place-0.2.0-py2.py3-none-any.whl#sha256=e1ad42a41dfde02092b411b1634a4be228e28c27553499a81ef04b377b28857c",
            requires_python=None,
            has_sig=False,
            yanked=None,
        ),
        DistributionPackage(
            filename='in_place-0.2.0.tar.gz',
            project='in_place',
            version='0.2.0',
            package_type='sdist',
            url=
            "https://files.pythonhosted.org/packages/f0/51/c30f1fad2b857f7b5d5ff76ec01f1f80dd0f2ab6b6afcde7b2aed54faa7e/in_place-0.2.0.tar.gz#sha256=ff783dca5d06f85b8d084871abd11a170d732423edb48c53ccb68c55fcbbeb76",
            requires_python=None,
            has_sig=False,
            yanked=None,
        ),
        DistributionPackage(
            filename='in_place-0.3.0-py2.py3-none-any.whl',
            project='in_place',
            version='0.3.0',
            package_type='wheel',
            url=
            "https://files.pythonhosted.org/packages/6f/84/ced31e646df335f8cd1b7884e3740b8c012314a28504542ef5631cdc1449/in_place-0.3.0-py2.py3-none-any.whl#sha256=af5ce9bd309f85a6bbe4119acbc0a67cda68f0ae616f0a76a947addc62791fda",
            requires_python=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4",
            has_sig=False,
            yanked=None,
        ),
        DistributionPackage(
            filename='in_place-0.3.0.tar.gz',
            project='in_place',
            version='0.3.0',
            package_type='sdist',
            url=
            "https://files.pythonhosted.org/packages/b6/cd/1dc736d5248420b15dd1546c2938aec7e6dab134e698e0768f54f1757af7/in_place-0.3.0.tar.gz#sha256=4758db1457c8addcd5f5b15ef870eab66b238e46e7d784bff99ab1b2126660ea",
            requires_python=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4",
            has_sig=False,
            yanked=None,
        ),
    ]

    assert simple.get_project_files('nonexistent') == []