view V5/synastry.py @ 31:926b008ccb0c tip

resolving vertex and fixing description results - I believe everything works
author DaveM
date Sat, 19 May 2018 14:50:41 +0100
parents 52ea10196da3
children
line wrap: on
line source
import sys
sys.path.insert(0,'/Volumes/Internal/Documents/localRequest')
import random
import csv
import re
import localRequests as lr
import time
from bs4 import BeautifulSoup

import pdb
DEFAULT_SOURCE = 'local'
# DEFAULT_SOURCE = None

class compatibility:
	def __init__(self):
		self.rules = []
		self.uniqueID = 0
		print 'Warning, need to fix [None Location] issues'

	def addRule(self,planetTuple,aspectList,score):
		rule = compatibilityRule(self.uniqueID,planetTuple,aspectList,score)
		self.rules.append(rule)
		self.uniqueID += 1

	def findRule(self,planet):
		ruleList = [r for r in self.rules if r.planet == planet]
		print ruleList
		return ruleList

	def readFile(self,filename):
		text = []
		with open(filename) as fp:
			line = fp.readline()
			text.append(line.strip())
			while line:
				line = fp.readline()
				text.append(line.strip())
		return text	

	def parseCompatRules(self,filename):
		comList = self.readFile(filename)
		for com in comList:
			# print com
			planetTuple = None
			aspectList = None
			score = None
			c = com.split(',')
			if len(c) == 4:
				if len(c[1]) > 1:
					aspectList = []
					planetTuple = tuple((c[0].lower(),c[2].lower()))
					score = int(c[3])
					for subset in c[1].lower().split(' '):
						aspectList.append(subset)
				elif len(c[1]) == 0 :
					if 'house' not in c[2]:
						print 'some error where rule is not house'
					planetTuple = (c[0].lower(),'house')
					houseNo = re.findall('\d+', c[2])
					if len(houseNo) != 1:
						print 'multiple house numbers found - ERROR'
					aspectList = int(houseNo[0])
					score = int(c[3])
				self.addRule(planetTuple,aspectList,score)

	def calcCompatibility(self, horiscope):
		score = 0
		for rule in sorted(self.rules):
			if rule.planet[1]  == 'house' and rule.planet[0] == 'asc':
				angle = horiscope.calcAngle('asc','asc')
				if (angle > 210 and angle < 240) or  (angle > 120 and angle < 150):
					score += rule.score
			elif horiscope.planets[rule.planet[0]].angleA is None:
				pdb.set_trace()
				print 'Error - None Location'
				return None
			elif rule.planet[1] == 'house':
				if horiscope.isInHouse(rule.planet[0],rule.aspect):
					score += rule.score
			elif rule.planet[0] == rule.planet[1]:
				aspect,variance = horiscope.calcAspect(rule.planet[0],rule.planet[1])
				if aspect is not None:
					if aspect in rule.aspect:
						score += rule.score
			else:
				for order in [0,1]:
					aspect,variance = horiscope.calcAspect(rule.planet[order],rule.planet[not order])
					if aspect is not None:
						if aspect in rule.aspect:
							score += rule.score
		return score


	def describeCompatibility(self, horiscope):
		score = 0
		outString = []
		for rule in sorted(self.rules):
			if rule.planet[1]  == 'house' and rule.planet[0] == 'asc':
				angle = horiscope.calcAngle('asc','asc')
				if (angle > 210 and angle < 240) or  (angle > 120 and angle < 150):
					score += rule.score
					outString += rule.planet[0] +' '+ rule.planet[1] +' '+ str(aspect)+' '+str(rule.score) + '\n'
					# aspect,variance = horiscope.calcAspect(rule.planet[order],rule.planet[not order])
			elif horiscope.planets[rule.planet[0]].angleA is None:
				pdb.set_trace()
				# print 'Error - None Location'
				return None
			elif rule.planet[1] == 'house':
				if horiscope.isInHouse(rule.planet[0],rule.aspect):
					score += rule.score
					outString += rule.planet[0] +' '+ rule.planet[1] +' '+ str(aspect)+' '+str(rule.score)+ '\n'
			elif rule.planet[0] == rule.planet[1]:
				aspect,variance = horiscope.calcAspect(rule.planet[0],rule.planet[1])
				if aspect is not None:
					if aspect in rule.aspect:
						score += rule.score
						outString += rule.planet[0]+' '+aspect +' '+ rule.planet[1] +' '+ str(rule.score) +'\n'
			else:
				for order in [0,1]:
					aspect,variance = horiscope.calcAspect(rule.planet[order],rule.planet[not order])
					if aspect is not None:
						if aspect in rule.aspect:
							score += rule.score
							outString += rule.planet[0] +' '+ aspect +' '+ rule.planet[1] +' '+ str(rule.score)+'\n'
						else:
							outString += rule.planet[0] +' '+ aspect +' '+ rule.planet[1] +' 0'+'\n'
		return score,outString

	


