<commit_before>#!/usr/bin/env python
"""
py2neo
=======

Python library for accessing neo4j via RESTful web service interface

"""

import httplib2
import json


class Resource:
	"""
	Web service resource class, nothing here specific to neo4j but designed to
	work with a well-behaved hypermedia web service; used here as a base class
	for objects represented within the neo4j web service
	"""

	_read_headers = {
		"Accept": "application/json"
	}
	_write_headers = {
		"Accept": "application/json",
		"Content-Type": "application/json"
	}

	def __init__(self, uri, http=None):
		"""
		Creates a new Resource instance
		
		Parameters:
			uri  - the root URI for this resource
			http - optional httplib2.Http() object to use for requests
		
		"""
		if http == None:
			self._http = httplib2.Http()
		else:
			self._http = http
		self.uri = uri
		self._index = None

	def lookup(self, key):
		"""
		Looks up a value in the resource index by key; will lazily load
		resource index if required
		"""
		if(self._index == None):
			self._index = self._get(self.uri)
		return self._index[key]

	def _get(self, uri, args={}):
		"""
		Issues an HTTP GET request
		
		Parameters:
			uri  - the URI of the resource to GET
			args - optional dictionary containing URI template substitution values
		
		Result (dependent on HTTP status code):
			200 - returns value created from returned json content
			204 - returns None
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response
		
		"""
		response, content = self._http.request(uri.format(**args), "GET", None, self._read_headers)
		if response.status == 200:
			return json.loads(content)
		elif response.status == 204:
			return None
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def _post(self, uri, data, args={}):
		"""
		Issues an HTTP POST request
		
		Parameters:
			uri  - the URI of the resource to POST to
			data - a value to be converted to json and passed in request payload
			args - optional dictionary containing URI template substitution values
		
		Result (dependent on HTTP status code):
			201 - returns value from "Location" header
			400 - raises a ValueError against the specified data
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response
		
		"""
		data = {} if data == None else json.dumps(data)
		response, content = self._http.request(uri.format(**args), "POST", data, self._write_headers)
		if response.status == 201:
			return response["location"]
		elif response.status == 400:
			raise ValueError(data)
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def _put(self, uri, data, args={}):
		"""
		Issues an HTTP PUT request
		
		Parameters:
			uri  - the URI of the resource to PUT
			data - a value to be converted to json and passed in request payload
			args - optional dictionary containing URI template substitution values
		
		Result (dependent on HTTP status code):
			204 - success (no return value)
			400 - raises a ValueError against the specified data
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response
		
		"""
		data = {} if data == None else json.dumps(data)
		response, content = self._http.request(uri.format(**args), "PUT", data, self._write_headers)
		if response.status == 204:
			pass
		elif response.status == 400:
			raise ValueError(data)
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def _delete(self, uri, args={}):
		"""
		Issues an HTTP DELETE request
		
		Parameters:
			uri  - the URI of the resource to DELETE
			args - optional dictionary containing URI template substitution values
		
		Result (dependent on HTTP status code):
			204 - success (no return value)
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response
		
		"""
		response, content = self._http.request(uri.format(**args), "DELETE", None, self._read_headers)
		if response.status == 204:
			pass
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def __repr__(self):
		return repr(self.uri)

	def __str__(self):
		return str(self.uri)


class Direction:

	INCOMING = -1
	BOTH     =  0
	OUTGOING =  1

	@staticmethod
	def get_label(direction):
		if direction > 0:
			return "outgoing"
		elif direction < 0:
			return "incoming"
		else:
			return "all"


class GraphDatabaseService(Resource):

	def __init__(self, uri, http=None):
		Resource.__init__(self, uri, http)

	def create_node(self, properties=None):
		return Node(self._post(self.lookup("node"), properties), self._http)

	def get_reference_node(self):
		return Node(self.lookup("reference_node"), self._http)

	def get_relationship_types(self):
		return self._get(self.lookup("relationship_types"))

	def get_node_indexes(self):
		indexes = self._get(self.lookup("node_index"))
		# replace with map()
		for i in indexes:
			index = indexes[i]
			indexes[i] = NodeIndex(index["type"], index["template"], index["provider"], self._http)
		return indexes

	def get_relationship_indexes(self):
		indexes = self._get(self.lookup("relationship_index"))
		# replace with map()
		for i in indexes:
			index = indexes[i]
			indexes[i] = RelationshipIndex(index["type"], index["template"], index["provider"], self._http)
		return indexes


