"""
Publication Module
"""
from functools import lru_cache
from datetime import datetime
from medium_api._user import User
class Newsletter:
"""Newsletter Class
With `Newsletter` object, you can use the following properties and methods:
- newsletter.id
- newsletter.info
- newsletter.save_info()
Note:
`Newsletter` class is NOT intended to be used directly by importing.
See :obj:`medium_api.medium.Medium.publication.newsletter`.
"""
def __init__(self, publication_id, get_resp, fetch_articles, fetch_users, save_info=False):
self.publication_id = publication_id
self.__get_resp = get_resp
self.__fetch_articles = fetch_articles
self.__fetch_users = fetch_users
self.__info = None
if save_info:
self.save_info()
@property
def info(self):
"""To get the newsletter related information
Returns:
dict: A dictionary object containing `id, name, slug, subscribers,
description, image_url, etc ...`
"""
if self.__info is None:
resp, _ = self.__get_resp(f'/publication/{self.publication_id}/newsletter')
self.__info = dict(resp)
return self.__info
def save_info(self):
"""Saves the information related to the publication
Note:
Only after running ``newsletter.save_info()`` you can use the following
variables:
- ``newsletter.name``
- ``newsletter.description``
- ``newsletter.id``
- ``newsletter.subscribers``
- ``newsletter.image_url``
- ``newsletter.slug``
- ``newsletter.creator``
"""
newsletter = self.info
self.id = newsletter['id']
self.name = newsletter['name']
self.subscribers = newsletter['subscribers']
self.slug = newsletter['slug']
self.description = newsletter['description']
self.image_url = newsletter['image']
self.creator = User(user_id=newsletter['creator_id'],
get_resp=self.__get_resp,
fetch_articles=self.__fetch_articles,
fetch_users=self.__fetch_users
)
[docs]class Publication:
"""Publication Class
With `Publication` object, you can use the following properties and methods:
- publication._id
- publication.info
- publication.articles
- publication.save_info()
- publication.fetch_articles()
Note:
`Publication` class is NOT intended to be used directly by importing.
See :obj:`medium_api.medium.Medium.publication`.
"""
def __init__(self, publication_id, get_resp, fetch_articles, fetch_users, save_info=False):
self.publication_id = str(publication_id)
self.__get_resp = get_resp
self.__fetch_articles = fetch_articles
self.__fetch_users = fetch_users
self.name = None
self.description = None
self.url = None
self.tagline = None
self.followers = None
self.slug = None
self.tags = None
self.creator = None
self.editors = None
self.domain = None
self.twitter_username = None
self.instagram_username = None
self.facebook_pagename = None
self.newsletter = Newsletter(publication_id=publication_id,
get_resp = self.__get_resp,
fetch_articles = self.__fetch_articles,
fetch_users = self.__fetch_users,
save_info=False)
self.__info = None
#self.__article_ids = None
self.__articles = None
if save_info:
self.save_info()
@property
def _id(self):
"""To get the publication_id
Returns:
str: `publication_id` of the object.
"""
return self.publication_id
@property
def info(self):
"""To get the publication related information
Returns:
dict: A dictionary object containing `name, slug, followers,
description, tagline, url, twitter_username, tags, etc ...`
"""
if self.__info is None:
resp, _ = self.__get_resp(f'/publication/{self._id}')
self.__info = dict(resp)
return self.__info
[docs] def save_info(self):
"""Saves the information related to the publication
Note:
Only after running ``publication.save_info()`` you can use the following
variables:
- ``publication.name``
- ``publication.description``
- ``publication.url``
- ``publication.tagline``
- ``publication.followers``
- ``publication.slug``
- ``publication.tags``
- ``publication.domain``
- ``publication.creator``
- ``publication.editors``
- ``publication.twitter_username``
- ``publication.instagram_username``
- ``publication.facebook_pagename``
"""
publication = self.info
self.name = publication.get('name')
self.description = publication.get('description')
self.url = publication.get('url')
self.tagline = publication.get('tagline')
self.followers = publication.get('followers')
self.slug = publication.get('slug')
self.tags = publication.get('tags')
self.domain = publication.get('domain')
self.twitter_username = publication.get('twitter_username')
self.instagram_username = publication.get('instagram_username')
self.facebook_pagename = publication.get('facebook_pagename')
self.creator = User(user_id=publication['creator'],
get_resp=self.__get_resp,
fetch_articles=self.__fetch_articles,
fetch_users=self.__fetch_users,
save_info=True
) if publication.get('creator') else None
self.editors = [User(user_id=editor_id,
get_resp=self.__get_resp,
fetch_articles=self.__fetch_articles,
fetch_users=self.__fetch_users,
save_info=True
) for editor_id in publication.get('editors') if editor_id]
if self.name is None:
print(f"[ERROR]: Could not retrieve publication for the given id ({self.publication_id}). Please check if this publication exists.")
print(f"[ERROR]: Link to unknown publication: https://medium.com/u/{self.publication_id}")
[docs] def articles_from_ids(self, article_ids):
"""A generic function to get `Article` Objects from article_ids (list).
Args:
article_ids (list[str]): List of ``article_ids`` (string)
Returns:
list[Article]: Returns a list of Article Objects.
"""
from medium_api._article import Article
return [Article(
article_id=article_id,
get_resp=self.__get_resp,
fetch_articles=self.__fetch_articles,
fetch_users = self.__fetch_users,
)
for article_id in article_ids]
[docs] @lru_cache(maxsize=16)
def get_articles_between(self, _from=None, _to=None):
"""To get publication articles within a datetime range.
Example usage:
``publication.get_articles_between(_from=datetime.now(), _to=datetime.now() - timedelta(days=15))``
Args:
_from (datetime.datetime): Starting date of the interval
_to (datetime.datetime): Ending date of the interval
Returns:
list[Article]: Returns a list of Article Objects (publication articles).
Note:
- If the ``_to`` parameter is not provided, then the function will return recent 25
articles from the given date (in ``_from`` parameter)
- If the ``_from`` parameter is not provided, then the function will take current
datetime value (``datetime.now()``)
- If both the parameters, ``_from`` and ``_to``, are not provided, then the function
will return top recent 25 articles from the current datetime.
"""
if _from is None:
_from = datetime.now()
if _from and _to:
if _to < _from:
resp,_ = self.__get_resp(f'/publication/{self._id}/articles?from={_from.isoformat()}')
articles = self.articles_from_ids(resp['publication_articles'][::-1])
next_to = datetime.strptime(resp['to'], '%Y-%m-%d %H:%M:%S')
while next_to > _to:
resp,_ = self.__get_resp(f'/publication/{self._id}/articles?from={next_to.isoformat()}')
articles += self.articles_from_ids(resp['publication_articles'][::-1])
next_to = datetime.strptime(resp['to'], '%Y-%m-%d %H:%M:%S')
self.__fetch_articles(articles)
self.__articles = [article for article in articles if (_to <= article.published_at <= _from)]
else:
print('[ERROR]: "from" date should be greater than "to" date. Try swapping both.')
return []
else:
resp,_ = self.__get_resp(f'/publication/{self._id}/articles?from={_from.isoformat()}')
self.__articles = self.articles_from_ids(resp['publication_articles'])
self.__fetch_articles(self.__articles)
return self.__articles
@property
def articles(self):
"""Returns top recent 25 articles
Typical Example Usage:
``publication.articles[0].title``
``publication.articles[1].author``
Returns:
list[Article]: Returns a list of Article Objects
"""
if self.__articles is None:
self.__articles = self.get_articles_between()
return self.__articles