class compatibilityRule:
	def __init__(self,uniqueId,planetTuple,aspectList,score):
		self.id = uniqueId
		self.planet = planetTuple
		self.aspect = aspectList
		self.score = score


class Person:
	url = 'https://horoscopes.astro-seek.com/calculate-love-compatibility/'
	def __init__(self,personDict):
		# self. = planetPositions()
		self.id = personDict['ID']
		self.dob = personDict['DOB']
		self.tob = personDict['TOB']
		self.cob = personDict['COB']
		self.p_dob = personDict['pDOB']
		self.p_tob = personDict['pTOB']
		self.p_cob = personDict['pCOB']
		self.horiscope = None
		self.resp = None
		self.vertex = None
		self.issue = 'INCOMPLETE'

	def identifyIssues(self):
		if self.id is None:
			self.issue = 'id'
		elif self.dob is None:
			self.issue = 'dob'
		elif self.tob is None:
			self.issue = 'tob'
		elif self.cob is None:
			self.issue = 'cob'
		elif self.p_dob is None:
			self.issue = 'p_dob'
		elif self.p_tob is None:
			self.issue = 'p_tob'
		elif self.p_cob is None:
			self.issue = 'p_cob'
		else:
			self.issue = None
		return self.issue

	def makePayload(self):
		if type(self.cob) is str:
			cob_0 = float(self.cob.split(',')[0][1:])
			cob_1 = float(self.cob.split(',')[1])
			self.cob = (cob_0,cob_1)
		if type(self.p_cob) is str:
			pcob_0 = float(self.p_cob.split(',')[0][1:])
			pcob_1 = float(self.p_cob.split(',')[1])
			self.p_cob = (pcob_0,pcob_1)
		if type(self.dob) is str:
			self.dob = self.dob[1:-1].split(',')
		if type(self.p_dob) is str:
			self.p_dob = self.p_dob[1:-1].split(',')
		if type(self.tob) is str:
			self.tob = self.tob[1:-1].split(',')
		if type(self.p_tob) is str:
			self.p_tob = self.p_tob[1:-1].split(',')
		
		self.payload = {'send_calculation':'1', #Req
			'muz_narozeni_den':self.dob[0],
			'muz_narozeni_mesic':self.dob[1],
			'muz_narozeni_rok':self.dob[2],
			'muz_narozeni_hodina':self.tob[0],
			'muz_narozeni_minuta':self.tob[1],
			'muz_narozeni_city':'',
			'muz_narozeni_mesto_hidden':'Manually+place%3A+%C2%B0%27N%2C+%C2%B0%27E',#auto
			'muz_narozeni_stat_hidden':'XX',
			'muz_narozeni_podstat_kratky_hidden':'',
			'muz_narozeni_podstat_hidden':'',
			'muz_narozeni_podstat2_kratky_hidden':'',
			'muz_narozeni_podstat3_kratky_hidden':'',
			'muz_narozeni_input_hidden':'',
			'muz_narozeni_sirka_stupne':str(abs(self.cob[0])).split('.')[0],
			'muz_narozeni_sirka_minuty':str(float('0.'+str(self.cob[0]).split('.')[1])*60).split('.')[0],
			'muz_narozeni_sirka_smer': '1' if self.cob[0]<0 else '0', #address N Dir (0':'N',1':'S)
			'muz_narozeni_delka_stupne':str(abs(self.cob[1])).split('.')[0], #address E - Main
			'muz_narozeni_delka_minuty':str(float('0.'+str(self.cob[1]).split('.')[1])*60).split('.')[0],
			'muz_narozeni_delka_smer': '1' if self.cob[1]<0 else '0', #address E Dir (0':'E',1':'W)
			'muz_narozeni_timezone_form':'auto',
			'muz_narozeni_timezone_dst_form':'auto',
			'send_calculation':'1',
			'zena_narozeni_den':self.p_dob[0],
			'zena_narozeni_mesic':self.p_dob[1],
			'zena_narozeni_rok':self.p_dob[2],
			'zena_narozeni_hodina':self.p_tob[0],
			'zena_narozeni_minuta':self.p_tob[1],
			'zena_narozeni_city':'',
			'zena_narozeni_mesto_hidden':'Manually+place%3A+%C2%B0%27N%2C+%C2%B0%27E',
			'zena_narozeni_stat_hidden':'XX',
			'zena_narozeni_podstat_kratky_hidden':'',
			'zena_narozeni_podstat_hidden':'',
			'zena_narozeni_podstat2_kratky_hidden':'',
			'zena_narozeni_podstat3_kratky_hidden':'',
			'zena_narozeni_input_hidden':'',
			'zena_narozeni_sirka_stupne':str(abs(self.p_cob[0])).split('.')[0],
			'zena_narozeni_sirka_minuty':str(float('0.'+str(self.p_cob[0]).split('.')[1])*60).split('.')[0],
			'zena_narozeni_sirka_smer': '1' if self.p_cob[0]<0 else '0',
			'zena_narozeni_delka_stupne':str(abs(self.p_cob[1])).split('.')[0],
			'zena_narozeni_delka_minuty':str(float('0.'+str(self.p_cob[1]).split('.')[1])*60).split('.')[0],
			'zena_narozeni_delka_smer': '1' if self.p_cob[1]<0 else '0',
			'zena_narozeni_timezone_form':'auto',
			'zena_narozeni_timezone_dst_form':'auto',
			'switch_interpretations':'0',
			'house_system':'placidus',
			'uhel_orbis':'#tabs_redraw'}

	def requestURL(self):
		# self.resp = requests.get(self.url, params=self.payload)
		self.resp = lr.get(self.url, params=self.payload, timeout=5, source=DEFAULT_SOURCE, verbose=True)
		# time.sleep(5)
		return self.resp

	def parsePage(self):
		self.horiscope = None
		# pdb.set_trace()
		if self.resp is None:
			pdb.set_trace()
		if('Please use valid date.' in self.resp['content']):
			self.issue = 'dob'
			return self.horiscope
		elif('Please use valid time.' in self.resp['content']):
			self.issue = 'tob'
			return self.horiscope
		gotLocation = 0
		self.horiscope = planetPositions()
		soup = BeautifulSoup(self.resp['content'], 'lxml')
		tcCell = soup.find_all('div', attrs={'class':'right-sedy-banner-svetlejsi'})
		for cell in tcCell:
			if "Planets in partner's house" in cell.get_text():
				gotLocation = 1
			divList = cell.find_all('div')
			for i in range(len(divList)):
				planetName = divList[i].getText().lower().strip().replace(':','').split(' ')[0]
				if planetName in planetPositions.planetNames:
					if gotLocation and not '/' in planetName:
						self.horiscope.planets[planetName].setHouse(divList[i+2].getText(),divList[i+4].getText())
					else:
						self.horiscope.planets[planetName].setLocation(divList[i+2].getText(),divList[i+1].img.attrs['alt'],0)
						self.horiscope.planets[planetName].setLocation(divList[i+4].getText(),divList[i+3].img.attrs['alt'],1)
					if planetName == 'node':
						self.horiscope.planets['southnode'].angleA = self.horiscope.planets['node'].angleA+180
						self.horiscope.planets['southnode'].angleB = self.horiscope.planets['node'].angleB+180
		vertex = requestVertex(None, self.payload)
		self.horiscope.planets['vertex'].setLocation(vertex[0][0],vertex[0][1],0)
		self.horiscope.planets['vertex'].setLocation(vertex[1][0],vertex[1][1],1)
		return self.horiscope

