Skip to content

make consistent with other extractor tools #4

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

Merged
merged 1 commit into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ message: If you use this software, please cite it using these metadata.
title: PyPi Extractor
abstract: Extract package information for a given user in PyPi.
type: software
version: 0.1.0
version: 0.1.1
date-released: 2024-06-11
repository-code: https://github.com/DevelopersToolbox/pypi-extractor-package
keywords:
Expand Down
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ pip install wolfsoftware.pypi-extractor
Here's a basic example of how to use the PyPI Extractor:

```python
from wolfsoftware.pypi_extractor import PyPIPackageInfo
from wolfsoftware.pypi_extractor import PyPiExtractor

# Initialize without username
pypi_info = PyPIPackageInfo()
pypi_info = PyPiExtractor()

# Set username later
pypi_info.set_username("your_pypi_username")
Expand All @@ -78,7 +78,7 @@ pypi_info.set_username("your_pypi_username")
try:
packages_details = pypi_info.get_all_packages_details()
print(packages_details)
except PyPIPackageInfoError as e:
except PyPiExtractorError as e:
print(f"An error occurred: {e.message}")
```

Expand All @@ -87,7 +87,7 @@ except PyPIPackageInfoError as e:
You can also set the username during initialization:

```python
pypi_info = PyPIPackageInfo("your_pypi_username")
pypi_info = PyPiExtractor("your_pypi_username")
```

### Retrieving User Packages
Expand All @@ -112,33 +112,33 @@ print(package_details)

### Classes

#### `PyPIPackageInfo`
#### `PyPiExtractor`

A class to fetch and process package details for a given PyPI user.

##### `__init__(self, username: str)`

- Initializes the `PyPIPackageInfo` with a username.
- Initializes the `PyPiExtractor` with a username.
- Parameters:
- `username` (str): The PyPI username.
- Raises:
- `PyPIPackageInfoError`: If the username is not provided.
- `PyPiExtractorError`: If the username is not provided.

##### `set_username(self, username: str)`

- Sets the PyPI username.
- Parameters:
- `username` (str): The PyPI username.
- Raises:
- `PyPIPackageInfoError`: If the username is not provided.
- `PyPiExtractorError`: If the username is not provided.

##### `get_user_packages(self) -> list`

- Fetches the list of packages for the given PyPI user.
- Returns:
- `list`: A list of dictionaries containing package names and summaries.
- Raises:
- `PyPIPackageInfoError`: If there is an error fetching or parsing the user profile.
- `PyPiExtractorError`: If there is an error fetching or parsing the user profile.

##### `get_package_details(self, package_name: str) -> dict`

Expand All @@ -148,19 +148,19 @@ A class to fetch and process package details for a given PyPI user.
- Returns:
- `dict`: A dictionary containing detailed information about the package.
- Raises:
- `PyPIPackageInfoError`: If there is an error fetching or parsing the package details.
- `PyPiExtractorError`: If there is an error fetching or parsing the package details.

##### `get_all_packages_details(self) -> list`

- Fetches detailed information for all packages of the given PyPI user.
- Returns:
- `list`: A list of dictionaries containing detailed information about each package.
- Raises:
- `PyPIPackageInfoError`: If there is an error fetching or processing the package details.
- `PyPiExtractorError`: If there is an error fetching or processing the package details.

#### `PyPIPackageInfoError`
#### `PyPiExtractorError`

Custom exception class for `PyPIPackageInfo` errors.
Custom exception class for `PyPiExtractor` errors.

<br />
<p align="right"><a href="https://wolfsoftware.com/"><img src="https://img.shields.io/badge/Created%20by%20Wolf%20on%20behalf%20of%20Wolf%20Software-blue?style=for-the-badge" /></a></p>
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

