browserstack-local 1.2.9__tar.gz → 1.2.11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (18) hide show
  1. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/PKG-INFO +1 -1
  2. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/browserstack/local.py +7 -1
  3. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/browserstack/local_binary.py +81 -18
  4. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/browserstack_local.egg-info/PKG-INFO +1 -1
  5. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/setup.py +1 -1
  6. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/tests/test_local.py +1 -1
  7. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/LICENSE.txt +0 -0
  8. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/MANIFEST.in +0 -0
  9. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/README +0 -0
  10. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/README.md +0 -0
  11. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/browserstack/__init__.py +0 -0
  12. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/browserstack/bserrors.py +0 -0
  13. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/browserstack_local.egg-info/SOURCES.txt +0 -0
  14. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/browserstack_local.egg-info/dependency_links.txt +0 -0
  15. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/browserstack_local.egg-info/requires.txt +0 -0
  16. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/browserstack_local.egg-info/top_level.txt +0 -0
  17. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/setup.cfg +0 -0
  18. {browserstack-local-1.2.9 → browserstack-local-1.2.11}/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: browserstack-local
3
- Version: 1.2.9
3
+ Version: 1.2.11
4
4
  Summary: Python bindings for Browserstack Local
5
5
  Home-page: https://github.com/browserstack/browserstack-local-python
6
6
  Download-URL: https://github.com/browserstack/browserstack-local-python/archive/master.zip
@@ -15,6 +15,7 @@ class Local:
15
15
  self.key = os.environ['BROWSERSTACK_ACCESS_KEY'] if 'BROWSERSTACK_ACCESS_KEY' in os.environ else key
16
16
  self.options = kwargs
17
17
  self.local_logfile_path = os.path.join(os.getcwd(), 'local.log')
18
+ LocalBinary.set_version(self.get_package_version())
18
19
 
19
20
  def __xstr(self, key, value):
20
21
  if key is None:
@@ -72,7 +73,12 @@ class Local:
72
73
  self.binary_path = self.options['binarypath']
73
74
  del self.options['binarypath']
74
75
  else:
75
- self.binary_path = LocalBinary().get_binary()
76
+ l = LocalBinary(self.key)
77
+ try:
78
+ self.binary_path = l.get_binary()
79
+ except Exception as e:
80
+ l = LocalBinary(self.key, e)
81
+ self.binary_path = l.get_binary()
76
82
 
77
83
  if 'logfile' in self.options:
78
84
  self.local_logfile_path = self.options['logfile']
@@ -1,29 +1,37 @@
1
1
  import platform, os, sys, stat, tempfile, re, subprocess
2
2
  from browserstack.bserrors import BrowserStackLocalError
3
+ import gzip
4
+ import json
3
5
 
4
6
  try:
5
- from urllib.request import urlopen
7
+ from urllib.request import urlopen, Request
6
8
  except ImportError:
7
- from urllib2 import urlopen
9
+ from urllib2 import urlopen, Request
8
10
 
9
11
  class LocalBinary:
10
- def __init__(self):
12
+ _version = None
13
+
14
+ def __init__(self, key, error_object=None):
15
+ self.key = key
16
+ self.error_object = error_object
11
17
  is_64bits = sys.maxsize > 2**32
12
18
  self.is_windows = False
13
19
  osname = platform.system()
20
+ source_url = self.fetch_source_url() + '/'
21
+
14
22
  if osname == 'Darwin':
15
- self.http_path = "https://www.browserstack.com/local-testing/downloads/binaries/BrowserStackLocal-darwin-x64"
23
+ self.http_path = source_url + "BrowserStackLocal-darwin-x64"
16
24
  elif osname == 'Linux':
17
25
  if self.is_alpine():
18
- self.http_path = "https://www.browserstack.com/local-testing/downloads/binaries/BrowserStackLocal-alpine"
26
+ self.http_path = source_url + "BrowserStackLocal-alpine"
19
27
  else:
20
28
  if is_64bits:
21
- self.http_path = "https://www.browserstack.com/local-testing/downloads/binaries/BrowserStackLocal-linux-x64"
29
+ self.http_path = source_url + "BrowserStackLocal-linux-x64"
22
30
  else:
23
- self.http_path = "https://www.browserstack.com/local-testing/downloads/binaries/BrowserStackLocal-linux-ia32"
31
+ self.http_path = source_url + "BrowserStackLocal-linux-ia32"
24
32
  else:
25
33
  self.is_windows = True
26
- self.http_path = "https://www.browserstack.com/local-testing/downloads/binaries/BrowserStackLocal.exe"
34
+ self.http_path = source_url + "BrowserStackLocal.exe"
27
35
 
28
36
  self.ordered_paths = [
29
37
  os.path.join(os.path.expanduser('~'), '.browserstack'),
@@ -32,11 +40,38 @@ class LocalBinary:
32
40
  ]
33
41
  self.path_index = 0
34
42
 
43
+ def fetch_source_url(self):
44
+ url = "https://local.browserstack.com/binary/api/v1/endpoint"
45
+ headers = {
46
+ "Content-Type": "application/json",
47
+ "Accept": "application/json"
48
+ }
49
+ data = {"auth_token": self.key}
50
+
51
+ if self.error_object is not None:
52
+ data["error_message"] = str(self.error_object)
53
+ headers["X-Local-Fallback-Cloudflare"] = "true"
54
+
55
+ req = Request(url, data=json.dumps(data).encode("utf-8"))
56
+ for key, value in headers.items():
57
+ req.add_header(key, value)
58
+
59
+ try:
60
+ with urlopen(req) as response:
61
+ resp_bytes = response.read()
62
+ resp_str = resp_bytes.decode('utf-8')
63
+ resp_json = json.loads(resp_str)
64
+ return resp_json["data"]["endpoint"]
65
+ except Exception as e:
66
+ raise BrowserStackLocalError('Error trying to fetch the source url for downloading the binary: {}'.format(e))
67
+
68
+ @staticmethod
69
+ def set_version(version):
70
+ LocalBinary._version = version
71
+
35
72
  def is_alpine(self):
