Skip to content

Commit

Permalink
Remove pandas dependency and deprecated classes, functions (#932)
Browse files Browse the repository at this point in the history
  • Loading branch information
mgrubent authored and efeg committed Sep 6, 2019
1 parent e9b63a9 commit c9dff71
Show file tree
Hide file tree
Showing 7 changed files with 5 additions and 710 deletions.
407 changes: 0 additions & 407 deletions cruise-control-client/cruisecontrolclient/client/Display.py

This file was deleted.

34 changes: 1 addition & 33 deletions cruise-control-client/cruisecontrolclient/client/Endpoint.py
Expand Up @@ -8,13 +8,7 @@
import cruisecontrolclient.client.CCParameter as CCParameter

# To allow us to make more-precise type hints
from typing import Callable, ClassVar, Dict, List, Tuple, Union # noqa

# To help us generate the right parameter string from a dict of parameters
from urllib.parse import urlencode

# To be able to deprecate methods
import warnings
from typing import Callable, ClassVar, Dict, List, Tuple, Union


class AbstractEndpoint(metaclass=ABCMeta):
Expand Down Expand Up @@ -160,32 +154,6 @@ def get_composed_params(self) -> Dict[str, Union[bool, int, str]]:

return combined_parameter_to_value

def compose_endpoint(self) -> str:
"""
Returns a valid URL suffix of this endpoint and any parameters
that have been defined for it.
Note that the ordering of the parameters is not guaranteed.
:return: A string like:
'rebalance?dryrun=false&allow_capacity_estimation=false&concurrent_partition_movements_per_broker=5'
'state'
'stop_proposal_execution'
"""
warnings.warn("This method is deprecated as of 0.2.0, as it needlessly recreates requests functionality. "
"It may be removed entirely in future versions. "
"Please use get_composed_params instead.",
DeprecationWarning,
stacklevel=2)
combined_parameter_to_value = self.get_composed_params()

# If we have any mappings, urlencode them and return the full string
if combined_parameter_to_value:
return f"{self.name}?{urlencode(combined_parameter_to_value)}"
# Otherwise, just return this Endpoint's name
else:
return self.name


class AddBrokerEndpoint(AbstractEndpoint):
name = "add_broker"
Expand Down
Expand Up @@ -5,7 +5,7 @@
import cruisecontrolclient.client.Endpoint as Endpoint

# To be able to make more precise type hints
from typing import Dict, Tuple, Type # noqa
from typing import Dict, Tuple, Type


class ExecutionContext:
Expand Down
233 changes: 1 addition & 232 deletions cruise-control-client/cruisecontrolclient/client/Responder.py
@@ -1,9 +1,6 @@
# Copyright 2019 LinkedIn Corp. Licensed under the BSD 2-Clause License (the "License").
# See License in the project root for license information.

# Use the common Display library for showing non-final responses
from cruisecontrolclient.client.Display import display_response

# Use convenience function to redirect printing to stderr
from cruisecontrolclient.util.print import print_error

Expand All @@ -16,16 +13,10 @@
# To be able to make HTTP calls
import requests

# To allow us to make more-precise type hints
from typing import Callable, Dict # noqa

# To be able to define a multithreaded way of interacting with cruise-control
from threading import Thread

# For composing a full URL to display to the humans
from urllib.parse import urlencode

# To be able to deprecate classes
# To inform humans about possibly too-old versions of cruise-control
import warnings


Expand Down Expand Up @@ -146,225 +137,3 @@ def retrieve_response_from_Endpoint(self,
params=endpoint.get_composed_params(),
**kwargs
)


class AbstractResponder(object):
"""
This abstract class provides the skeleton for returning a final requests.Response
object from cruise-control.
This class should not be used directly, since the HTTP method is not defined
in this class.
See the children of AbstractJSONResponder and of AbstractTextResponder
for the concrete classes that use GET and POST to retrieve a response
from cruise-control.
"""

def __init__(self, url: str, headers: Dict[str, str] = None):
warnings.warn("This class is deprecated as of 0.2.0. "
"It may be removed entirely in future versions.",
DeprecationWarning,
stacklevel=2)

self.url: str = url
self.headers: Dict[str, str] = headers

# Open a session in order to handle cruise-control cookies
self.session: requests.Session = requests.Session()

# This abstract class does not define which of the session's
# HTTP methods should be used
self.session_http_method: Callable[[str], requests.Response] = None

def retrieve_response(self) -> requests.Response:
raise NotImplementedError


class AbstractTextResponder(AbstractResponder):
"""
This abstract class provides the skeleton for returning a final requests.Response
object from cruise-control where request.text is text-formatted.
This class should not be used directly, since the HTTP method is not defined
in this class.
TextResponderGet and TextResponderPost are the concrete classes for
using GET and POST to retrieve a response from cruise-control.
"""

def __init__(self, url: str, headers: Dict[str, str] = None):
warnings.warn("This class is deprecated as of 0.2.0. "
"It may be removed entirely in future versions.",
DeprecationWarning,
stacklevel=2)

if 'json=true' in url:
raise ValueError("url must not contain the \"json=true\" parameter")
AbstractResponder.__init__(self, url, headers)

def retrieve_response(self) -> requests.Response:
"""
Returns a final requests.Response object from cruise-control
where Response.text is text-formatted.
:return: requests.Response
"""
# There's actually not a good way at present to do this with
# a text response from cruise-control.
#
# It is much easier to determine whether every JSON response is "final".
raise NotImplementedError


class AbstractJSONResponder(AbstractResponder):
print_to_stdout_enabled = False
"""
This abstract class provides the skeleton for returning a final requests.Response
object from cruise-control where request.text is JSON-formatted.
This class should not be used directly, since the HTTP method is not defined
in this class.
JSONResponderGet and JSONResponderPost are the concrete classes for
using GET and POST to retrieve a response from cruise-control.
This class does NOT display intermediate responses to humans.
"""

def __init__(self, url: str, headers: Dict[str, str] = None):
warnings.warn("This class is deprecated as of 0.2.0. "
"It may be removed entirely in future versions.",
DeprecationWarning,
stacklevel=2)

if 'json=true' not in url:
raise ValueError("url must contain the \"json=true\" parameter")
AbstractResponder.__init__(self, url, headers)
# This abstract class _still_ does not define which HTTP method should be used

def retrieve_response(self) -> requests.Response:
"""
Returns a final requests.Response object from cruise-control
where Response.text is JSON-formatted.
:return: requests.Response
"""
# cruise-control's JSON response has a 'progress' key in it so long
# as the response is not final.
#
# Once the response is final, it does not contain the 'progress' key.
#
# Accordingly, keep getting the response from this session and checking
# it for the 'progress' key.
#
# Return the response as JSON once we get a valid JSON response that we
# think is 'final'.

# Alert the humans to long-running poll
if self.print_to_stdout_enabled:
print_error("Starting long-running poll of {}".format(self.url))

# TODO: Session.get and Session.post can return a plethora of exceptions;
# they should be handled here.
response = self.session_http_method(self.url, headers=self.headers)
while 'progress' in response.json().keys():
if self.print_to_stdout_enabled:
display_response(response)
response = self.session_http_method(self.url, headers=self.headers)

# return the requests.response object
return response


class AbstractJSONDisplayingResponder(AbstractJSONResponder):
print_to_stdout_enabled = True
"""
This class displays intermediate responses to humans via stdout.
"""


class JSONDisplayingResponderGet(AbstractJSONDisplayingResponder):
"""
This class returns a final requests.Response object from cruise-control
where Response.text is JSON-formatted, and where the HTTP method is GET.
"""

def __init__(self, url: str, headers: Dict[str, str] = None):
warnings.warn("This class is deprecated as of 0.2.0. "
"It may be removed entirely in future versions.",
DeprecationWarning,
stacklevel=2)

AbstractJSONDisplayingResponder.__init__(self, url, headers)
self.session_http_method = self.session.get


class JSONDisplayingResponderPost(AbstractJSONDisplayingResponder):
"""
This class returns a final requests.Response object from cruise-control
where Response.text is JSON-formatted, and where the HTTP method is POST.
"""

def __init__(self, url: str, headers: Dict[str, str] = None):
warnings.warn("This class is deprecated as of 0.2.0. "
"It may be removed entirely in future versions.",
DeprecationWarning,
stacklevel=2)

AbstractJSONDisplayingResponder.__init__(self, url, headers)
self.session_http_method = self.session.post


class AbstractJSONResponderThread(Thread):
"""
This abstract class defines a Thread whose purpose is to communicate with
cruise-control and return a requests.Response object.
This class should not be used directly, since the HTTP method is not defined
in this class.
JSONResponderGetThread and JSONResponderPostThread are the concrete classes
for using GET and POST to retrieve a response from cruise-control.
"""

def __init__(self):
warnings.warn("This class is deprecated as of 0.2.0. "
"It may be removed entirely in future versions.",
DeprecationWarning,
stacklevel=2)

Thread.__init__(self)
# This abstract class does not define which concrete JSONResponder class to use
self.json_responder = None
self.response = None

def run(self):
self.response = self.json_responder.retrieve_response()

def get_response(self):
return self.response

def get_json_response(self):
return self.response.json()


class JSONResponderGetThread(AbstractJSONResponderThread):
"""
This class defines a Thread whose purpose is to communicate with cruise-control
via HTTP GET and return a requests.Response object.
"""

def __init__(self, url: str, headers: Dict[str, str] = None):
warnings.warn("This class is deprecated as of 0.2.0. "
"It may be removed entirely in future versions.",
DeprecationWarning,
stacklevel=2)

AbstractJSONResponderThread.__init__(self)
self.json_responder = JSONDisplayingResponderGet(url, headers)


class JSONResponderPostThread(AbstractJSONResponderThread):
"""
This class defines a Thread whose purpose is to communicate with cruise-control
via HTTP POST and return a requests.Response object.
"""

def __init__(self, url: str, headers: Dict[str, str] = None):
warnings.warn("This class is deprecated as of 0.2.0. "
"It may be removed entirely in future versions.",
DeprecationWarning,
stacklevel=2)

AbstractJSONResponderThread.__init__(self)
self.json_responder = JSONDisplayingResponderPost(url, headers)
35 changes: 1 addition & 34 deletions cruise-control-client/cruisecontrolclient/client/cccli.py
Expand Up @@ -6,18 +6,14 @@
# To be able to easily parse command-line arguments
import argparse

# To be able to signify deprecation
import warnings

# To be able to easily pass around the available endpoints and parameters
from cruisecontrolclient.client.ExecutionContext import ExecutionContext

# To be able to instantiate Endpoint objects
import cruisecontrolclient.client.Endpoint as Endpoint

# To be able to make long-running requests to cruise-control
from cruisecontrolclient.client.Responder import AbstractResponder, \
CruiseControlResponder, JSONDisplayingResponderGet, JSONDisplayingResponderPost
from cruisecontrolclient.client.Responder import CruiseControlResponder


def get_endpoint(args: argparse.Namespace,
Expand Down Expand Up @@ -136,35 +132,6 @@ def get_endpoint(args: argparse.Namespace,
return endpoint


def get_responder(endpoint: Endpoint.AbstractEndpoint,
fully_composed_url: str) -> AbstractResponder:
"""
Given an Endpoint and fully-composed URL, return an instantiation of
the correct JSONDisplayingResponder.
This is needed because the JSONDisplayingResponder classes do not dynamically
determine from the given Endpoint which type of HTTP request they must make.
:param endpoint: A built Endpoint object
:param fully_composed_url: The full cruise-control URL, including paths and parameters
:return: An instantiation of the correct JSONDisplayingResponder.
"""
warnings.warn("This function is deprecated as of 0.2.0, as "
"it only exists to facilitate the use of deprecated classes. "
"It may be removed entirely in future versions.",
DeprecationWarning,
stacklevel=2)
# Handle instantiating the correct Responder
if endpoint.http_method == "GET":
json_responder = JSONDisplayingResponderGet(fully_composed_url)
elif endpoint.http_method == "POST":
json_responder = JSONDisplayingResponderPost(fully_composed_url)
else:
raise ValueError(f"Unexpected http_method {endpoint.http_method} in endpoint")

return json_responder


def build_argument_parser(execution_context: ExecutionContext) -> argparse.ArgumentParser:
"""
Builds and returns an argument parser for interacting with cruise-control via CLI.
Expand Down
1 change: 0 additions & 1 deletion cruise-control-client/requirements.txt
@@ -1,2 +1 @@
pandas
requests
3 changes: 1 addition & 2 deletions cruise-control-client/setup.py
Expand Up @@ -11,7 +11,7 @@

setuptools.setup(
name='cruise-control-client',
version='0.3.1',
version='1.0.0',
author='mgrubent',
author_email='mgrubentrejo@linkedin.com',
description='A Python client for cruise-control',
Expand All @@ -25,7 +25,6 @@
},
packages=setuptools.find_packages(),
install_requires=[
'pandas',
'requests'
],
license='Copyright 2019 LinkedIn Corp. Licensed under the BSD 2-Clause License (the "License").'
Expand Down

0 comments on commit c9dff71

Please sign in to comment.