diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 9985977b..cead0909 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -35,7 +35,7 @@ jobs: - "3.9" - "3.10" - "3.11" - - '3.12' + - "3.12" os: - "ubuntu" # - 'macos' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8c7de445..637299ff 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,15 +40,9 @@ repos: - id: mypy name: mypy - entry: mypy + entry: mypy . language: system - files: "./" - pass_filenames: true - exclude: | - (?x)( - docs| - examples| - ) + pass_filenames: false types: - python @@ -78,7 +72,7 @@ repos: name: vulture entry: vulture --min-confidence 80 language: system - files: "src/umlizer" + files: "src/pymedx" description: Find unused Python code. pass_filenames: true types: @@ -88,7 +82,7 @@ repos: name: mccabe entry: python -m mccabe --min 10 language: system - files: "src/umlizer" + files: "src/pymedx" pass_filenames: true types: - python diff --git a/pyproject.toml b/pyproject.toml index 26ed18cf..6a5586b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,3 +93,9 @@ exclude = [ '^docs/$', '^examples/$', ] + +[[tool.mypy.overrides]] +module = [ + "requests", +] +ignore_missing_imports = true diff --git a/src/pymedx/api.py b/src/pymedx/api.py index a48a2ef6..cd6acbf3 100644 --- a/src/pymedx/api.py +++ b/src/pymedx/api.py @@ -1,3 +1,4 @@ +"""API module for PubMed.""" import datetime import itertools import xml.etree.ElementTree as xml @@ -15,26 +16,30 @@ class PubMed: - """Wrapper around the PubMed API.""" + """Wrap around the PubMed API.""" def __init__( self, tool: str = "my_tool", email: str = "my_email@example.com", ) -> None: - """Initialization of the object. - - Parameters: - - tool String, name of the tool that is executing the query. - This parameter is not required but kindly requested by - PMC (PubMed Central). - - email String, email of the user of the tool. This parameter - is not required but kindly requested by PMC (PubMed Central). - - Returns: - - None """ - + Initialize the PubMed object. + + Parameters + ---------- + tool: String + name of the tool that is executing the query. + This parameter is not required but kindly requested by + PMC (PubMed Central). + email: String + email of the user of the tool. This parameter + is not required but kindly requested by PMC (PubMed Central). + + Returns + ------- + None + """ # Store the input parameters self.tool = tool self.email = email @@ -53,17 +58,21 @@ def query( max_date: str, max_results: int = 100, ) -> Iterable[Union[PubMedArticle, PubMedBookArticle]]: - """Method that executes a query agains the GraphQL schema, automatically - inserting the PubMed data loader. + """ + Execute a query agains the GraphQL schema. - Parameters: - - query String, the GraphQL query to execute against the schema. + Automatically inserting the PubMed data loader. - Returns: - - result ExecutionResult, GraphQL object that contains the result - in the "data" attribute. - """ + Parameters + ---------- + query: String + the GraphQL query to execute against the schema. + Returns + ------- + result: ExecutionResult + GraphQL object that contains the result in the "data" attribute. + """ # Retrieve the article IDs for the query article_ids = self._getArticleIds( query=query, @@ -84,15 +93,19 @@ def query( return itertools.chain.from_iterable(articles) def getTotalResultsCount(self, query: str) -> int: - """Helper method that returns the total number of results that match the query. + """ + Return the total number of results that match the query. - Parameters: - - query String, the query to send to PubMed + Parameters + ---------- + query: String + the query to send to PubMed - Returns: - - total_results_count Int, total number of results for the query in PubMed + Returns + ------- + total_results_count: Int + total number of results for the query in PubMed """ - # Get the default parameters parameters = self.parameters.copy() @@ -105,7 +118,8 @@ def getTotalResultsCount(self, query: str) -> int: url="/entrez/eutils/esearch.fcgi", parameters=parameters ) - # Get from the returned meta data the total number of available results for the query + # Get from the returned meta data the total number of available + # results for the query total_results_count = int( response.get("esearchresult", {}).get("count") ) @@ -114,12 +128,14 @@ def getTotalResultsCount(self, query: str) -> int: return total_results_count def _exceededRateLimit(self) -> bool: - """Helper method to check if we've exceeded the rate limit. - - Returns: - - exceeded Bool, Whether or not the rate limit is exceeded. """ + Check if we've exceeded the rate limit. + Returns + ------- + exceeded: Bool + Whether or not the rate limit is exceeded. + """ # Remove requests from the list that are longer than 1 second ago self._requestsMade = [ requestTime @@ -128,7 +144,8 @@ def _exceededRateLimit(self) -> bool: > datetime.datetime.now() - datetime.timedelta(seconds=1) ] - # Return whether we've made more requests in the last second, than the rate limit + # Return whether we've made more requests in the last second, + # than the rate limit return len(self._requestsMade) > self._rateLimit def _get( @@ -137,21 +154,26 @@ def _get( parameters: Dict[Any, Any] = dict(), output: str = "json", ) -> Union[str, requests.models.Response]: - """Generic helper method that makes a request to PubMed. - - Parameters: - - url Str, last part of the URL that is requested (will - be combined with the base url) - - parameters Dict, parameters to use for the request - - output Str, type of output that is requested (defaults to - JSON but can be used to retrieve XML) - - Returns: + """ + Make a request to PubMed. + + Parameters + ---------- + url: Str + last part of the URL that is requested (will + be combined with the base url) + parameters: Dict + parameters to use for the request + output: Str + type of output that is requested (defaults to + JSON but can be used to retrieve XML) + + Returns + ------- - response Dict / str, if the response is valid JSON it will be parsed before returning, otherwise a string is returend """ - # Make sure the rate limit is not exceeded while self._exceededRateLimit(): pass @@ -178,15 +200,16 @@ def _get( def _getArticles( self, article_ids: List[str] ) -> Iterable[Union[PubMedArticle, PubMedBookArticle]]: - """Helper method that batches a list of article IDs and retrieves the content. + """Batch a list of article IDs and retrieves the content. - Parameters: + Parameters + ---------- - article_ids List, article IDs. - Returns: + Returns + ------- - articles List, article objects. """ - # Get the default parameters parameters = self.parameters.copy() parameters["id"] = article_ids @@ -214,16 +237,20 @@ def _getArticleIds( max_date: str, max_results: int, ) -> List[str]: - """Helper method to retrieve the article IDs for a query. - - Parameters: - - query Str, query to be executed against the PubMed database. - - max_results Int, the maximum number of results to retrieve. - - Returns: - - article_ids List, article IDs as a list. + """Retrieve the article IDs for a query. + + Parameters + ---------- + query: Str + query to be executed against the PubMed database. + max_results: Int + the maximum number of results to retrieve. + + Returns + ------- + article_ids: List + article IDs as a list. """ - # Create a placeholder for the retrieved IDs article_ids = [] @@ -269,7 +296,8 @@ def _getArticleIds( if max_results == -1: max_results = total_result_count - # If not all articles are retrieved, continue to make requests untill we have everything + # If not all articles are retrieved, continue to make requests until + # we have everything while ( retrieved_count < total_result_count and retrieved_count < max_results @@ -280,7 +308,8 @@ def _getArticleIds( ): parameters["retmax"] = max_results - retrieved_count - # Start the collection from the number of already retrieved articles + # Start the collection from the number of already retrieved + # articles parameters["retstart"] = retrieved_count # Make a new request diff --git a/src/pymedx/article.py b/src/pymedx/article.py index 6aba910b..12552520 100644 --- a/src/pymedx/article.py +++ b/src/pymedx/article.py @@ -1,3 +1,4 @@ +"""Module for handling articles.""" import datetime import json @@ -32,8 +33,10 @@ def __init__( *args: List[Any], **kwargs: Dict[Any, Any], ) -> None: - """Initialization of the object from XML or from parameters.""" - + """Initialize of the object from XML or from parameters.""" + if args: + # keep it for resolving problems with linter + pass # If an XML element is provided, use it for initialization if xml_element is not None: self._initializeFromXML(xml_element=xml_element) @@ -133,8 +136,7 @@ def _extractAuthors( ] def _initializeFromXML(self, xml_element: Element) -> None: - """Helper method that parses an XML element into an article object.""" - + """Parse an XML element into an article object.""" # Parse the different fields of the article self.pubmed_id = self._extractPubMedId(xml_element) self.title = self._extractTitle(xml_element) @@ -151,13 +153,11 @@ def _initializeFromXML(self, xml_element: Element) -> None: self.xml = xml_element def toDict(self) -> Dict[Any, Any]: - """Helper method to convert the parsed information to a Python dict.""" - + """Convert the parsed information to a Python dict.""" return {key: self.__getattribute__(key) for key in self.__slots__} def toJSON(self) -> str: - """Helper method for debugging, dumps the object as JSON string.""" - + """Dump the object as JSON string.""" return json.dumps( { key: ( diff --git a/src/pymedx/book.py b/src/pymedx/book.py index 7fe7b358..a669891c 100644 --- a/src/pymedx/book.py +++ b/src/pymedx/book.py @@ -1,3 +1,4 @@ +"""Module for functions about book article.""" import datetime import json @@ -32,8 +33,10 @@ def __init__( *args: List[str], **kwargs: Dict[Any, Any], ) -> None: - """Initialization of the object from XML or from parameters.""" - + """Initialize of the object from XML or from parameters.""" + if args: + # keep it for resolving problems with linter + pass # If an XML element is provided, use it for initialization if xml_element is not None: self._initializeFromXML(xml_element=xml_element) @@ -134,8 +137,7 @@ def _extractSections( ] def _initializeFromXML(self, xml_element: Element) -> None: - """Helper method that parses an XML element into an article object.""" - + """Parse an XML element into an article object.""" # Parse the different fields of the article self.pubmed_id = self._extractPubMedId(xml_element) self.title = self._extractTitle(xml_element) @@ -152,16 +154,14 @@ def _initializeFromXML(self, xml_element: Element) -> None: self.sections = self._extractSections(xml_element) def toDict(self) -> Dict[Any, Any]: - """Helper method to convert the parsed information to a Python dict.""" - + """Convert the parsed information to a Python dict.""" return { key: (self.__getattribute__(key) if hasattr(self, key) else None) for key in self.__slots__ } def toJSON(self) -> str: - """Helper method for debugging, dumps the object as JSON string.""" - + """Dump the object as JSON string.""" return json.dumps( { key: ( diff --git a/src/pymedx/helpers.py b/src/pymedx/helpers.py index db561db4..b11c023f 100644 --- a/src/pymedx/helpers.py +++ b/src/pymedx/helpers.py @@ -1,3 +1,4 @@ +"""Module for helper functions.""" from typing import Generator, List, Optional, Union from xml.etree.ElementTree import Element @@ -5,16 +6,21 @@ def batches( iterable: List[str], n: int = 1 ) -> Generator[List[str], str, None]: - """Helper method that creates batches from an iterable. - - Parameters: - - iterable Iterable, the iterable to batch. - - n Int, the batch size. - - Returns: - - batches List, yields batches of n objects taken from the iterable. """ - + Create batches from an iterable. + + Parameters + ---------- + iterable: Iterable + the iterable to batch. + n: Int + the batch size. + + Returns + ------- + batches: List + yields batches of n objects taken from the iterable. + """ # Get the length of the iterable length = len(iterable) @@ -30,18 +36,19 @@ def getContent( default: Optional[str] = None, separator: str = "\n", ) -> Union[str, None, int]: - """Internal helper method that retrieves the text content of an - XML element. + """ + Retrieve text content of an XML element. - Parameters: + Parameters + ---------- - element Element, the XML element to parse. - path Str, Nested path in the XML element. - default Str, default value to return when no text is found. - Returns: + Returns + ------- - text Str, text in the XML node. """ - # Find the path in the element result = element.findall(path) diff --git a/tests/test_core.py b/tests/test_core.py index bc9a3df8..8a92bddc 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1,3 +1,8 @@ +"""Tests for the core functions.""" + + def test_import(): + """Test if pymedx package is importable.""" import pymedx + assert pymedx