<commit_before>#Create classes Observable and Subscribe 
#Observable applies on any property that needs to be observed
#Subscribe applies on cases where a variable depends on the subscribed values. A variable could Subscribe to one or more Observables, with an operand in case there's more than one observables. The operation is evaluated according to Infix notation.
#Create a global dictionary that is initialized when the module is imported. Hold the variable ids against the name of the variables. Whenever a Subscription comes in, check for its dependencies, create a dependency graph, and mention this in a list called VariablesThatDepend.


#UUID is the basis on which each variable is identified. In other words, the variable in a program is uniquely mapped to a UUID, which serves as the placeholder for the variable.
import uuid

_observable = {}
_depends_on = {}
cascadeEffect = {}

class InvalidSubscriptionError(Exception):
	"""Special Exception that inherits from Base Exception class. Does nothing but raise a relevant exception"""
	pass

class Observe:
	"""Deals with all observables/properties."""
	
	global _observable, _depends_on, cascadeEffect
	def __init__(self, value):
		"""Initializes the observable. Also assigns a UUID"""
		self.id = uuid.uuid4()
		self.value = value
		_observable[self] = self.id
		cascadeEffect[self] = []
		#print("%s"%_observable)

	def get(self):
		"""Returns the current value of the variable"""
		temp = self.value
		if type(temp) is Observe:
			while type(temp) is Observe:
				temp = temp.value
				continue
		if type(temp) is Subscribe:
			#Write the code for observing a Subscription.
			while type(temp) is Subscribe:
				temp = temp.value
				continue
		return temp
	
	def update(self, value):
		"""Updates the value of the variable"""
		self.value = value
		#Whenever an update of a variable occurs, this update needs to cascade into an updation of the value of the subscripted variable that depends on it. And this could be done by maintaining a cascadeList.
		#Cascade the effect on to the subscription.
		if len(cascadeEffect[self]) != 0:
			for i in cascadeEffect[self]:
				Subscribe.update(i)


