Repository: InstaPy/InstaPy

Issue:
UnboundLocalError: local variable 'allfollowing' referenced before assignment
hello guys i start to use instapy 3 weeks ago, at the beginning it looks well, but now it stops after 10 or 15 minutes. i use a mac, i provided with update the chrome driver and erase the cookie but remains the same:
WARNING [ignacio.24fit]  policortez -> Less users to follow than requested.
and
UnboundLocalError: local variable 'allfollowing' referenced before assignment

[quickstart.py.zip](https://github.com/timgrossmann/InstaPy/files/1803063/quickstart.py.zip)

## Expected Behavior

## Current Behavior
INFO [ignacio.24fit]  --> Total people unfollowed : 28 
WARNING [ignacio.24fit]  policortez -> Less users to follow than requested.
ERROR [ignacio.24fit]  follow loop error sample larger than population
WARNING [ignacio.24fit]  gimnasiosevenlife -> Less users to follow than requested.
ERROR [ignacio.24fit]  follow loop error sample larger than population
WARNING [ignacio.24fit]  There are 0 people to follow
ERROR [ignacio.24fit]  following_link error list index out of range
INFO [ignacio.24fit]  Session ended - 2018-03-11 23:20:51
INFO [ignacio.24fit]  --------------------


Traceback (most recent call last):
  File "quickstart.py", line 60, in <module>
    randomize=True)
  File "/Users/marcelacortes/Downloads/InstaPy-master/instapy/instapy.py", line 1409, in follow_user_followers
    self.follow_times)
  File "/Users/marcelacortes/Downloads/InstaPy-master/instapy/unfollow_util.py", line 753, in follow_given_user_followers
    allfollowing,
UnboundLocalError: local variable 'allfollowing' referenced before assignment

# all the lists have more than 2k followers (policortez have 14k)

## Possible Solution (optional)

## InstaPy configuration




Discussion:

Resolving patch:
diff --git a/instapy/unfollow_util.py b/instapy/unfollow_util.py
--- a/instapy/unfollow_util.py
+++ b/instapy/unfollow_util.py
@@ -751,56 +751,61 @@ def get_given_user_following(browser,
     return person_list
 
 
-def follow_given_user_followers(browser,
-                                user_name,
-                                amount,
-                                dont_include,
-                                login,
-                                follow_restrict,
-                                random,
-                                delay,
-                                blacklist,
-                                logger,
-                                logfolder,
-                                follow_times):
-
-    browser.get('https://www.instagram.com/' + user_name)
-    # update server calls
+def follow_given_user_followers(browser, user_name, amount, dont_include, login, follow_restrict,
+                                random, delay, blacklist, logger, logfolder, follow_times):
+    """
+    For the given username, follow their followers.
+
+    :param browser: webdriver instance
+    :param user_name: given username of account to follow
+    :param amount: the number of followers to follow
+    :param dont_include: ignore these usernames
+    :param login:
+    :param follow_restrict:
+    :param random: randomly select from users' followers
+    :param delay: the seconds to delay between each follow
+    :param blacklist:
+    :param logger: the logger instance
+    :param logfolder: the logger folder
+    :param follow_times:
+    :return: list of user's followers also followed
+    """
+    browser.get('https://www.instagram.com/{}'.format(user_name))
     update_activity()
 
-    #  check how many poeple are following this user.
-    #  throw RuntimeWarning if we are 0 people following this user
+    # check how many people are following this user.
     try:
-        allfollowing = format_number(
-            browser.find_element_by_xpath("//li[2]/a/span").text)
+        user_followers_count = format_number(browser.find_element_by_xpath(
+            '//li[2]/a/span').text)
     except NoSuchElementException:
-        logger.warning('There are 0 people to follow')
-
+        # todo check if private account?
+        logger.error('Could not determine if {} has followers'.format(user_name))
+        return []
+
+    # skip early for no followers
+    if not user_followers_count:
+        logger.info('{} has no followers'.format(user_name))
+        return []
+    elif user_followers_count < amount:
+        logger.warning('{} has less followers than given amount of {}'.format(
+            user_followers_count, amount))
+
+    # locate element to user's followers
     try:
-        following_link = browser.find_elements_by_xpath(
-            '//a[@href="/' + user_name + '/followers/"]')
-        click_element(browser, following_link[0]) # following_link.send_keys("\n")
-        # update server calls
+        user_followers_link = browser.find_elements_by_xpath(
+            '//a[@href="/{}/followers/"]'.format(user_name))
+        click_element(browser, user_followers_link[0])
         update_activity()
     except BaseException as e:
         logger.error("following_link error {}".format(str(e)))
+        return []
 
-    personFollowed = follow_through_dialog(browser,
-                                           user_name,
-                                           amount,
-                                           dont_include,
-                                           login,
-                                           follow_restrict,
-                                           allfollowing,
-                                           random,
-                                           delay,
-                                           blacklist,
-                                           logger,
-                                           logfolder,
-                                           follow_times,
-                                           callbacks=[])
+    persons_followed = follow_through_dialog(browser, user_name, amount, dont_include, login,
+                                             follow_restrict, user_followers_count, random, delay,
+                                             blacklist, logger, logfolder, follow_times,
+                                             callbacks=[])
 
-    return personFollowed
+    return persons_followed
 
 
 def follow_given_user_following(browser,


Test patch:
diff --git a/tests/test_unfollow_util.py b/tests/test_unfollow_util.py
new file mode 100644
--- /dev/null
+++ b/tests/test_unfollow_util.py
@@ -0,0 +1,33 @@
+from unittest.mock import MagicMock, Mock
+
+from selenium.common.exceptions import NoSuchElementException
+
+from instapy.unfollow_util import follow_given_user_followers
+
+
+def test_follow_given_user_followers_with_missing_count():
+    """ensure follower count error returns empty"""
+    webdriver = MagicMock()
+    webdriver.find_element_by_xpath.side_effect = NoSuchElementException
+    params = [MagicMock()] * 11
+    res = follow_given_user_followers(webdriver, *params)
+    assert len(res) == 0
+
+
+def test_follow_given_user_followers_with_no_followers():
+    """ensure follower count is not zero"""
+    webdriver = MagicMock()
+    webdriver.find_element_by_xpath.return_value = Mock(text='0')
+    params = [MagicMock()] * 11
+    res = follow_given_user_followers(webdriver, *params)
+    assert len(res) == 0
+
+
+def test_follow_given_user_followers_with_missing_link():
+    """ensure follower link error returns empty"""
+    webdriver = MagicMock()
+    webdriver.find_element_by_xpath.return_value = Mock(text='123')
+    webdriver.find_elements_by_xpath.side_effect = BaseException
+    params = [MagicMock()] * 11
+    res = follow_given_user_followers(webdriver, *params)
+    assert len(res) == 0