# Buggy code
def lookup_episode(
    name=None,
    season_number=None,
    episode_number=None,
    absolute_number=None,
    tvdb_id=None,
    only_cached=False,
    session=None,
):
    """
    Look up information on an episode. Will be returned from cache if available, and looked up online and cached if not.

    Either `name` or `tvdb_id` parameter are needed to specify the series.
    Either `seasonnum` and `episodedum`, `absolutenum`, or `airdate` are required to specify episode number.
    :param unicode name: Name of series episode belongs to.
    :param int tvdb_id: TVDb ID of series episode belongs to.
    :param int season_number: Season number of episode.
    :param int episode_number: Episode number of episode.
    :param int absolute_number: Absolute number of episode.
    :param bool only_cached: If True, will not cause an online lookup. LookupError will be raised if not available
        in the cache.
    :param session: An sqlalchemy session to be used to lookup and store to cache. Commit(s) may occur when passing in
        a session. If one is not supplied it will be created, however if you need to access relationships you should
        pass one in.

    :return: Instance of :class:`TVDBEpisode` populated with series information.
    :raises: :class:`LookupError` if episode cannot be looked up.
    """
    # First make sure we have the series data
    series = lookup_series(
        name=name, tvdb_id=tvdb_id, only_cached=only_cached, session=session
    )

    if not series:
        LookupError("Series %s (%s) not found from" % (name, tvdb_id))

    ep_description = series.name
    query_params = {}
    episode = session.query(TVDBEpisode).filter(TVDBEpisode.series_id == series.id)

    if absolute_number:
        episode = episode.filter(TVDBEpisode.absolute_number == absolute_number)
        query_params["absoluteNumber"] = absolute_number
        ep_description = "%s absNo: %s" % (ep_description, absolute_number)

    if season_number:
        episode = episode.filter(TVDBEpisode.season_number == season_number)
        query_params["airedSeason"] = season_number
        ep_description = "%s s%s" % (ep_description, season_number)

    if episode_number:
        episode = episode.filter(TVDBEpisode.episode_number == episode_number)
        query_params["airedEpisode"] = episode_number
        ep_description = "%s e%s" % (ep_description, episode_number)

    episode = episode.first()

    if episode:
        if episode.expired and not only_cached:
            log.info("Data for %r has expired, refreshing from tvdb", episode)
            try:
                episode.update()
            except LookupError as e:
                log.warning(
                    "Error while updating from tvdb (%s), using cached data." % str(e)
                )
        else:
            log.debug("Using episode info for %s from cache.", ep_description)
    else:
        if only_cached:
            raise LookupError("Episode %s not found from cache" % ep_description)
        # There was no episode found in the cache, do a lookup from tvdb
        log.debug(
            "Episode %s not found in cache, looking up from tvdb.", ep_description
        )
        try:
            results = TVDBRequest().get(
                "series/%s/episodes/query" % series.id, **query_params
            )
            if results:
                # Check if this episode id is already in our db
                episode = (
                    session.query(TVDBEpisode)
                    .filter(TVDBEpisode.id == results[0]["id"])
                    .first()
                )
                if not episode:
                    episode = TVDBEpisode(id=results[0]["id"])
                if episode.expired is not False:
                    episode.update()

                series.episodes.append(episode)
                session.merge(series)
        except requests.RequestException as e:
            raise LookupError("Error looking up episode from TVDb (%s)" % e)
    if episode:
        return episode
    else:
        raise LookupError("No results found for %s" % ep_description)


# Traceback (FlushError)
2016-04-01 21:04 INFO     download      tv_shows        Downloading: Sleepy.Hollow.S03E17.720p.HDTV.x264-AVS
2016-04-01 21:04 ERROR    api_tvdb      tv_shows        Could not get update information from tvdb: 404 Client Error: Not Found for url: https://api-beta.thetvdb.com/updated/query?fromTime=1459529228
2016-04-01 21:04 ERROR    lazy_lookup   tv_shows        Unhandled error in lazy lookup plugin
2016-04-01 21:04 CRITICAL manager       tv_shows        An unexpected crash has occurred. Writing crash report to /home/pi/.flexget/crash_report.2016.04.01.210426572780.log. Please verify you are running the latest version of flexget by using "flexget -V" from CLI or by using version_checker plugin at http://flexget.com/wiki/Plugins/version_checker. You are currently using version 1.2.499
2016-04-01 21:04 ERROR    lazy_lookup   tv_shows        Unhandled error in lazy lookup plugin
2016-04-01 21:04 CRITICAL manager       tv_shows        An unexpected crash has occurred. Writing crash report to /home/pi/.flexget/crash_report.2016.04.01.210427914486.log. Please verify you are running the latest version of flexget by using "flexget -V" from CLI or by using version_checker plugin at http://flexget.com/wiki/Plugins/version_checker. You are currently using version 1.2.499
2016-04-01 21:04 INFO     transmission  tv_shows        "Sleepy.Hollow.S03E17.720p.HDTV.x264-AVS" torrent added to transmission
2016-04-01 21:04 ERROR    lazy_lookup   tv_shows        Unhandled error in lazy lookup plugin
2016-04-01 21:04 CRITICAL manager       tv_shows        An unexpected crash has occurred. Writing crash report to /home/pi/.flexget/crash_report.2016.04.01.210434515925.log. Please verify you are running the latest version of flexget by using "flexget -V" from CLI or by using version_checker plugin at http://flexget.com/wiki/Plugins/version_checker. You are currently using version 1.2.499
2016-04-01 21:04 ERROR    lazy_lookup   tv_shows        Unhandled error in lazy lookup plugin
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flexget/utils/lazy_dict.py", line 36, in __getitem__
func(self.store)
File "/usr/local/lib/python2.7/dist-packages/flexget/plugins/metainfo/thetvdb_lookup.py", line 115, in lazy_series_poster_lookup
return self.series_lookup(entry, self.series_poster_map)
File "/usr/local/lib/python2.7/dist-packages/flexget/utils/database.py", line 30, in wrapper
return func(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/flexget/utils/sqlalchemy_utils.py", line 137, in __exit__
self.commit()
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", line 801, in commit
self.transaction.commit()
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", line 392, in commit
self._prepare_impl()
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", line 372, in _prepare_impl
self.session.flush()
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", line 2019, in flush
self._flush(objects)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", line 2137, in _flush
transaction.rollback(_capture_exception=True)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/util/langhelpers.py", line 60, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", line 2101, in _flush
flush_context.execute()
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/unitofwork.py", line 373, in execute
rec.execute(self)
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/unitofwork.py", line 532, in execute
uow
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/persistence.py", line 149, in save_obj
base_mapper, states, uowtransaction
File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/persistence.py", line 301, in _organize_states_for_save
state_str(existing)))
FlushError: New instance <TVDBGenre at 0x68f50970> with identity key (<class 'flexget.plugins.api_tvdb.TVDBGenre'>, (4,)) conflicts with persistent instance <TVDBGenre at 0x68f433d0>