class Subscribe:
	"""Deals with the subscription of observables/properties."""

	global _observable, _depends_on, cascadeEffect
	def __init__(self, **args):
		"""Initializes the subscription. Compulsory arguments are var and op, where var is a tuple of variables that need to be subscribed to and op is the tuple of operands that operate upon the variables. v0.0.1 would only work for binary operators."""
		try:
			self.variablesToObserve = list(args['var'])

			self.OperatorsList = list(args['op'])
			#_depends_on[self] = {}
			secondOperatorsList = self.OperatorsList[:]
		except:
			raise InvalidSubscriptionError("Can't initialize a subscription with no observables")
		#if len(args) is 0 or len(args['var']) is 0 or len(args['op'] is 0:
		#	raise InvalidSubscriptionError("Can't initialize a subscription with no observables")
		#Not handling unary operators here. Need to handle '++', '--', '- (negation)', byte shift. Also check for other unary operands
		

		
		for var in self.variablesToObserve:
			#Checking if the received variable is a predefined observable
			try:
				#variableId = var.id
				#if variableId not in _observable:
					#Case when the variable is an observable, except that it hasn't been declared in the local scope
				#	raise InvalidSubscriptionError("Not a local observable. Initialize the observable first")
				varId = _observable[var]
				print("Variable UUID is %s"%varId)
			except:
				#Case when the variable passed isn't an observable
				raise InvalidSubscriptionError("Variable not an observable. Declare the variable as an observable before subscribing to it")

		if len(self.variablesToObserve) - 1 != len(self.OperatorsList):
			raise InvalidSubscriptionError("Can't initialize subscription. The number of variables should always be 1 more than the number of operands")
		#else:
		#	print(args)

		self.id = uuid.uuid4()
		cascadeEffect[self] = []

		_observable[self] = self.id
		for i in self.variablesToObserve:
			cascadeEffect[i].append(self)
		self.update()
		#_depends_on[]

		#The procedure from here could be done using asyncio. The above process can't, because it would be too risky, as the variables passed might not be Observables. But at this point, all variables are checked for their nature, and only if they're Observables, can we reach this point of execution. Hence, it is safe to execute further code asynchronously.

		#BEGIN THE EVALUATION HERE
		#THE EVALUATION PRECEDENCE IS AS FOLLOWS:
		#1. ** OPERATOR GETS THE HIGHEST PREFERENCE
		#2. *, /, //, % GET THE NEXT PREFERENCE
		#3. + and - GET THE NEXT PREFERENCE
		#4. Also, in case of a tie, the L-to-R operator precedence is followed. This is because the first occurrence of the operator is found, evaluated, then the evaluation moves on to the second occurrence. 
		#BRACKETS AREN'T SUPPORTED YET, SO A WORKAROUND IS TO SUBSCRIBE A RESULTANT ON THE OBSERVABLES, AND THEN FURTHER PASS THIS VALUE TO THE NEW SUBSCRIPTION

		#CASE list(1: CHECK FOR THE PRESENCE OF ** IN OperatorsList, NOTE ITS LOCATION, POP THE RELEVANT OPERANDS FROM THE VARIABLESTOOBSERVE LIST, PERFORM THE OPERATION, ASSIGN IT TO A TEMP VARIABLE)
		#ALSO, COUNT THE NUMBER OF TIMES THE CORRESPONDING OPERATOR IS PRESENT. ITERATE THESE MANY TIMES, PICK UP THE CORRESPONDING ELEMENTS, PERFORM THE OPERATIONS, REPLACE THE CORRESPONDIlist(NG ELEMENTS WITH THE RESULT, THEN CONTINUE WITH OTHER OPERATIONS)

		#REWORK: CREATE A SET OF ALL OPERATORS AND LOOP THROUGH EACH OPERATOR. FOR EVERY OPERATOR, COUNT THE NUMBER OF TIMES OF OCCURRENCE, AND EVALUATE THE APPROPRIATE OPERANDS

		

	def update(self):
		"""This method needs to be hidden. Can only be called by Observables when there's an update in their values."""

		OperatorsSet = createSetInPrecedence(self.OperatorsList)		#Generates the set of all operators, and hence, this is unique. Also, the set has the operators according to their order of precedence, that is, the operator with the highest order of precedence will have a lower index.
		OperatorsListCopy = self.OperatorsList[:]
		print("The operators set in order of precedence is %s"%OperatorsSet)
		#Here, instead of simply shallow copying the variablesToObserve list, copy the return values of every item with the .get() method. This would mean that only the latest values of the observables are used, and also, further calculation would be easier.
		alteredListCopy = self.variablesToObserve[:]
		alteredList = []
		for element in alteredListCopy:
			alteredList.append(element.get())

		for operator in OperatorsSet:
			#Send the list of variables, current operator and OperatorsList to a calculatingFunction that evaluates
			print("The operator in __init__ is %s"%operator)
			alteredList = evaluateEquation(alteredList, operator, OperatorsListCopy)
			print("The alteredList is %s"%alteredList)

		self.value = alteredList[0]		#Assign the last remaining value as the value of the expression
		#print(self.value)

		if len(cascadeEffect[self]) != 0:
			for i in cascadeEffect[self]:
				Subscribe.update(i)



	def equation(self):
		"""Returns the current equation of the subscription"""
		equationString = ''
		for i in range(len(self.variablesToObserve)):
			if i < len(self.OperatorsList):
				operatorEqn = self.OperatorsList[i]
			else:
				operatorEqn = ''
			
			equationString += str(self.variablesToObserve[i].get()) + operatorEqn		#Instead of using .get(), use self.variablesToObserve.variableName here. Store variableName as an Observe class parameter and declare it at __init__ itself.
		self.equation = equationString
		return self.equation





	def get(self):
		"""Retrieve the latest value of the subscription"""
		return self.value


def createSetInPrecedence(OperatorsList):
	newOperatorList = []
	#Check for all operators here. In future, this can accomodate more operators
	if '**' in OperatorsList:
		newOperatorList.append('**')<commit_msg>Edited equation method to output variable names<commit_after>#Create classes Observable and Subscribe 
#Observable applies on any property that needs to be observed
#Subscribe applies on cases where a variable depends on the subscribed values. A variable could Subscribe to one or more Observables, with an operand in case there's more than one observables. The operation is evaluated according to Infix notation.
#Create a global dictionary that is initialized when the module is imported. Hold the variable ids against the name of the variables. Whenever a Subscription comes in, check for its dependencies, create a dependency graph, and mention this in a list called VariablesThatDepend.