36
- grepOutput = subprocess.run("grep -w NAME /etc/os-release", capture_output=True, shell=True)
37
- if grepOutput.stdout.decode('utf-8').find('Alpine') > -1:
38
- return True
39
- return False
73
+ response = subprocess.check_output(["grep", "-w", "NAME", "/etc/os-release"])
74
+ return response.decode('utf-8').find('Alpine') > -1
40
75
 
41
76
  def __make_path(self, dest_path):
42
77
  try:
@@ -54,36 +89,64 @@ class LocalBinary:
54
89
  return final_path
55
90
  else:
56
91
  self.path_index += 1
57
- raise BrowserStackLocalError('Error trying to download BrowserStack Local binary')
92
+ raise BrowserStackLocalError('Error trying to download BrowserStack Local binary, exhausted user directories to download to.')
58
93
 
59
94
  def download(self, chunk_size=8192, progress_hook=None):
60
- response = urlopen(self.http_path)
95
+ headers = {
96
+ 'User-Agent': '/'.join(('browserstack-local-python', LocalBinary._version)),
97
+ 'Accept-Encoding': 'gzip, *',
98
+ }
99
+
100
+ if sys.version_info < (3, 2):
101
+ # lack of support for gzip decoding for stream, response is expected to have a tell() method
102
+ headers.pop('Accept-Encoding', None)
103
+
104
+ response = urlopen(Request(self.http_path, headers=headers))
61
105
  try:
62
- total_size = int(response.info().getheader('Content-Length').strip())
106
+ total_size = int(response.info().get('Content-Length', '').strip() or '0')
63
107
  except:
64
- total_size = int(response.info().get_all('Content-Length')[0].strip())
108
+ total_size = int(response.info().get_all('Content-Length')[0].strip() or '0')
65
109
  bytes_so_far = 0
66
110
 
111
+ # Limits retries to the number of directories
67
112
  dest_parent_dir = self.__available_dir()
68
113
  dest_binary_name = 'BrowserStackLocal'
69
114
  if self.is_windows:
70
115
  dest_binary_name += '.exe'
71
116
 
117
+ content_encoding = response.info().get('Content-Encoding', '')
118
+ gzip_file = gzip.GzipFile(fileobj=response, mode='rb') if content_encoding.lower() == 'gzip' else None
119
+
120
+ if os.getenv('BROWSERSTACK_LOCAL_DEBUG_GZIP') and gzip_file:
121
+ print('using gzip in ' + headers['User-Agent'])
122
+
123
+ def read_chunk(chunk_size):
124
+ if gzip_file:
125
+ return gzip_file.read(chunk_size)
126
+ else:
127
+ return response.read(chunk_size)
128
+
72
129
  with open(os.path.join(dest_parent_dir, dest_binary_name), 'wb') as local_file:
73
130
  while True:
74
- chunk = response.read(chunk_size)
131
+ chunk = read_chunk(chunk_size)
75
132
  bytes_so_far += len(chunk)
76
133
 
77
134
  if not chunk:
78
135
  break
79
136
 
80
- if progress_hook:
137
+ if total_size > 0 and progress_hook:
81
138
  progress_hook(bytes_so_far, chunk_size, total_size)
82
139
 
83
140
  try:
84
141
  local_file.write(chunk)
85
142
  except:
86
143
  return self.download(chunk_size, progress_hook)
144
+
145
+ if gzip_file:
146
+ gzip_file.close()
147
+
148
+ if callable(getattr(response, 'close', None)):
149
+ response.close()
87
150
 
88
151
  final_path = os.path.join(dest_parent_dir, dest_binary_name)
89
152
  st = os.stat(final_path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: browserstack-local
3
- Version: 1.2.9
3
+ Version: 1.2.11
4
4
  Summary: Python bindings for Browserstack Local
5
5
  Home-page: https://github.com/browserstack/browserstack-local-python
6
6
  Download-URL: https://github.com/browserstack/browserstack-local-python/archive/master.zip
@@ -5,7 +5,7 @@ except ImportError:
5
5
  setup(
6
6
  name = 'browserstack-local',
7
7
  packages = ['browserstack'],
8
- version = '1.2.9',
8
+ version = '1.2.11',
9
9
  description = 'Python bindings for Browserstack Local',
10
10
  long_description=open('README.md').read(),
11
11
  long_description_content_type='text/markdown',
@@ -70,7 +70,7 @@ class TestLocal(unittest.TestCase):
70
70
  self.assertIn('-proxyHost', self.local._generate_cmd())
71
71
  self.assertIn('localhost', self.local._generate_cmd())
72
72
  self.assertIn('-proxyPort', self.local._generate_cmd())
73
- self.assertIn(2000, self.local._generate_cmd())
73
+ self.assertIn('2000', self.local._generate_cmd())
74
74
  self.assertIn('-proxyUser', self.local._generate_cmd())
75
75
  self.assertIn('hello', self.local._generate_cmd())
76
76
  self.assertIn('-proxyPass', self.local._generate_cmd())