def parseVertex(content):
	soup = BeautifulSoup(content, 'lxml')
	tcCell = soup.find('div', attrs={'class':'detail-rozbor-obalka'})
	tableList = tcCell.find_all('table')[0]
	row = tableList.find_all('tr')[1]
	box = row.find_all('td')[2]
	num = box.getText()
	zone = box.img.attrs['alt']
	return num,zone

def slicedict(d, s):
	return {k.replace(s,''):v for k,v in d.iteritems() if k.startswith(s)}

def setVertexPayload(payload,isPartner):
	if isPartner:
		head = 'zena_'
	else:
		head = 'muz_'

	vPayload = slicedict(payload, head)
	vPayload['send_calculation'] = 1
	# pdb.set_trace()
	return vPayload 

def requestVertex(url,payload):
	resp = dict()
	vertex = dict()
	if url == None:
		url = 'https://horoscopes.astro-seek.com/calculate-vertex-sign/'
	for i in [0,1]: # 0 is individual, 1 is partner
		vPayload = setVertexPayload(payload,i)
		resp[i] = lr.get(url, params=vPayload, timeout=5, source=DEFAULT_SOURCE, verbose=True)
		# pdb.set_trace()
		vertex[i] = parseVertex(resp[i]['content'])
	# pdb.set_trace()
	return vertex

