From c2b9e7463f62d88bab3237439f81b5255e97c611 Mon Sep 17 00:00:00 2001 From: Lin Luo <15869300264@163.com> Date: Tue, 19 Nov 2019 18:12:52 +0800 Subject: [PATCH 01/10] add cycle time --- pyapollo/apollo_client.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pyapollo/apollo_client.py b/pyapollo/apollo_client.py index e8acd20..d770a7b 100644 --- a/pyapollo/apollo_client.py +++ b/pyapollo/apollo_client.py @@ -9,7 +9,8 @@ class ApolloClient(object): - def __init__(self, app_id, cluster='default', config_server_url='http://localhost:8080', timeout=35, ip=None): + def __init__(self, app_id, cluster='default', config_server_url='http://localhost:8080', timeout=35, ip=None, + cycle_time=300): self.config_server_url = config_server_url self.appId = app_id self.cluster = cluster @@ -20,6 +21,7 @@ def __init__(self, app_id, cluster='default', config_server_url='http://localhos self._stopping = False self._cache = {} self._notification_map = {'application': -1} + self._cycle_time = cycle_time def init_ip(self, ip): if ip: @@ -80,7 +82,8 @@ def stop(self): logging.getLogger(__name__).info("Stopping listener...") def _cached_http_get(self, key, default_val, namespace='application'): - url = '{}/configfiles/json/{}/{}/{}?ip={}'.format(self.config_server_url, self.appId, self.cluster, namespace, self.ip) + url = '{}/configfiles/json/{}/{}/{}?ip={}'.format(self.config_server_url, self.appId, self.cluster, namespace, + self.ip) r = requests.get(url) if r.ok: data = r.json() @@ -147,6 +150,7 @@ def _listener(self): logging.getLogger(__name__).info('Entering listener loop...') while not self._stopping: self._long_poll() + time.sleep(self._cycle_time) logging.getLogger(__name__).info("Listener stopped!") self.stopped = True From d80eeb5232bfcc7b7a5ce4b7b83fad9e69719222 Mon Sep 17 00:00:00 2001 From: Lin Luo <15869300264@163.com> Date: Tue, 19 Nov 2019 18:19:27 +0800 Subject: [PATCH 02/10] add exception handler --- pyapollo/apollo_client.py | 51 +++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/pyapollo/apollo_client.py b/pyapollo/apollo_client.py index d770a7b..4af298d 100644 --- a/pyapollo/apollo_client.py +++ b/pyapollo/apollo_client.py @@ -120,31 +120,34 @@ def _long_poll(self): 'namespaceName': key, 'notificationId': notification_id }) + try: + r = requests.get(url=url, params={ + 'appId': self.appId, + 'cluster': self.cluster, + 'notifications': json.dumps(notifications, ensure_ascii=False) + }, timeout=self.timeout) + + logging.getLogger(__name__).debug('Long polling returns %d: url=%s', r.status_code, r.request.url) + + if r.status_code == 304: + # no change, loop + logging.getLogger(__name__).debug('No change, loop...') + return + + if r.status_code == 200: + data = r.json() + for entry in data: + ns = entry['namespaceName'] + nid = entry['notificationId'] + logging.getLogger(__name__).info("%s has changes: notificationId=%d", ns, nid) + self._uncached_http_get(ns) + self._notification_map[ns] = nid + else: + logging.getLogger(__name__).warn('Sleep...') + time.sleep(self.timeout) - r = requests.get(url=url, params={ - 'appId': self.appId, - 'cluster': self.cluster, - 'notifications': json.dumps(notifications, ensure_ascii=False) - }, timeout=self.timeout) - - logging.getLogger(__name__).debug('Long polling returns %d: url=%s', r.status_code, r.request.url) - - if r.status_code == 304: - # no change, loop - logging.getLogger(__name__).debug('No change, loop...') - return - - if r.status_code == 200: - data = r.json() - for entry in data: - ns = entry['namespaceName'] - nid = entry['notificationId'] - logging.getLogger(__name__).info("%s has changes: notificationId=%d", ns, nid) - self._uncached_http_get(ns) - self._notification_map[ns] = nid - else: - logging.getLogger(__name__).warn('Sleep...') - time.sleep(self.timeout) + except requests.exceptions.ReadTimeout as e: + logging.getLogger(__name__).warning(str(e)) def _listener(self): logging.getLogger(__name__).info('Entering listener loop...') From 69ffc45415b0fe3e21398a8b663e6484b697f3c9 Mon Sep 17 00:00:00 2001 From: Lin Luo <15869300264@163.com> Date: Wed, 20 Nov 2019 11:26:08 +0800 Subject: [PATCH 03/10] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E7=BC=93=E5=AD=98=20=E6=9C=8D=E5=8A=A1=E5=99=A8=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E5=A4=84=E7=90=86=EF=BC=9A=20=E5=BD=93=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=99=A8=E6=97=A0=E6=B3=95=E5=93=8D=E5=BA=94=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=85=88=E8=AF=BB=E5=8F=96=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E4=B8=AD=E7=9A=84=E9=85=8D=E7=BD=AE=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyapollo/apollo_client.py | 126 ++++++++++++++++++++++++++++++++------ 1 file changed, 106 insertions(+), 20 deletions(-) diff --git a/pyapollo/apollo_client.py b/pyapollo/apollo_client.py index 4af298d..43a5d39 100644 --- a/pyapollo/apollo_client.py +++ b/pyapollo/apollo_client.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- +import hashlib import json import logging +import os import sys import threading import time @@ -10,7 +12,7 @@ class ApolloClient(object): def __init__(self, app_id, cluster='default', config_server_url='http://localhost:8080', timeout=35, ip=None, - cycle_time=300): + cycle_time=300, cache_file_path=None): self.config_server_url = config_server_url self.appId = app_id self.cluster = cluster @@ -22,6 +24,12 @@ def __init__(self, app_id, cluster='default', config_server_url='http://localhos self._cache = {} self._notification_map = {'application': -1} self._cycle_time = cycle_time + self._hash = dict() + if cache_file_path is None: + self._cache_file_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'config') + else: + self._cache_file_path = cache_file_path + self._path_checker() def init_ip(self, ip): if ip: @@ -84,33 +92,92 @@ def stop(self): def _cached_http_get(self, key, default_val, namespace='application'): url = '{}/configfiles/json/{}/{}/{}?ip={}'.format(self.config_server_url, self.appId, self.cluster, namespace, self.ip) - r = requests.get(url) - if r.ok: - data = r.json() - self._cache[namespace] = data - logging.getLogger(__name__).info('Updated local cache for namespace %s', namespace) - else: - data = self._cache[namespace] - - if key in data: - return data[key] - else: - return default_val + data = dict() + try: + r = requests.get(url) + if r.ok: + data = r.json() + self._cache[namespace] = data + logging.getLogger(__name__).info('Updated local cache for namespace %s', namespace) + self._update_local_cache(data, namespace) + else: + if self._cache[namespace] is None or len(self._cache[namespace]) == 0: + logging.getLogger(__name__).info('cached http get configuration from local cache file') + data = self._get_local_cache(namespace) + else: + data = self._cache[namespace] + except BaseException as e: + logging.getLogger(__name__).warning(str(e)) + data = self._get_local_cache(namespace) + finally: + if key in data: + return data[key] + else: + return default_val def _uncached_http_get(self, namespace='application'): url = '{}/configs/{}/{}/{}?ip={}'.format(self.config_server_url, self.appId, self.cluster, namespace, self.ip) - r = requests.get(url) - if r.status_code == 200: - data = r.json() - self._cache[namespace] = data['configurations'] - logging.getLogger(__name__).info('Updated local cache for namespace %s release key %s: %s', + try: + r = requests.get(url) + if r.status_code == 200: + data = r.json() + self._cache[namespace] = data['configurations'] + logging.getLogger(__name__).info('Updated local cache for namespace %s release key %s: %s', namespace, data['releaseKey'], repr(self._cache[namespace])) + self._update_local_cache(data, namespace) + else: + data = self._get_local_cache(namespace) + logging.getLogger(__name__).info('uncached http get configuration from local cache file') + self._cache[namespace] = data['configurations'] + except BaseException as e: + logging.getLogger(__name__).warning(str(e)) + data = self._get_local_cache(namespace) + self._cache[namespace] = data['configurations'] def _signal_handler(self, signal, frame): logging.getLogger(__name__).info('You pressed Ctrl+C!') self._stopping = True + def _path_checker(self): + """ + create configuration cache file directory if not exits + :return: + """ + if not os.path.isdir(self._cache_file_path): + os.mkdir(self._cache_file_path) + + def _update_local_cache(self, data, namespace='application'): + """ + if local cache file exits, update the content + if local cache file not exits, create a version + :param data: new configuration content + :param namespace::s + :return: + """ + new_string = json.dumps(data) + new_hash = hashlib.md5(new_string.encode('utf-8')).hexdigest() + if self._hash[namespace] == new_hash: + pass + else: + with open(os.path.join(self._cache_file_path, 'configuration_%s.txt' % namespace), 'w') as f: + f.write(new_string) + self._hash[namespace] = new_hash + + def _get_local_cache(self, namespace='application'): + """ + get configuration from local cache file + if local cache file not exits than return empty dict + :param namespace: + :return: + """ + cache_file_path = os.path.join(self._cache_file_path, 'configuration_%s.txt' % namespace) + if os.path.isfile(cache_file_path): + with open(cache_file_path, 'r') as f: + result = json.loads(f.readline()) + return result + return dict() + def _long_poll(self): url = '{}/notifications/v2'.format(self.config_server_url) notifications = [] @@ -142,12 +209,31 @@ def _long_poll(self): logging.getLogger(__name__).info("%s has changes: notificationId=%d", ns, nid) self._uncached_http_get(ns) self._notification_map[ns] = nid + return else: - logging.getLogger(__name__).warn('Sleep...') + logging.getLogger(__name__).warning('Sleep...') time.sleep(self.timeout) - + return except requests.exceptions.ReadTimeout as e: logging.getLogger(__name__).warning(str(e)) + except requests.exceptions.ConnectionError as e: + logging.getLogger(__name__).warning(str(e)) + self._load_local_cache_file() + + def _load_local_cache_file(self): + """ + load all cached files from local path + is only used while apollo server is unreachable + :return: + """ + for file in os.listdir(self._cache_file_path): + file_path = os.path.join(self._cache_file_path, file) + if os.path.isfile(file_path): + namespace = file.split('.')[0].split('_')[1] + with open(file_path) as f: + self._cache[namespace] = json.loads(f.read())['configurations'] + return True + def _listener(self): logging.getLogger(__name__).info('Entering listener loop...') From 00b13b951d47a0267eed07d0c1a18dd25b2cdea2 Mon Sep 17 00:00:00 2001 From: Lin Luo <15869300264@163.com> Date: Wed, 20 Nov 2019 11:38:33 +0800 Subject: [PATCH 04/10] use get method to avoid error while namespace is not exists --- pyapollo/apollo_client.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/pyapollo/apollo_client.py b/pyapollo/apollo_client.py index 43a5d39..6b85328 100644 --- a/pyapollo/apollo_client.py +++ b/pyapollo/apollo_client.py @@ -13,6 +13,16 @@ class ApolloClient(object): def __init__(self, app_id, cluster='default', config_server_url='http://localhost:8080', timeout=35, ip=None, cycle_time=300, cache_file_path=None): + """ + + :param app_id: + :param cluster: + :param config_server_url: + :param timeout: + :param ip: + :param cycle_time: the cycle time to update configuration content from server + :param cache_file_path: local cache file store path + """ self.config_server_url = config_server_url self.appId = app_id self.cluster = cluster @@ -157,7 +167,7 @@ def _update_local_cache(self, data, namespace='application'): """ new_string = json.dumps(data) new_hash = hashlib.md5(new_string.encode('utf-8')).hexdigest() - if self._hash[namespace] == new_hash: + if self._hash.get(namespace) == new_hash: pass else: with open(os.path.join(self._cache_file_path, 'configuration_%s.txt' % namespace), 'w') as f: @@ -234,7 +244,6 @@ def _load_local_cache_file(self): self._cache[namespace] = json.loads(f.read())['configurations'] return True - def _listener(self): logging.getLogger(__name__).info('Entering listener loop...') while not self._stopping: From 2e243eca9b1c19e29d67d8fe0606a37d8864630f Mon Sep 17 00:00:00 2001 From: Lin Luo <15869300264@163.com> Date: Wed, 20 Nov 2019 14:41:28 +0800 Subject: [PATCH 05/10] update readme and --- README.md | 8 +-- pyapollo/apollo_client.py | 118 +++++++++++++++++++++++--------------- 2 files changed, 75 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 7944856..03bdaf9 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ PyApollo - Python Client for Ctrip's Apollo [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 方便Python接入配置中心框架 [Apollo](https://github.com/ctripcorp/apollo) 所开发的Python版本客户端。 -Tested with python 2.7 & 3.6 +Tested with python 3 Installation ------------ @@ -16,8 +16,6 @@ python setup.py install # Features * 实时同步配置 * 灰度配置 - -# Missing Features * 客户端容灾 # Usage @@ -35,8 +33,8 @@ client.start() ``` # Contribution - * Source Code: https://github.com/filamoon/pyapollo/ - * Issue Tracker: https://github.com/filamoon/pyapollo/issues + * Source Code: https://github.com/BruceWW/pyapollo + * Issue Tracker: https://github.com/BruceWW/pyapollo/issues # License The project is licensed under the [Apache 2 license](https://github.com/zouyx/agollo/blob/master/LICENSE). diff --git a/pyapollo/apollo_client.py b/pyapollo/apollo_client.py index 6b85328..d0e2147 100644 --- a/pyapollo/apollo_client.py +++ b/pyapollo/apollo_client.py @@ -1,17 +1,28 @@ +# !/usr/bin/env python # -*- coding: utf-8 -*- +# @Time : 2019 +# @Author : Bruce Liu +# @Email : 15869300264@163.com +# @File : apollo_client import hashlib import json import logging import os -import sys import threading import time import requests +""" +this module is modified from the project: https://github.com/filamoon/pyapollo +and had commit the merge request to the original repo +thanks for the contributors +since the contributors had stopped to commit code to the original repo, please submit issue or commit to https://github.com/BruceWW/pyapollo +""" + class ApolloClient(object): - def __init__(self, app_id, cluster='default', config_server_url='http://localhost:8080', timeout=35, ip=None, + def __init__(self, app_id, cluster='default', config_server_url='http://localhost:8080', timeout=60, ip=None, cycle_time=300, cache_file_path=None): """ @@ -19,16 +30,16 @@ def __init__(self, app_id, cluster='default', config_server_url='http://localhos :param cluster: :param config_server_url: :param timeout: - :param ip: + :param ip: the deploy ip for grey release :param cycle_time: the cycle time to update configuration content from server :param cache_file_path: local cache file store path """ self.config_server_url = config_server_url - self.appId = app_id + self.app_id = app_id self.cluster = cluster self.timeout = timeout self.stopped = False - self.init_ip(ip) + self.ip = self.init_ip(ip) self._stopping = False self._cache = {} @@ -41,10 +52,14 @@ def __init__(self, app_id, cluster='default', config_server_url='http://localhos self._cache_file_path = cache_file_path self._path_checker() - def init_ip(self, ip): - if ip: - self.ip = ip - else: + @staticmethod + def init_ip(ip): + """ + for grey release + :param ip: + :return: + """ + if ip is None: import socket try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) @@ -52,10 +67,17 @@ def init_ip(self, ip): ip = s.getsockname()[0] finally: s.close() - self.ip = ip + return ip - # Main method def get_value(self, key, default_val=None, namespace='application', auto_fetch_on_cache_miss=False): + """ + get the configuration value + :param key: + :param default_val: + :param namespace: + :param auto_fetch_on_cache_miss: + :return: + """ if namespace not in self._notification_map: self._notification_map[namespace] = -1 logging.getLogger(__name__).info("Add namespace '%s' to local notification map", namespace) @@ -74,16 +96,22 @@ def get_value(self, key, default_val=None, namespace='application', auto_fetch_o else: return default_val - # Start the long polling loop. Two modes are provided: - # 1: thread mode (default), create a worker thread to do the loop. Call self.stop() to quit the loop - # 2: eventlet mode (recommended), no need to call the .stop() since it is async - def start(self, use_eventlet=False, eventlet_monkey_patch=False, catch_signals=True): - # First do a blocking long poll to populate the local cache, otherwise we may get racing problems + def start(self, use_event_let=False, event_let_monkey_patch=False, catch_signals=True): + """ + Start the long polling loop. Two modes are provided: + 1: thread mode (default), create a worker thread to do the loop. Call self.stop() to quit the loop + 2: event_let mode (recommended), no need to call the .stop() since it is async + First do a blocking long poll to populate the local cache, otherwise we may get racing problems + :param use_event_let: + :param event_let_monkey_patch: + :param catch_signals: + :return: + """ if len(self._cache) == 0: self._long_poll() - if use_eventlet: + if use_event_let: import eventlet - if eventlet_monkey_patch: + if event_let_monkey_patch: eventlet.monkey_patch() eventlet.spawn(self._listener) else: @@ -96,11 +124,22 @@ def start(self, use_eventlet=False, eventlet_monkey_patch=False, catch_signals=T t.start() def stop(self): + """ + stop the client + :return: + """ self._stopping = True logging.getLogger(__name__).info("Stopping listener...") def _cached_http_get(self, key, default_val, namespace='application'): - url = '{}/configfiles/json/{}/{}/{}?ip={}'.format(self.config_server_url, self.appId, self.cluster, namespace, + """ + get the configuration content from server with cache + :param key: + :param default_val: + :param namespace: + :return: + """ + url = '{}/configfiles/json/{}/{}/{}?ip={}'.format(self.config_server_url, self.app_id, self.cluster, namespace, self.ip) data = dict() try: @@ -126,15 +165,20 @@ def _cached_http_get(self, key, default_val, namespace='application'): return default_val def _uncached_http_get(self, namespace='application'): - url = '{}/configs/{}/{}/{}?ip={}'.format(self.config_server_url, self.appId, self.cluster, namespace, self.ip) + """ + get thr configuration content from server without cache + :param namespace: + :return: + """ + url = '{}/configs/{}/{}/{}?ip={}'.format(self.config_server_url, self.app_id, self.cluster, namespace, self.ip) try: r = requests.get(url) if r.status_code == 200: data = r.json() self._cache[namespace] = data['configurations'] logging.getLogger(__name__).info('Updated local cache for namespace %s release key %s: %s', - namespace, data['releaseKey'], - repr(self._cache[namespace])) + namespace, data['releaseKey'], + repr(self._cache[namespace])) self._update_local_cache(data, namespace) else: data = self._get_local_cache(namespace) @@ -145,7 +189,7 @@ def _uncached_http_get(self, namespace='application'): data = self._get_local_cache(namespace) self._cache[namespace] = data['configurations'] - def _signal_handler(self, signal, frame): + def _signal_handler(self): logging.getLogger(__name__).info('You pressed Ctrl+C!') self._stopping = True @@ -199,7 +243,7 @@ def _long_poll(self): }) try: r = requests.get(url=url, params={ - 'appId': self.appId, + 'appId': self.app_id, 'cluster': self.cluster, 'notifications': json.dumps(notifications, ensure_ascii=False) }, timeout=self.timeout) @@ -245,6 +289,10 @@ def _load_local_cache_file(self): return True def _listener(self): + """ + + :return: + """ logging.getLogger(__name__).info('Entering listener loop...') while not self._stopping: self._long_poll() @@ -252,25 +300,3 @@ def _listener(self): logging.getLogger(__name__).info("Listener stopped!") self.stopped = True - - -if __name__ == '__main__': - root = logging.getLogger() - root.setLevel(logging.DEBUG) - - ch = logging.StreamHandler(sys.stdout) - ch.setLevel(logging.INFO) - formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') - ch.setFormatter(formatter) - root.addHandler(ch) - - client = ApolloClient('pycrawler') - client.start() - if sys.version_info[0] < 3: - v = raw_input('Press any key to quit...') - else: - v = input('Press any key to quit...') - - client.stop() - while not client.stopped: - pass From a80331cb0bd8174404ca3ab6ec45fdc25fda11d1 Mon Sep 17 00:00:00 2001 From: Lin Luo <15869300264@163.com> Date: Wed, 20 Nov 2019 14:50:03 +0800 Subject: [PATCH 06/10] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E4=BB=A5=E5=8F=8A=E5=AE=B9=E7=81=BE=E5=A4=87?= =?UTF-8?q?=E4=BB=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyapollo/apollo_client.py | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/pyapollo/apollo_client.py b/pyapollo/apollo_client.py index d0e2147..f531ddf 100644 --- a/pyapollo/apollo_client.py +++ b/pyapollo/apollo_client.py @@ -1,25 +1,15 @@ # !/usr/bin/env python # -*- coding: utf-8 -*- -# @Time : 2019 -# @Author : Bruce Liu -# @Email : 15869300264@163.com -# @File : apollo_client import hashlib import json import logging import os +import sys import threading import time import requests -""" -this module is modified from the project: https://github.com/filamoon/pyapollo -and had commit the merge request to the original repo -thanks for the contributors -since the contributors had stopped to commit code to the original repo, please submit issue or commit to https://github.com/BruceWW/pyapollo -""" - class ApolloClient(object): def __init__(self, app_id, cluster='default', config_server_url='http://localhost:8080', timeout=60, ip=None, @@ -290,7 +280,7 @@ def _load_local_cache_file(self): def _listener(self): """ - + :return: """ logging.getLogger(__name__).info('Entering listener loop...') @@ -300,3 +290,25 @@ def _listener(self): logging.getLogger(__name__).info("Listener stopped!") self.stopped = True + + +if __name__ == '__main__': + root = logging.getLogger() + root.setLevel(logging.DEBUG) + + ch = logging.StreamHandler(sys.stdout) + ch.setLevel(logging.INFO) + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + ch.setFormatter(formatter) + root.addHandler(ch) + + client = ApolloClient('pycrawler') + client.start() + if sys.version_info[0] < 3: + v = raw_input('Press any key to quit...') + else: + v = input('Press any key to quit...') + + client.stop() + while not client.stopped: + pass From b788955334b46d23db2292a086630c68cfc251b6 Mon Sep 17 00:00:00 2001 From: Lin Luo <15869300264@163.com> Date: Wed, 20 Nov 2019 14:51:43 +0800 Subject: [PATCH 07/10] recovery readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 03bdaf9..546e720 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,8 @@ client.start() ``` # Contribution - * Source Code: https://github.com/BruceWW/pyapollo - * Issue Tracker: https://github.com/BruceWW/pyapollo/issues + * Source Code: https://github.com/filamoon/pyapollo + * Issue Tracker: https://github.com/filamonn/pyapollo/issues # License The project is licensed under the [Apache 2 license](https://github.com/zouyx/agollo/blob/master/LICENSE). From eb254607d668b8360bd79bb270c58c170f064649 Mon Sep 17 00:00:00 2001 From: Lin Luo <15869300264@163.com> Date: Wed, 20 Nov 2019 15:19:53 +0800 Subject: [PATCH 08/10] update setup file and readme --- README.md | 2 +- pyapollo/__init__.py | 6 +++--- setup.py | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 546e720..78c6c8a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Installation ------------ ``` shell -python setup.py install +pip install apollo-client ``` # Features diff --git a/pyapollo/__init__.py b/pyapollo/__init__.py index 34eb45e..02623af 100644 --- a/pyapollo/__init__.py +++ b/pyapollo/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from .apollo_client import ApolloClient -__version__ = "0.0.1.dev1" -__author__ = 'filamoon' -__email__ = 'filamoon@gmail.com' +__version__ = "0.8" +__author__ = 'Bruce.Liu' +__email__ = '15869300264@163.com' diff --git a/setup.py b/setup.py index 9d257eb..ab30904 100644 --- a/setup.py +++ b/setup.py @@ -7,24 +7,24 @@ from setuptools import setup, find_packages import pyapollo -SHORT=u'pyapollo' +SHORT = u'a client for apollo' setup( - name='pyapollo', + name='apollo-client', version=pyapollo.__version__, packages=find_packages(), install_requires=[ 'requests' ], - url='https://code.aliyun.com/cashbusrisk/pyapollo', + url='', author=pyapollo.__author__, - author_email='filamoon@gmail.com', + author_email=pyapollo.__email__, classifiers=[ 'Programming Language :: Python', 'Programming Language :: Python :: 2.7', ], include_package_data=True, - package_data={'': ['*.py','*.pyc']}, + package_data={'': ['*.py', '*.pyc']}, zip_safe=False, platforms='any', From f25ffdf7ef7098bb414cfca0b11078da90e1cc91 Mon Sep 17 00:00:00 2001 From: BruceWW <550487182@qq.com> Date: Wed, 20 Nov 2019 15:26:39 +0800 Subject: [PATCH 09/10] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 78c6c8a..8e77737 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,8 @@ client.start() ``` # Contribution - * Source Code: https://github.com/filamoon/pyapollo - * Issue Tracker: https://github.com/filamonn/pyapollo/issues + * Source Code: https://github.com/BruceWW/pyapollo + * Issue Tracker: https://github.com/BruceWW/pyapollo/issues # License The project is licensed under the [Apache 2 license](https://github.com/zouyx/agollo/blob/master/LICENSE). From 086f334040036552558533e6d29177cc5d1777c5 Mon Sep 17 00:00:00 2001 From: BruceWW <550487182@qq.com> Date: Wed, 20 Nov 2019 15:27:57 +0800 Subject: [PATCH 10/10] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8e77737..cde18c6 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ PyApollo - Python Client for Ctrip's Apollo 方便Python接入配置中心框架 [Apollo](https://github.com/ctripcorp/apollo) 所开发的Python版本客户端。 Tested with python 3 +基于https://github.com/filamoon/pyapollo修改 + Installation ------------