Repository: stravalib/stravalib

Issue:
unable to upload_activity if its bytes type
When calling `client.upload_activity` and `activity_file` type is `bytes`, 
I get this error 
`Invalid type specified for activity_file: bytes`

Comments:

Patch:
diff --git a/changelog.md b/changelog.md
index 9350dcf..1871743 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,6 +1,7 @@
 # Change Log
 
 ## Unreleased
+* Add: Support uploading `activity_file` object with type `bytes` (@gitexel, #308)
 
 ## v1.1.0
 
diff --git a/stravalib/client.py b/stravalib/client.py
index e2ac772..fa23a81 100644
--- a/stravalib/client.py
+++ b/stravalib/client.py
@@ -694,7 +694,7 @@ class Client(object):
         https://developers.strava.com/docs/reference/#api-Uploads-createUpload
 
         :param activity_file: The file object to upload or file contents.
-        :type activity_file: file or str
+        :type activity_file: TextIOWrapper, str or bytes
 
         :param data_type: File format for upload. Possible values: fit, fit.gz, tcx, tcx.gz, gpx, gpx.gz
         :type data_type: str
@@ -734,7 +734,7 @@ class Client(object):
         if not hasattr(activity_file, 'read'):
             if isinstance(activity_file, str):
                 activity_file = BytesIO(activity_file.encode('utf-8'))
-            elif isinstance(activity_file, str):
+            elif isinstance(activity_file, bytes):
                 activity_file = BytesIO(activity_file)
             else:
                 raise TypeError("Invalid type specified for activity_file: {0}".format(type(activity_file)))


Test patch:
diff --git a/stravalib/tests/integration/test_client.py b/stravalib/tests/integration/test_client.py
index 30d1812..10aa27d 100644
--- a/stravalib/tests/integration/test_client.py
+++ b/stravalib/tests/integration/test_client.py
@@ -83,6 +83,7 @@ def test_update_activity(
     (
         ('file', 'tcx', {}, {'data_type': 'tcx'}, None, None),
         ('str', 'tcx', {}, {'data_type': 'tcx'}, None, None),
+        ('bytes', 'tcx', {}, {'data_type': 'tcx'}, None, None),
         ('not_supported', 'tcx', {}, {}, None, TypeError),
         ('file', 'invalid', {}, {}, None, ValueError),
         ('file', 'tcx', {'name': 'name'}, {'data_type': 'tcx', 'name': 'name'}, None, None),
@@ -135,6 +136,8 @@ def test_upload_activity(
             _call_upload(f)
         elif activity_file_type == 'str':
             _call_upload(f.read())
+        elif activity_file_type == 'bytes':
+            _call_upload(f.read().encode('utf-8'))
         else:
             _call_upload({})
 
diff --git a/stravalib/tests/unit/test_client_utils.py b/stravalib/tests/unit/test_client_utils.py
index 88a8a8a..e3e6cd4 100644
--- a/stravalib/tests/unit/test_client_utils.py
+++ b/stravalib/tests/unit/test_client_utils.py
@@ -1,5 +1,8 @@
+import os
+from unittest import mock
+
 from stravalib.client import Client
-from stravalib.tests import TestBase
+from stravalib.tests import TestBase, RESOURCES_DIR
 import datetime
 import pytz
 from urllib import parse as urlparse
@@ -54,3 +57,32 @@ class ClientAuthorizationUrlTest(TestBase):
         self.assertEqual(self.get_url_param(url, "client_id"), "1")
         self.assertEqual(self.get_url_param(url, "redirect_uri"), "www.example.com")
         self.assertEqual(self.get_url_param(url, "approval_prompt"), "auto")
+
+
+class TestClientUploadActivity(TestBase):
+    client = Client()
+
+    def test_upload_activity_file_with_different_types(self):
+        """
+        Test uploading an activity with different activity_file object types.
+
+        """
+
+        with mock.patch("stravalib.protocol.ApiV3.post", return_value={}), open(
+            os.path.join(RESOURCES_DIR, "sample.tcx")
+        ) as fp:
+            # test activity_file with type TextIOWrapper
+            uploader = self.client.upload_activity(fp, data_type="tcx")
+            self.assertTrue(uploader.is_processing)
+
+            # test activity_file with type str
+            uploader = self.client.upload_activity(
+                fp.read(), data_type="tcx", activity_type="ride"
+            )
+            self.assertTrue(uploader.is_processing)
+
+            # test activity_file with type bytes
+            uploader = self.client.upload_activity(
+                fp.read().encode("utf-8"), data_type="tcx", activity_type="ride"
+            )
+            self.assertTrue(uploader.is_processing)