#UUID is the basis on which each variable is identified. In other words, the variable in a program is uniquely mapped to a UUID, which serves as the placeholder for the variable.
import uuid

_observable = {}
_depends_on = {}
cascadeEffect = {}

class InvalidSubscriptionError(Exception):
	"""Special Exception that inherits from Base Exception class. Does nothing but raise a relevant exception"""
	pass

class Observe:
	"""Deals with all observables/properties."""
	
	global _observable, _depends_on, cascadeEffect
	def __init__(self, value, name=''):
		"""Initializes the observable. Also assigns a UUID"""
		self.id = uuid.uuid4()
		self.value = value
		print("Value is %s"%self.value)
		_observable[self] = self.id
		cascadeEffect[self] = []
		if type(name) is str:
			self.name = name
		else:
			raise TypeError("Name has to be a string.")
		#print("%s"%_observable)

	def get(self):
		"""Returns the current value of the variable"""
		temp = self.value
		if type(temp) is Observe:
			while type(temp) is Observe:
				temp = temp.value
				continue
		if type(temp) is Subscribe:
			#Write the code for observing a Subscription.
			while type(temp) is Subscribe:
				temp = temp.value
				continue
		return temp
	
	def update(self, value):
		"""Updates the value of the variable"""
		self.value = value
		#Whenever an update of a variable occurs, this update needs to cascade into an updation of the value of the subscripted variable that depends on it. And this could be done by maintaining a cascadeList.
		#Cascade the effect on to the subscription.
		if len(cascadeEffect[self]) != 0:
			for i in cascadeEffect[self]:
				Subscribe.update(i)