class PropertyContainer(Resource):

	def __init__(self, uri, http=None):
		Resource.__init__(self, uri, http)

	def set_properties(self, properties):
		self._put(self.lookup("properties"), properties)

	def get_properties(self):
		return self._get(self.lookup("properties"))

	def remove_properties(self):
		self._delete(self.lookup("properties"))

	def __setitem__(self, key, value):
		self._put(self.lookup("property").format(key=key), value)

	def __getitem__(self, key):
		return self._get(self.lookup("property").format(key=key))

	def __delitem__(self, key):
		self._delete(self.lookup("property").format(key=key))


class Node(PropertyContainer):

	def __init__(self, uri, http=None):
		PropertyContainer.__init__(self, uri, http)

	def delete(self):
		self._delete(self._index["self"])

	def create_relationship_to(self, other_node, type, data=None):
		return Relationship(self._post(self.lookup("create_relationship"), {
			"to": str(other_node),
			"type": type,
			"data": data
		}), self._http)

	def get_relationships(self, direction, *types):
		prefix = Direction.get_label(direction)
		if len(types) == 0:
			uri = self.lookup("{0}_relationships".format(prefix))
		else:
			uri = self.lookup("{0}_typed_relationships".format(prefix)).replace("{-list|&|types}", "&".join(types))
		return [Relationship(rel["self"]) for rel in self._get(uri)]

	def get_related_nodes(self, direction, *types):
		prefix = Direction.get_label(direction)
		if len(types) == 0:
			uri = self.lookup("{0}_relationships".format(prefix))
		else:
			uri = self.lookup("{0}_typed_relationships".format(prefix)).replace("{-list|&|types}", "&".join(types))
		return [Node(rel["start"] if rel["end"] == self.uri else rel["end"]) for rel in self._get(uri)]


class Relationship(PropertyContainer):
<commit_msg>Refactored direction prefix code<commit_after>#!/usr/bin/env python
"""
py2neo
=======

Python library for accessing neo4j via RESTful web service interface

"""

import httplib2
import json


class Resource:
	"""
	Web service resource class, nothing here specific to neo4j but designed to
	work with a well-behaved hypermedia web service; used here as a base class
	for objects represented within the neo4j web service
	"""

	_read_headers = {
		"Accept": "application/json"
	}
	_write_headers = {
		"Accept": "application/json",
		"Content-Type": "application/json"
	}

	def __init__(self, uri, http=None):
		"""
		Creates a new Resource instance
		
		Parameters:
			uri  - the root URI for this resource
			http - optional httplib2.Http() object to use for requests
		
		"""
		if http == None:
			self._http = httplib2.Http()
		else:
			self._http = http
		self.uri = uri
		self._index = None

	def lookup(self, key):
		"""
		Looks up a value in the resource index by key; will lazily load
		resource index if required
		"""
		if(self._index == None):
			self._index = self._get(self.uri)
		return self._index[key]

	def _get(self, uri, args={}):
		"""
		Issues an HTTP GET request
		
		Parameters:
			uri  - the URI of the resource to GET
			args - optional dictionary containing URI template substitution values
		
		Result (dependent on HTTP status code):
			200 - returns value created from returned json content
			204 - returns None
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response
		
		"""
		response, content = self._http.request(uri.format(**args), "GET", None, self._read_headers)
		if response.status == 200:
			return json.loads(content)
		elif response.status == 204:
			return None
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def _post(self, uri, data, args={}):
		"""
		Issues an HTTP POST request
		
		Parameters:
			uri  - the URI of the resource to POST to
			data - a value to be converted to json and passed in request payload
			args - optional dictionary containing URI template substitution values
		
		Result (dependent on HTTP status code):
			201 - returns value from "Location" header
			400 - raises a ValueError against the specified data
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response
		
		"""
		data = {} if data == None else json.dumps(data)
		response, content = self._http.request(uri.format(**args), "POST", data, self._write_headers)
		if response.status == 201:
			return response["location"]
		elif response.status == 400:
			raise ValueError(data)
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def _put(self, uri, data, args={}):
		"""
		Issues an HTTP PUT request
		
		Parameters:
			uri  - the URI of the resource to PUT
			data - a value to be converted to json and passed in request payload
			args - optional dictionary containing URI template substitution values
		
		Result (dependent on HTTP status code):
			204 - success (no return value)
			400 - raises a ValueError against the specified data
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response
		
		"""
		data = {} if data == None else json.dumps(data)
		response, content = self._http.request(uri.format(**args), "PUT", data, self._write_headers)
		if response.status == 204:
			pass
		elif response.status == 400:
			raise ValueError(data)
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def _delete(self, uri, args={}):
		"""
		Issues an HTTP DELETE request
		
		Parameters:
			uri  - the URI of the resource to DELETE
			args - optional dictionary containing URI template substitution values
		
		Result (dependent on HTTP status code):
			204 - success (no return value)
			404 - raises a KeyError against the specified URI
			??? - raises a SystemError with the HTTP response
		
		"""
		response, content = self._http.request(uri.format(**args), "DELETE", None, self._read_headers)
		if response.status == 204:
			pass
		elif response.status == 404:
			raise KeyError(uri)
		else:
			raise SystemError(response)

	def __repr__(self):
		return repr(self.uri)

	def __str__(self):
		return str(self.uri)