class planetRelation:
	noHouseList = ['asc','ic','dsc','mc','asc/mc','sun/moon','sNode']
	zodiacAngle = {'aries':0,'taurus':30,'gemini':60,'cancer':90,'leo':120,'virgo':150,'libra':180,'scorpio':210,'sagittarius':240,'capricorn':270,'aquarius':300,'pisces':330}

	def __init__(self,planetName):
		self.name = planetName
		self.angleA = None
		self.angleB = None
		if planetName not in planetRelation.noHouseList:
			self.houseA = None
			self.houseB = None

	def setLocation(self,value,sign,isB):
		signVal = planetRelation.zodiacAngle[sign.lower()]
		signVal+= float('.'.join(value.encode('ascii','replace').split('?'))[:-1])
		# print self.name,sign.lower(),planetRelation.zodiacAngle[sign.lower()],value,signVal
		if not isB:
			self.angleA = signVal
		else:
			self.angleB = signVal
		
	def setHouse(self,A,B):
		self.houseA = int(A.encode('ascii','ignore'))
		self.houseB = int(B.encode('ascii','ignore'))

	def test_random(self):
		self.angleA = random.random()*360
		self.angleB = random.random()*360


class planetPositions:
	aspectDict = {'conjunction':0,'semi-square':45,'sextile':60,'square':90,'trine':120,'opposition':180}
	aspectRange = {'conjunction':10,'semi-square':2,'sextile':4,'square':10,'trine':10,'opposition':10}
	reduceAspectPlanets = {'sun':10,'moon':10,'mercury':10,'venus':10,'mars':10,'jupiter':10,'saturn':10,'uranus':10,'neptune':10,'pluto':10,'node':10,'southnode':10,'lilith':10,'chiron':10,'asc':10,'ic':10,'dsc':10,'mc':10,'asc/mc':2,'sun/moon':2,'vertex':2}
	# zodiacAngle = {'aries':0,'taurus':30,'gemini':60,'cancer':90,'leo':120,'virgo':150,'libra':180,'scorpio':210,'sagittarius':240,'capricorn':270,'aquarius':300,'pisces':330}
	# Taken from https://en.wikipedia.org/wiki/Astrological_sign, with reference from https://en.wikipedia.org/wiki/Astrological_symbols#Signs_of_the_zodiac
	planetNames = ['sun','moon','mercury','venus','mars','jupiter','saturn','uranus','neptune','pluto','node','southnode','lilith','chiron','asc','ic','dsc','mc','asc/mc','sun/moon','vertex']
	def __init__(self):
		self.planets = {}
		for p in planetPositions.planetNames:
			self.planets[p] = planetRelation(p)
		self.aspect = {}

	def test_random(self):
		for planet in self.planets:
			self.planets[planet].test_random()

	def calcAngle(self,componentA,componentB):
		self.angle = abs(self.planets[componentA].angleA - self.planets[componentB].angleB)

	def calcAspect(self,componentA,componentB):
		self.calcAngle(componentA,componentB)
		for aspect in planetPositions.aspectDict:
			compareRange = min(self.aspectDict[aspect], self.reduceAspectPlanets[componentA])
			if self.angle-self.aspectRange[aspect] < compareRange and self.angle+self.aspectRange[aspect] > compareRange:
				aspectDiff = round(abs(self.angle - planetPositions.aspectDict[aspect]),2)
				self.aspect[componentA,componentB] = (aspect,aspectDiff)
				# print componentA,self.planets[componentA].angleA,componentB,self.planets[componentB].angleB,self.angle,aspect,aspectDiff
				return aspect,aspectDiff
		return None,None

	def isInHouse(self,component,houseNo):
		# print (self.planets[component].houseA,self.planets[component].houseB,houseNo)
		if (self.planets[component].houseA == houseNo) or (self.planets[component].houseB == houseNo):
			return True
		return False

	def makeAllAspectTreple(self):
		self.aspectTreple = {}
		for p1 in planetPositions.planetNames:
			for p2 in planetPositions.planetNames:
				aspect = self.calcAspect(p1,p2)[0]
				if aspect is not None:
					self.aspectTreple[(p1,p2,aspect)] = 1
		
	def calcAllAspects(self):
		for p1 in planetPositions.planetNames:
			for p2 in planetPositions.planetNames:
				self.calcAspect(p1,p2)

	def printPositions(self):
		for p in planetPositions.planetNames:
			if p in planetRelation.noHouseList:
				print p,self.planets[p].angleA,self.planets[p].angleB
			else:
				print p,self.planets[p].angleA,self.planets[p].angleB,self.planets[p].houseA,self.planets[p].houseB