class Subscribe:
	"""Deals with the subscription of observables/properties."""

	global _observable, _depends_on, cascadeEffect
	def __init__(self, name = '', **args):
		"""Initializes the subscription. Compulsory arguments are var and op, where var is a tuple of variables that need to be subscribed to and op is the tuple of operands that operate upon the variables. v0.0.1 would only work for binary operators."""
		try:
			self.variablesToObserve = list(args['var'])

			self.OperatorsList = list(args['op'])
			#_depends_on[self] = {}
			secondOperatorsList = self.OperatorsList[:]
		except:
			raise InvalidSubscriptionError("Can't initialize a subscription with no observables")
		#if len(args) is 0 or len(args['var']) is 0 or len(args['op'] is 0:
		#	raise InvalidSubscriptionError("Can't initialize a subscription with no observables")
		#Not handling unary operators here. Need to handle '++', '--', '- (negation)', byte shift. Also check for other unary operands
		

		
		for var in self.variablesToObserve:
			#Checking if the received variable is a predefined observable
			try:
				#variableId = var.id
				#if variableId not in _observable:
					#Case when the variable is an observable, except that it hasn't been declared in the local scope
				#	raise InvalidSubscriptionError("Not a local observable. Initialize the observable first")
				varId = _observable[var]
				print("Variable UUID is %s"%varId)
			except:
				#Case when the variable passed isn't an observable
				raise InvalidSubscriptionError("Variable not an observable. Declare the variable as an observable before subscribing to it")

		if len(self.variablesToObserve) - 1 != len(self.OperatorsList):
			raise InvalidSubscriptionError("Can't initialize subscription. The number of variables should always be 1 more than the number of operands")
		#else:
		#	print(args)

		self.id = uuid.uuid4()
		cascadeEffect[self] = []

		_observable[self] = self.id
		self.name = name
		for i in self.variablesToObserve:
			cascadeEffect[i].append(self)
		self.update()
		#_depends_on[]

		#The procedure from here could be done using asyncio. The above process can't, because it would be too risky, as the variables passed might not be Observables. But at this point, all variables are checked for their nature, and only if they're Observables, can we reach this point of execution. Hence, it is safe to execute further code asynchronously.

		#BEGIN THE EVALUATION HERE
		#THE EVALUATION PRECEDENCE IS AS FOLLOWS:
		#1. ** OPERATOR GETS THE HIGHEST PREFERENCE
		#2. *, /, //, % GET THE NEXT PREFERENCE
		#3. + and - GET THE NEXT PREFERENCE
		#4. Also, in case of a tie, the L-to-R operator precedence is followed. This is because the first occurrence of the operator is found, evaluated, then the evaluation moves on to the second occurrence. 
		#BRACKETS AREN'T SUPPORTED YET, SO A WORKAROUND IS TO SUBSCRIBE A RESULTANT ON THE OBSERVABLES, AND THEN FURTHER PASS THIS VALUE TO THE NEW SUBSCRIPTION

		#CASE list(1: CHECK FOR THE PRESENCE OF ** IN OperatorsList, NOTE ITS LOCATION, POP THE RELEVANT OPERANDS FROM THE VARIABLESTOOBSERVE LIST, PERFORM THE OPERATION, ASSIGN IT TO A TEMP VARIABLE)
		#ALSO, COUNT THE NUMBER OF TIMES THE CORRESPONDING OPERATOR IS PRESENT. ITERATE THESE MANY TIMES, PICK UP THE CORRESPONDING ELEMENTS, PERFORM THE OPERATIONS, REPLACE THE CORRESPONDIlist(NG ELEMENTS WITH THE RESULT, THEN CONTINUE WITH OTHER OPERATIONS)

		#REWORK: CREATE A SET OF ALL OPERATORS AND LOOP THROUGH EACH OPERATOR. FOR EVERY OPERATOR, COUNT THE NUMBER OF TIMES OF OCCURRENCE, AND EVALUATE THE APPROPRIATE OPERANDS

		

	def update(self):
		"""This method needs to be hidden. Can only be called by Observables when there's an update in their values."""

		OperatorsSet = createSetInPrecedence(self.OperatorsList)		#Generates the set of all operators, and hence, this is unique. Also, the set has the operators according to their order of precedence, that is, the operator with the highest order of precedence will have a lower index.
		OperatorsListCopy = self.OperatorsList[:]
		print("The operators set in order of precedence is %s"%OperatorsSet)
		#Here, instead of simply shallow copying the variablesToObserve list, copy the return values of every item with the .get() method. This would mean that only the latest values of the observables are used, and also, further calculation would be easier.
		alteredListCopy = self.variablesToObserve[:]
		alteredList = []
		for element in alteredListCopy:
			alteredList.append(element.get())

		for operator in OperatorsSet:
			#Send the list of variables, current operator and OperatorsList to a calculatingFunction that evaluates
			print("The operator in __init__ is %s"%operator)
			alteredList = evaluateEquation(alteredList, operator, OperatorsListCopy)
			print("The alteredList is %s"%alteredList)

		self.value = alteredList[0]		#Assign the last remaining value as the value of the expression
		#print(self.value)

		if len(cascadeEffect[self]) != 0:
			for i in cascadeEffect[self]:
				Subscribe.update(i)



	def equation(self):
		"""Returns the current equation of the subscription"""
		equationString = ''
		if self.name != '':
			equationString = self.name + ' ='
		for i in range(len(self.variablesToObserve)):
			if i < len(self.OperatorsList):
				operatorEqn = self.OperatorsList[i]
			else:
				operatorEqn = ''
			if self.variablesToObserve[i].name == '':		#Case when name hasn't been defined
				nameOfVariable = str(self.variablesToObserve[i].get())
			else:
				nameOfVariable = self.variablesToObserve[i].name

			equationString += ' ' + nameOfVariable + ' ' + operatorEqn		#Instead of using .get(), use self.variablesToObserve.variableName here. Store variableName as an Observe class parameter and declare it at __init__ itself.
		self.equation = equationString
		return self.equation





	def get(self):
		"""Retrieve the latest value of the subscription"""
		return self.value


def createSetInPrecedence(OperatorsList):
	newOperatorList = []
	#Check for all operators here. In future, this can accomodate more operators
	if '**' in OperatorsList:
		newOperatorList.append('**')
{'fraction_non_alphanumeric': 0.0755813953488372, 'fraction_numerical': 0.002180232558139535, 'mean_word_length': 4.350939727802981, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, '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': '563914', 'n_tokens_mistral': 5195, 'n_tokens_neox': 4605, 'n_words': 2031}