class Direction:

	INCOMING = -1
	BOTH     =  0
	OUTGOING =  1

	@staticmethod
	def get_label(direction):
		if direction > 0:
			return "outgoing"
		elif direction < 0:
			return "incoming"
		else:
			return "all"


class GraphDatabaseService(Resource):

	def __init__(self, uri, http=None):
		Resource.__init__(self, uri, http)

	def create_node(self, properties=None):
		return Node(self._post(self.lookup("node"), properties), self._http)

	def get_reference_node(self):
		return Node(self.lookup("reference_node"), self._http)

	def get_relationship_types(self):
		return self._get(self.lookup("relationship_types"))

	def get_node_indexes(self):
		indexes = self._get(self.lookup("node_index"))
		# replace with map()
		for i in indexes:
			index = indexes[i]
			indexes[i] = NodeIndex(index["type"], index["template"], index["provider"], self._http)
		return indexes

	def get_relationship_indexes(self):
		indexes = self._get(self.lookup("relationship_index"))
		# replace with map()
		for i in indexes:
			index = indexes[i]
			indexes[i] = RelationshipIndex(index["type"], index["template"], index["provider"], self._http)
		return indexes


class PropertyContainer(Resource):

	def __init__(self, uri, http=None):
		Resource.__init__(self, uri, http)

	def set_properties(self, properties):
		self._put(self.lookup("properties"), properties)

	def get_properties(self):
		return self._get(self.lookup("properties"))

	def remove_properties(self):
		self._delete(self.lookup("properties"))

	def __setitem__(self, key, value):
		self._put(self.lookup("property").format(key=key), value)

	def __getitem__(self, key):
		return self._get(self.lookup("property").format(key=key))

	def __delitem__(self, key):
		self._delete(self.lookup("property").format(key=key))


class Node(PropertyContainer):

	def __init__(self, uri, http=None):
		PropertyContainer.__init__(self, uri, http)

	def delete(self):
		self._delete(self._index["self"])

	def create_relationship_to(self, other_node, type, data=None):
		return Relationship(self._post(self.lookup("create_relationship"), {
			"to": str(other_node),
			"type": type,
			"data": data
		}), self._http)

	def get_relationships(self, direction, *types):
		prefix = Direction.get_label(direction)
		if len(types) == 0:
			uri = self.lookup(prefix + "_relationships")
		else:
			uri = self.lookup(prefix + "_typed_relationships").replace("{-list|&|types}", "&".join(types))
		return [Relationship(rel["self"]) for rel in self._get(uri)]

	def get_related_nodes(self, direction, *types):
		prefix = Direction.get_label(direction)
		if len(types) == 0:
			uri = self.lookup(prefix + "_relationships")
		else:
			uri = self.lookup(prefix + "_typed_relationships").replace("{-list|&|types}", "&".join(types))
		return [Node(rel["start"] if rel["end"] == self.uri else rel["end"]) for rel in self._get(uri)]


class Relationship(PropertyContainer):

{'fraction_non_alphanumeric': 0.11856560491950528, 'fraction_numerical': 0.0113314447592068, 'mean_word_length': 4.0326842837273995, 'pattern_counts': {'":': 12, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4567534', 'n_tokens_mistral': 5094, 'n_tokens_neox': 4315, 'n_words': 1391}