setup(
name='wolfsoftware.pypi-extractor',
version='0.1.0',
version='0.1.1',
author='Wolf Software',
author_email='[email protected]',
description='Extract package information for a given user in PyPi.',
Expand Down
36 changes: 18 additions & 18 deletions tests/test_pypi_extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import pytest

from wolfsoftware.pypi_extractor import PyPIPackageInfo, PyPIPackageInfoError # pylint: disable=unused-import
from wolfsoftware.pypi_extractor import PyPiExtractor, PyPiExtractorError # pylint: disable=unused-import, no-name-in-module
from .testconf import ( # noqa: F401 pylint: disable=unused-import
mock_get_user_packages_success,
mock_get_user_packages_error,
Expand Down Expand Up @@ -45,23 +45,23 @@ def test_init_with_empty_username() -> None:
does not raise an error, and that attempting to fetch packages without setting a username
raises a PyPIPackageInfoError.
"""
pypi_info = PyPIPackageInfo()
pypi_info = PyPiExtractor()

with pytest.raises(PyPIPackageInfoError, match="Username must be set before fetching packages"):
with pytest.raises(PyPiExtractorError, match="Username must be set before fetching packages"):
pypi_info.get_user_packages()

with pytest.raises(PyPIPackageInfoError, match="Username must be set before fetching package details"):
with pytest.raises(PyPiExtractorError, match="Username must be set before fetching package details"):
pypi_info.get_all_packages_details()


def test_set_username() -> None:
"""
Test setting the username after initialization.
This test verifies that the username can be set after initializing the PyPIPackageInfo class,
This test verifies that the username can be set after initializing the PyPiExtractor class,
and that it functions correctly with the set username.
"""
pypi_info = PyPIPackageInfo()
pypi_info = PyPiExtractor()
pypi_info.set_username("testuser")
assert pypi_info.username == "testuser" # nosec: B101

Expand All @@ -70,11 +70,11 @@ def test_set_username_with_invalid_value() -> None:
"""
Test setting the username with an invalid value.
This test verifies that setting the username to an empty string raises a PyPIPackageInfoError.
This test verifies that setting the username to an empty string raises a PyPiExtractorError.
"""
pypi_info = PyPIPackageInfo()
pypi_info = PyPiExtractor()

with pytest.raises(PyPIPackageInfoError, match="Username must be provided"):
with pytest.raises(PyPiExtractorError, match="Username must be provided"):
pypi_info.set_username("")


Expand All @@ -86,7 +86,7 @@ def test_get_user_packages_success(mock_get_user_packages_success) -> None: # n
to return a successful response and verifies that the get_user_packages method returns
the expected list of packages.
"""
pypi_info = PyPIPackageInfo("testuser")
pypi_info = PyPiExtractor("testuser")
packages: List = pypi_info.get_user_packages()

assert len(packages) == 2 # nosec: B101
Expand All @@ -101,11 +101,11 @@ def test_get_user_packages_error(mock_get_user_packages_error) -> None: # noqa:
Test get_user_packages method when there is an error.
This test uses the mock_get_user_packages_error fixture to mock requests.get method
to raise an exception and verifies that the get_user_packages method raises a PyPIPackageInfoError.
to raise an exception and verifies that the get_user_packages method raises a PyPiExtractorError.
"""
pypi_info = PyPIPackageInfo("testuser")
pypi_info = PyPiExtractor("testuser")

with pytest.raises(PyPIPackageInfoError, match="Error fetching user profile: Request error"):
with pytest.raises(PyPiExtractorError, match="Error fetching user profile: Request error"):
pypi_info.get_user_packages()


Expand All @@ -117,7 +117,7 @@ def test_get_package_details_success(mock_get_package_details_success) -> None:
to return a successful response and verifies that the get_package_details method returns
the expected package details.
"""
pypi_info = PyPIPackageInfo("testuser")
pypi_info = PyPiExtractor("testuser")
details: Dict[str, Any] = pypi_info.get_package_details("Package1")

assert details['name'] == "Package1" # nosec: B101
Expand All @@ -141,11 +141,11 @@ def test_get_package_details_error(mock_get_package_details_error) -> None: # n
Test get_package_details method when there is an error.
This test uses the mock_get_package_details_error fixture to mock requests.get method
to raise an exception and verifies that the get_package_details method raises a PyPIPackageInfoError.
to raise an exception and verifies that the get_package_details method raises a PyPiExtractorError.
"""
pypi_info = PyPIPackageInfo("testuser")
pypi_info = PyPiExtractor("testuser")

with pytest.raises(PyPIPackageInfoError, match="Error fetching package details: Request error"):
with pytest.raises(PyPiExtractorError, match="Error fetching package details: Request error"):
pypi_info.get_package_details("Package1")


Expand All @@ -157,7 +157,7 @@ def test_get_all_packages_details_success(mock_get_all_packages_details_success)
to return a successful response for both user packages and package details, and verifies that
the get_all_packages_details method returns the expected list of detailed package information.
"""
pypi_info = PyPIPackageInfo("testuser")
pypi_info = PyPiExtractor("testuser")
details: List = pypi_info.get_all_packages_details()

assert len(details) == 2 # nosec: B101
Expand Down
8 changes: 4 additions & 4 deletions wolfsoftware/pypi_extractor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@

import importlib.metadata

from .exceptions import PyPIPackageInfoError
from .pypi import PyPIPackageInfo
from .exceptions import PyPiExtractorError
from .pypi import PyPiExtractor

try:
__version__: str = importlib.metadata.version('pypi_extractor')
except importlib.metadata.PackageNotFoundError:
__version__ = 'unknown'

__all__: list[str] = [
'PyPIPackageInfoError',
'PyPIPackageInfo'
'PyPiExtractorError',
'PyPiExtractor'
]
6 changes: 3 additions & 3 deletions wolfsoftware/pypi_extractor/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""
This module defines custom exceptions for the PyPI package info retriever.
This module defines custom exceptions for the PyPI Extractor package.
Classes:
- PyPIPackageInfoError: A custom exception class for errors in the PyPIPackageInfo class.
- PyPiExtractorError: A custom exception class for errors in the PyPiExtractor class.
"""


class PyPIPackageInfoError(Exception):
class PyPiExtractorError(Exception):
"""
Custom exception class for PyPIPackageInfo errors.
Expand Down
32 changes: 16 additions & 16 deletions wolfsoftware/pypi_extractor/pypi.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
"""
This module defines the PyPIPackageInfo class for fetching and processing package details from PyPI.
This module defines the PyPiExtractor class for fetching and processing package details from PyPI.
Classes:
- PyPIPackageInfo: A class to fetch and process package details for a given PyPI user.
- PyPiExtractor: A class to fetch and process package details for a given PyPI user.
"""
from typing import Any, Dict, List, Optional

import json
import requests
from bs4 import BeautifulSoup

from .exceptions import PyPIPackageInfoError
from .exceptions import PyPiExtractorError


class PyPIPackageInfo:
class PyPiExtractor:
"""
A class to fetch and process package details for a given PyPI user.
Expand Down Expand Up @@ -41,7 +41,7 @@ def set_username(self, username: str) -> None:
PyPIPackageInfoError: If the username is not provided.
"""
if not username:
raise PyPIPackageInfoError("Username must be provided")
raise PyPiExtractorError("Username must be provided")
self.username = username

def get_user_packages(self) -> List[Dict[str, str]]:
Expand All @@ -55,14 +55,14 @@ def get_user_packages(self) -> List[Dict[str, str]]:
PyPIPackageInfoError: If the username is not set or if there is an error fetching or parsing the user profile.
"""
if not self.username:
raise PyPIPackageInfoError("Username must be set before fetching packages")
raise PyPiExtractorError("Username must be set before fetching packages")

profile_url: str = "https://pypi.org/user/" + self.username + "/"
try:
response: requests.Response = requests.get(profile_url, timeout=10)
response.raise_for_status()
except requests.RequestException as e:
raise PyPIPackageInfoError(f"Error fetching user profile: {e}") from e
raise PyPiExtractorError(f"Error fetching user profile: {e}") from e

soup = BeautifulSoup(response.text, 'html.parser')
packages: List[Dict[str, str]] = []
Expand All @@ -72,7 +72,7 @@ def get_user_packages(self) -> List[Dict[str, str]]:
summary: str = project.find('p', class_='package-snippet__description').text.strip()
packages.append({'name': package_name, 'summary': summary})
except AttributeError as e:
raise PyPIPackageInfoError(f"Error parsing package details: {e}") from e
raise PyPiExtractorError(f"Error parsing package details: {e}") from e

return packages

Expand All @@ -94,12 +94,12 @@ def get_package_details(self, package_name: str) -> Dict[str, Any]:
response: requests.Response = requests.get(url, timeout=10)
response.raise_for_status()
except requests.RequestException as e:
raise PyPIPackageInfoError(f"Error fetching package details: {e}") from e
raise PyPiExtractorError(f"Error fetching package details: {e}") from e

try:
package_data: Any = response.json()
except json.JSONDecodeError as e:
raise PyPIPackageInfoError(f"Error decoding JSON response: {e}") from e
raise PyPiExtractorError(f"Error decoding JSON response: {e}") from e

info: Any = package_data.get('info', {})
current_version: str = info.get('version')
Expand Down Expand Up @@ -149,21 +149,21 @@ def get_all_packages_details(self) -> List[Dict[str, Any]]:
PyPIPackageInfoError: If there is an error fetching or processing the package details.
"""
if not self.username:
raise PyPIPackageInfoError("Username must be set before fetching package details")
raise PyPiExtractorError("Username must be set before fetching package details")

try:
packages: List[Dict[str, str]] = self.get_user_packages()
except PyPIPackageInfoError as e:
raise PyPIPackageInfoError(f"Failed to get user packages: {e}") from e
except PyPiExtractorError as e:
raise PyPiExtractorError(f"Failed to get user packages: {e}") from e

if not packages:
raise PyPIPackageInfoError(f"No packages found for user/organization '{self.username}'")
raise PyPiExtractorError(f"No packages found for user/organization '{self.username}'")

detailed_packages: List[Dict[str, Any]] = []
for package in packages:
try:
details: Dict[str, Any] = self.get_package_details(package['name'])
detailed_packages.append(details)
except PyPIPackageInfoError as e:
raise PyPIPackageInfoError(f"Failed to get details for package '{package['name']}': {e}") from e
except PyPiExtractorError as e:
raise PyPiExtractorError(f"Failed to get details for package '{package['name']}': {e}") from e
return detailed_packages
Loading