# Fixed code
def lookup_episode(
    name=None,
    season_number=None,
    episode_number=None,
    absolute_number=None,
    tvdb_id=None,
    only_cached=False,
    session=None,
):
    """
    Look up information on an episode. Will be returned from cache if available, and looked up online and cached if not.

    Either `name` or `tvdb_id` parameter are needed to specify the series.
    Either `seasonnum` and `episodedum`, `absolutenum`, or `airdate` are required to specify episode number.
    :param unicode name: Name of series episode belongs to.
    :param int tvdb_id: TVDb ID of series episode belongs to.
    :param int season_number: Season number of episode.
    :param int episode_number: Episode number of episode.
    :param int absolute_number: Absolute number of episode.
    :param bool only_cached: If True, will not cause an online lookup. LookupError will be raised if not available
        in the cache.
    :param session: An sqlalchemy session to be used to lookup and store to cache. Commit(s) may occur when passing in
        a session. If one is not supplied it will be created, however if you need to access relationships you should
        pass one in.

    :return: Instance of :class:`TVDBEpisode` populated with series information.
    :raises: :class:`LookupError` if episode cannot be looked up.
    """
    # First make sure we have the series data
    series = lookup_series(
        name=name, tvdb_id=tvdb_id, only_cached=only_cached, session=session
    )

    if not series:
        LookupError("Series %s (%s) not found from" % (name, tvdb_id))

    ep_description = series.name
    query_params = {}
    episode = session.query(TVDBEpisode).filter(TVDBEpisode.series_id == series.id)

    if absolute_number:
        episode = episode.filter(TVDBEpisode.absolute_number == absolute_number)
        query_params["absoluteNumber"] = absolute_number
        ep_description = "%s absNo: %s" % (ep_description, absolute_number)

    if season_number:
        episode = episode.filter(TVDBEpisode.season_number == season_number)
        query_params["airedSeason"] = season_number
        ep_description = "%s s%s" % (ep_description, season_number)

    if episode_number:
        episode = episode.filter(TVDBEpisode.episode_number == episode_number)
        query_params["airedEpisode"] = episode_number
        ep_description = "%s e%s" % (ep_description, episode_number)

    episode = episode.first()

    if episode:
        if episode.expired and not only_cached:
            log.info("Data for %r has expired, refreshing from tvdb", episode)
            try:
                updated_episode = TVDBEpisode(id=series.id)
                episode = session.merge(updated_episode)
            except LookupError as e:
                log.warning(
                    "Error while updating from tvdb (%s), using cached data." % str(e)
                )
        else:
            log.debug("Using episode info for %s from cache.", ep_description)
    else:
        if only_cached:
            raise LookupError("Episode %s not found from cache" % ep_description)
        # There was no episode found in the cache, do a lookup from tvdb
        log.debug(
            "Episode %s not found in cache, looking up from tvdb.", ep_description
        )
        try:
            results = TVDBRequest().get(
                "series/%s/episodes/query" % series.id, **query_params
            )
            if results:
                # Check if this episode id is already in our db
                episode = (
                    session.query(TVDBEpisode)
                    .filter(TVDBEpisode.id == results[0]["id"])
                    .first()
                )
                if not episode or (episode and episode.expired is not False):
                    episode = session.merge(TVDBEpisode(id=results[0]["id"]))

                episode.series = series
        except requests.RequestException as e:
            raise LookupError("Error looking up episode from TVDb (%s)" % e)
    if episode:
        return episode
    else:
        raise LookupError("No results found for %s" % ep_description)