Error in Google Custom Search API nexpage - python

Google Custom API search code I wrote
import time
from googleapiclient.discovery import build
# Google custom search API info
API_KEY = 'My Key'
API_ID = 'My ID'
def spider_next_page(service, index, searchterm_in, incl_searchterm_in, sitesearch_in):
time.sleep(1)
response = service.cse().list(
q=searchterm_in,
orTerms=incl_searchterm_in,
siteSearch=sitesearch_in,
cx=my_cse_id,
num=10,
start=index,
).execute()
nextPageIndex = response['queries']['nextPage'][0]['startIndex']
nextPageCount = response['queries']['nextPage'][0]['count']
for values_spider_next_page in response['items']:
itemsave.append(values_spider_next_page)
if nextPageIndex == 21:
pageno = ((nextPageIndex - 1) / 10)
print('Found', round(pageno), "Pages")
return
if nextPageCount != 0:
spider_next_page(service, nextPageIndex, searchterm_in, incl_searchterm_in, sitesearch_in)
def spider(searchterm_in, incl_searchterm_in, sitesearch_in):
service = build("customsearch", "v1",
developerKey=my_api_key)
res = service.cse().list(
q=searchterm_in,
orTerms=incl_searchterm_in,
siteSearch=sitesearch_in,
cx=my_cse_id,
).execute()
searchterm_in = res['queries']['request'][0]['searchTerms']
nextPageIndex = res['queries']['nextPage'][0]['startIndex']
nextPageCount = res['queries']['nextPage'][0]['count']
print('nextPageIndex', nextPageIndex)
print("Search Query:", searchterm_in)
print("Include Query :", incl_searchterm_in)
print("Target Site :", sitesearch_in)
for values_spider in res['items']:
itemsave.append(values_spider)
if nextPageCount != 0:
spider_next_page(service, nextPageIndex, searchterm_in, incl_searchterm_in, sitesearch_in)
return
if __name__ == '__main__':
my_api_key = API_KEY
my_cse_id = API_ID
itemsave = []
spider('men shorts', 'adidas', 'yahoo.com')
Normally, data can be obtained without errors, but sometimes the errors below occur.
Traceback (most recent call last):
File "D://Google_Search_API_0.4.py", line 122, in <module>
spider(f'{searchterm}', f'{incl_searchterm}', f'{sitesearch}')
File "D://Google_Search_API_0.4.py", line 70, in spider
nextPageIndex = res['queries']['nextPage'][0]['startIndex']
KeyError: 'nextPage'
It works in the following order.
spider('men shorts', 'adidas', 'yahoo.com') # input query (q,orTerms,siteSearch)
spider(searchterm_in, incl_searchterm_in, sitesearch_in): # first page -> get input query
spider_next_page(service, index, searchterm_in, incl_searchterm_in, sitesearch_in): # next page
If an error occurs, it occurs here.
def spider(searchterm_in, incl_searchterm_in, sitesearch_in):
...
--> nextPageIndex = res['queries']['nextPage'][0]['startIndex']
If I'm right, what's the problem? And why does it sometimes work without errors?

Maybe it is the end of data so there is no more nextPage.
You could use try/except to catch error and skip code.
Or you should run it in if 'nextPage' in res['queries']:
if 'nextPage' not in res['queries']:`
print("The End")
else:
nextPageIndex = response['queries']['nextPage'][0]['startIndex']
nextPageCount = response['queries']['nextPage'][0]['count']
for values_spider_next_page in response['items']:
itemsave.append(values_spider_next_page)
if nextPageIndex == 21:
pageno = ((nextPageIndex - 1) / 10)
print('Found', round(pageno), "Pages")
return
if nextPageCount != 0:
spider_next_page(service, nextPageIndex, searchterm_in, incl_searchterm_in, sitesearch_in)

Related

Python, SqlAlchemy. Or_ expected 2 arguments, got 3

I have this problem with my code. When Iinsert three or more params in the body request, I get this Error "POST Error: or_ expected 2 arguments, got 3."
I can only pass one or two parameters in the body, in this case it works fine. But I don't understand where is the mistake. Can someone help me?
def read_uptime(logid, filteredData, dateStart, dateEnd, timeStart, timeEnd, elementsForPage, currentPage, filterUptime):
log.info(f"{logid} read_uptime: Started")
try:
# Check Timeframe Correct
startDateTime, endDateTime = _checkDataInput(timeStart, timeEnd, dateStart, dateEnd)
# Create Filter
filters = _createFilter(filteredData, startDateTime, endDateTime, filterUptime)
# Query
dataFiltered = uptime_model_db.query.with_entities(
uptime_model_db.projectId.label('projectId'),
uptime_model_db.url.label('url'),
uptime_model_db.timeStamp.label('timeStamp'),
uptime_model_db.uptime.label('uptime'),
uptime_model_db.latency.label('latency')
).filter(*filters).paginate(per_page=int(elementsForPage + 1), page=int(currentPage), error_out=True)
# Checking more pages
nextPage = {
"currentPage": currentPage,
"totalElements": len(dataFiltered.items)
}
if (len(dataFiltered.items) > elementsForPage):
nextPage["nextPage"] = True
else:
nextPage["nextPage"] = False
# Format and return JSON
return _createJson(dataFiltered.items, nextPage)
except Exception as e:
log.error(f"{logid} read_uptime: function read_uptime returned {e}")
raise e
i get in this code the mistake: "array.Filter.append(and_(uptime_model.db.porjectId == projectId, or_(*arrayUrl))"
def filterAppend(arrayFilter, urls, projectId, arrayUrl):
if(len(urls) == 1):
arrayFilter.append(and_(uptime_model_db.projectId == projectId, uptime_model_db.url == urls[0]))
if(len(urls) > 1):
for url in urls:
arrayUrl.append(uptime_model_db.url == url)
arrayFilter.append(and_(uptime_model_db.projectId == projectId, or_(*arrayUrl)))
i get in this code the mistake:
"filters.append(or_(*arrayFilter))"
def _createFilter(filteredData, startDateTime, endDateTime, filterUptime):
filters = []
if filteredData is not None:
arrayFilter = []
for data in filteredData:
projectId = data["projectId"]
urls = data["uptimeUrls"]
arrayUrl = []
if (len(filteredData) == 1):
filterAppend(filters, urls, projectId, arrayUrl)
else:
filterAppend(arrayFilter, urls, projectId, arrayUrl)
if(len(filteredData) > 1 or len(arrayFilter) > 1):
filters.append(or_(*arrayFilter))
if startDateTime is not None:
filters.append(str(startDateTime) <= uptime_model_db.timeStamp)
if startDateTime is not None:
filters.append(str(endDateTime) >= uptime_model_db.timeStamp)
if filterUptime == "True":
filters.append(uptime_model_db.uptime < 100)
return filters
import or_ from sqlalchemy instead of operators:
from sqlalchemy import or_

‘module’ object has no attribute ‘MStatus' in Maya python Api 2020

I am trying to build a command in python for Maya following a course on youtube and it's showing this error "# Error: RuntimeError: file line 2: AttributeError: file C:/Users/saeed/OneDrive/Documents/maya/2020/Plugins/vertexParticle.py line 23: 'module' object has no attribute 'MStatus' # "
I checked Maya API documents and we should have "MStatus" class but I have no idea why it's not accepted, I tried to use "MStatusCode" and it's showing same error.
from maya import OpenMaya
from maya import OpenMayaMPx
from maya import OpenMayaFX
import sys
commandName = "vertexParticle"
kHelpFlag = "-h"
kHelpLongFlag = "-help"
kSparseFlag = "-s"
kSparseLongFlag = "-sparse"
helpMessage = "This command will attach a particle for each vertex"
class pluginCommand(OpenMayaMPx.MPxCommand):
sparse = None
def __init__(self):
OpenMayaMPx.MPxCommand.__init__(self)
def argumentParser(self, argList):
syntax = self.syntax()
parserArguments = OpenMaya.MArgDatabase(syntax, argList)
if parserArguments.isFlagSet(kSparseFlag):
self.sparse = parserArguments.flagArgumentDouble(kSparseFlag, 0)
return OpenMaya.MStatus.kSuccess
if parserArguments.isFlagSet(kSparseLongFlag):
self.sparse = parserArguments.flagArgumentDouble(kSparseLongFlag, 0)
return OpenMaya.MStatus.kSuccess
if parserArguments.isFlagSet(kHelpFlag):
self.setResult(helpMessage)
return OpenMaya.MStatus.kSuccess
if parserArguments.isFlagSet(kHelpLongFlag):
self.setResult(helpMessage)
return OpenMaya.MStatus.kSuccess
def isUndoable(self):
return True
def undoIt(self):
print "undo"
mFnDagNode = OpenMaya.MFnDagNode(self.mObjParticle)
mDagMod = OpenMaya.MDagModifier()
mDagMod.deleteNode(mFnDagNode.parent(0))
mDagMod.doIt()
return OpenMaya.MStatus.kSuccess
def redoIt(self):
mSel = OpenMaya.MSelectionList()
mDagPath = OpenMaya.MDagPath()
mFnMesh = OpenMaya.MFnMesh()
OpenMaya.MGlobal.getActiveSelectionList(mSel)
if mSel.length() >= 1:
try:
mSel.getDagPath(0, mDagPath)
mFnMesh.setObject(mDagPath)
except:
print "please select a poly mesh"
return OpenMaya.MStatus.kUnknownParameter
else:
print "please select a poly mesh"
return OpenMaya.MStatus.kUnknownParameter
mPointArray = OpenMaya.MPointArray()
mFnMesh.getPoints(mPointArray, OpenMaya.MSpace.kWorld)
mFnParticle = OpenMayaFX.MFnParticleSystem()
self.mObjParticle = mFnParticle.create()
mFnParticle = OpenMayaFX.MFnParticleSystem(self.mObjParticle)
counter == 0
for i in xrange(mPointArray.length()):
if i%self.sparse == 0:
mFnParticle.emit(mPointArray[i])
counter += 1
print "total points :" + str(counter)
mFnParticle.saveInitialState()
return OpenMaya.MStatus.kSuccess
def doIt(self, argList):
self.argumentParser(argList)
if self.sparse != None:
self.redoIt()
return OpenMaya.MStatus.kSuccess
def cmdCreator():
return OpenMayaMPx.asMPxPtr(pluginCommand())
def syntaxCreator():
syntax = OpenMaya.MSyntax()
syntax.addFlag(kHelpFlag, kHelpLongFlag)
syntax.addFlag(kSparseFlag, kSparseLongFlag, OpenMaya.MSyntax.kDouble)
return syntax
def initializePlugin(mObject):
mPlugin = OpenMayaMPx.MFnPlugin(mObject)
try:
mPlugin.registerCommand(commandName, cmdCreator, syntaxCreator)
except:
sys.stderr.write("Failed to register" + commandName)
def uninitializePlugin(mObject):
mPlugin = OpenMayaMPx.MFnPlugin(pluginCommand())
try:
mPlugin.deregisterCommand(commandName)
except:
sys.stderr.write("Failed to deregister" + commandName)
Because MStatus.MStatusCode is an enum, you can return its integer value in Python. The only issue is that because in C++ this is an enum, there is no guarantee that the values won't change/shift between releases. This enum has remained consistent since 2019, so there isn't much risk of this happening for MStatus.MStatusCode.
https://help.autodesk.com/view/MAYAUL/2019/ENU/?guid=__cpp_ref_class_m_status_html
https://help.autodesk.com/view/MAYAUL/2023/ENU/?guid=Maya_SDK_cpp_ref_class_m_status_html
Somewhere in the top of your file simply add the constants you intend to use:
MStatus_kSuccess = 0
MStatus_kFailure = 1
MStatus_kUnknownParameter = 5
Then return the constant instead in your functions:
if parserArguments.isFlagSet(kHelpFlag):
self.setResult(helpMessage)
return MStatus_kSuccess

Python concurrent.future not running in Parallel

I am writing code for querying CMDB data from ServiceNow through REST API calls using python. To gain results faster I am using concurrent.future module of python to allow parallel query executions.
Below is the code and output:
import requests
import os
import base64
import threading
import concurrent.futures
import datetime
class ServiceNowAPI:
__ServiceNowUserName = os.environ.get('ServiceNow_USERNAME')
__ServiceNowPassword = None
__ServiceNowPasswordProd = None
__BASE_URL = None
__WSI_URL = 'https://esiocecr.contoso.com:9443/rsrv_servicenow-outbound/'
__ServiceNow_Cert_Path = 'C:\Certificates\OSMCert.pem'
# ServiceNow API URL paths
__GET_CI_DETAILS = "/api/now/table/cmdb_ci_circuit?sysparm_query=u_port_circuit_idLIKE__CINAME__^ORnameLIKE__CINAME__&sysparam_fields=*"
def __init__(self, ServiceNowEnvironment):
self.ServiceNowEnvironment = ServiceNowEnvironment
self.__ServiceNowPassword = os.environ.get('ServiceNow_PROD_PWD') if ServiceNowEnvironment.lower() == "prod" or ServiceNowEnvironment.lower() == "production" else os.environ.get('ServiceNow_EAGLE_PWD')
self.__BASE_URL = "https://contososervicenow.service-now.com" if ServiceNowEnvironment.lower() == "prod" or ServiceNowEnvironment.lower() == "production" else "https://contosoeagle.service-now.com"
CredsPair = "{0}:{1}".format(self.__ServiceNowUserName, self.__ServiceNowPassword)
CredBytes = CredsPair.encode('ascii')
Base64Creds = base64.b64encode(CredBytes).decode('utf-8')
self.__Authorization = "Basic {0}".format(Base64Creds)
def _GetRouterName(self, RouterLink):
RouterName = ''
with requests.Session() as ServiceNowCall:
ServiceNowCall.headers.update({ 'Authorization': self.__Authorization, 'content-type': 'application/json', 'DP_EXTERNAL_URL': RouterLink})
ServiceNowCall.cert = self.__ServiceNow_Cert_Path
ServiceNowCall.verify = self.__ServiceNow_Cert_Path
with ServiceNowCall.get(self.__WSI_URL) as ResponseObject:
ResponseJSON = ResponseObject.json()
Results = ResponseJSON['result']
RouterName = Results['name']
return RouterName
def _GetCircuitCIDetails(self, CircuitID):
print('Started for ' + CircuitID + ' at ' + datetime.datetime.now().strftime("%d-%b-%Y %H:%M:%S.%f"))
ResponseJSON = ''
URL = "{0}{1}".format(self.__BASE_URL, self.__GET_CI_DETAILS.replace('__CINAME__', CircuitID))
with requests.Session() as ServiceNowCall:
ServiceNowCall.headers.update({ 'Authorization': self.__Authorization, 'content-type': 'application/json', 'DP_EXTERNAL_URL': URL})
ServiceNowCall.cert = self.__ServiceNow_Cert_Path
ServiceNowCall.verify = self.__ServiceNow_Cert_Path
with ServiceNowCall.get(self.__WSI_URL) as ResponseObject:
ResponseJSON = ResponseObject.json()
AllRecords = list(ResponseJSON['result'])
ActiveRecord = [rec for rec in AllRecords if rec['u_lifecycle_status'] != 'end of life'][0]
Router_Name = self._GetRouterName(ActiveRecord['u_router_name']['link'])
Results = {
'Name': ActiveRecord['name'],
'CarrierName': ActiveRecord['u_carrier_name'],
'NetworkType': ActiveRecord['u_network_type'],
'NetworkSubType': ActiveRecord['u_network_sub_type'],
'RouterName': Router_Name,
'PortCircuitID': ActiveRecord['name'],
'AccessCircuitID': ActiveRecord['u_port_circuit_id']
}
print('Finished ' + CircuitID + ' at ' + datetime.datetime.now().strftime("%d-%b-%Y %H:%M:%S.%f"))
yield Results
def GetCIDetails(self, CICSV):
CircuitDetails = []
CircuitIDList = [Circuit.strip() for Circuit in CICSV.split(',')]
CircuitDetails = []
with concurrent.futures.ThreadPoolExecutor() as executor:
CIDetailsResult = { executor.submit(self._GetCircuitCIDetails, CircuitID): CircuitID for CircuitID in CircuitIDList }
for future in concurrent.futures.as_completed(CIDetailsResult):
CircuitCI = CIDetailsResult[future]
try:
CurrentResult = future.result()
except Exception as exc:
ErrorResult = dict({ 'Name': CircuitCI, 'CarrierName': 'NA', 'NetworkType': 'NA', 'NetworkSubType': 'NA', 'RouterName': 'NA', 'PortCircuitID': 'Error', 'AccessCircuitID': 'Error'})
CircuitDetails.extend(ErrorResult)
else:
CircuitDetails.extend(CurrentResult)
return CircuitDetails
if __name__ == "__main__":
ServiceNowAPIClass = ServiceNowAPI('NONPROD')
CIDetails = ServiceNowAPIClass.GetCIDetails('Circuit1,Circuit2')
print(CIDetails)
Output:
Started for Circuit1 at 30-Apr-2022 13:40:06.784841
Finished Circuit1 at 30-Apr-2022 13:40:09.749164
Started for Circuit2 at 30-Apr-2022 13:40:09.751166
Finished Circuit2 at 30-Apr-2022 13:40:12.479171
[{'Name': 'Circuit1', 'CarrierName': 'CenturyLink', 'NetworkType': 'EU-BTM', 'NetworkSubType': 'N/A', 'RouterName': 'RT1234ABCD03', 'PortCircuitID': 'Circuit1', 'AccessCircuitID': 'Circuit1'}, {'Name': 'Circuit2', 'CarrierName': 'Verizon', 'NetworkType': 'DPS-NA', 'NetworkSubType': 'N/A', 'RouterName': 'RT12345678ABC', 'PortCircuitID': 'Circuit2', 'AccessCircuitID': 'Circuit2'}]
However, as you can see the executions are not happening in Parallel. It is finishing the queries for each circuit one after another.
How can I fix this to run the _GetCircuitCIDetails(self, CircuitID) function against all CircuitIDs in parallel?

How can i drop table after finish my scenario?

i have a problem with drop table after finish my scenario
when I try to delete using db.drop_table(Routes, if_exists=False, with_all_data=False) or db.drop_table(Routes, if_exists=True, with_all_data=True)
i get an error
pony.orm.core.TransactionError: #db_session-decorated drop_table() function with ddl option cannot be called inside of another db_sessio
i try to delete using Routes.delete() and I got the same one
i read more documentation and i dont know how can i drop this table
my full code
import logging
import random
import requests
import vk_api
from pony.orm import db_session, rollback
from vk_api.bot_longpoll import VkBotLongPoll, VkBotEventType
import handlers
from models import UserState, Registration, Routes, db
try:
import settings
except ImportError:
exit('DO CP settings.py.default setting.py and set token')
log = logging.getLogger('bot')
def configure_logging():
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(logging.Formatter('%(levelname)s %(message)s'))
stream_handler.setLevel(logging.INFO)
log.addHandler(stream_handler)
file_handler = logging.FileHandler('bot.log')
file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s'))
file_handler.setLevel(logging.DEBUG)
log.addHandler(file_handler)
class Bot:
"""
Echo bot for vk.com
Use python 3.7
"""
def __init__(self, group_id, token):
"""
:param group_id:group_id from group vk.com
:param token:secret key
"""
self.group_id = group_id
self.token = token
self.vk = vk_api.VkApi(token=self.token)
self.long_poller = VkBotLongPoll(self.vk, self.group_id)
self.api = self.vk.get_api()
def run(self):
"""run bot"""
for event in self.long_poller.listen():
try:
print(event)
self.on_event(event)
except Exception:
log.exception('ошибка в обработке события')
#db_session
def on_event(self, event):
"""
sends the message back, if message text
:param event: VKBotMessageEvent object
:return: None
"""
if event.type != VkBotEventType.MESSAGE_NEW:
log.info('пока не умеем работать с таким типом события %s', event.type)
return
user_id = event.message.peer_id
text = event.message.text
state = UserState.get(user_id=str(user_id))
if state is not None:
self.continue_scenario(text=text, state=state, user_id=user_id)
else:
# search intent, the user is found outside of the scenario
for intent in settings.INTENTS:
log.debug(f'User gets {intent}')
if any(token in text.lower() for token in intent['tokens']):
# run intent
if intent['answer']:
self.send_text(text_to_send=intent['answer'], user_id=user_id)
else:
self.start_scenario(scenario_name=intent['scenario'], user_id=user_id, text=text)
break
else:
self.send_text(text_to_send=settings.DEFAULT_ANSWER, user_id=user_id)
# функция отправки текста
def send_text(self, text_to_send, user_id):
self.api.messages.send(
message=text_to_send,
random_id=random.randint(0, 2 ** 20),
peer_id=user_id)
# функция отправки изображения
def send_image(self, image, user_id):
upload_url = self.api.photos.getMessagesUploadServer()['upload_url']
upload_data = requests.post(url=upload_url, files={'photo': ('image.png', image, 'image/png')}).json()
image_data = self.api.photos.saveMessagesPhoto(**upload_data)
owner_id = image_data[0]['owner_id']
media_id = image_data[0]['id']
attachment = f'photo{owner_id}_{media_id}'
self.api.messages.send(
attachment=attachment,
random_id=random.randint(0, 2 ** 20),
peer_id=user_id)
# функция отправки маршрутов
def send_routes(self, text_to_send, user_id):
self.api.messages.send(
message=text_to_send,
random_id=random.randint(0, 2 ** 20),
peer_id=user_id)
# шаг отправки
def send_step(self, step, user_id, text, context):
if 'text' in step:
self.send_text(text_to_send=step['text'].format(**context), user_id=user_id)
if 'image' in step:
handler = getattr(handlers, step['image'])
image = handler(text=text, context=context)
self.send_image(image=image, user_id=user_id)
if 'choice' in step:
handler = getattr(handlers, step['choice'])
choices = handler(text=text, context=context)
for i, choice in enumerate(choices, start=1):
city_from = context['city_from']
city_to = context['city_to']
flight_time = choice[city_from][city_to][0]
flight_board = choice[city_from][city_to][1]
flight_date = choice[city_from][city_to][2]
number_choice = str(i) + ') '
Routes(number_choice=number_choice, flight_time=flight_time, city_from=city_from, city_to=city_to,
flight_board=flight_board, flight_date=flight_date)
select = db.select('number_choice,flight_time,city_from,city_to,flight_board,flight_date FROM Routes')
text_to_send = ' '.join(select[0]) + '\n' + ' '.join(select[1]) + '\n' + ' '.join(
select[2]) + '\n' + ' '.join(
select[3]) + '\n' + ' '.join(select[4]) + '\n'
self.send_routes(text_to_send=text_to_send, user_id=user_id)
# начало сценария
def start_scenario(self, scenario_name, user_id, text):
scenario = settings.SCENARIOS[scenario_name]
first_step = scenario['first_step']
step = scenario['steps'][first_step]
self.send_step(step=step, user_id=user_id, text=text, context={})
UserState(user_id=str(user_id), scenario_name=scenario_name, step_name=first_step, context={})
# конец сценария
def continue_scenario(self, text, state, user_id):
steps = settings.SCENARIOS[state.scenario_name]['steps']
step = steps[state.step_name]
handler = getattr(handlers, step['handler'])
if handler(text=text, context=state.context):
# next_step
if step['handler'] != 'handler_answer':
self.walking_through_scenario(state=state, step=step, steps=steps, text=text, user_id=user_id)
else:
if state.context['answer'] == 'да':
self.walking_through_scenario(state=state, step=step, steps=steps, text=text, user_id=user_id)
else:
next_step = step['failure_step']
state.delete()
self.send_step(step=step, user_id=user_id, text=text, context={})
UserState(user_id=str(user_id), scenario_name=state.scenario_name, step_name=next_step, context={})
else:
# retry_current_step
text_to_send = step['failure_text'].format(**state.context)
self.send_text(text_to_send=text_to_send, user_id=user_id)
# движения по сценарию
def walking_through_scenario(self, state, step, steps, text, user_id):
next_step = steps[step['next_step']]
self.send_step(step=next_step, user_id=user_id, text=text, context=state.context)
if next_step['next_step']:
# switch to next step
state.step_name = step['next_step']
else:
# finish scenario and delete user states
log.info(
'Зарегистрирован пользователь ФИО {name} следует из {city_from} в {city_to} телефон для контактов {phone} '.format(
**state.context))
Registration(name=state.context['name'], city_from=state.context['city_from'],
city_to=state.context['city_to'],
phone=state.context['phone'])
state.delete()
if __name__ == '__main__':
configure_logging()
bot = Bot(group_id=settings.GROUP_ID, token=settings.TOKEN)
bot.run()
it helped me this command Routes.select(lambda p: p.id > 0 ).delete(bulk=True)

Using the Dragonly package for NatSpeak, how do I define a CompoundRule that is both a standalone rule and can also be used by other CompoundRules?

I am working on a module for vim. Currently I have the following code:
alphabet_rule = Sequence([Repetition(RuleRef(name="x", rule=MappingRule(name="t", mapping=ALPHABET)), min=1, max=20)])
numbers_rule = Sequence([Repetition(RuleRef(name="y", rule=MappingRule(name="u", mapping=DIGITS)), min=1, max=20)])
symbols_rule = Sequence([Repetition(RuleRef(name="z", rule=MappingRule(name="v", mapping=SYMBOLS)), min=1, max=20)])
alphanumeric = [alphabet_rule, numbers_rule, symbols_rule]
class FindRule(CompoundRule):
spec = ("(bind | find | tank | bank) <alphanumeric> [<n>]")
extras = [IntegerRef("n", 1, 10), Alternative(alphanumeric, name="alphanumeric")]
defaults = {"n": 1}
def value(self, node, extras):
words = node.words()
rule = words[0]
times = extras["n"]
print words
print "Times: %d" % times
find = Events('key->key=%d;key->key=f' % times)
bind = Events('key->key=%d;key->key=f&modifier=shift' % times)
bank = Events('key->key=%d;key->key=t&modifier=shift' % times)
tank = Events('key->key=%d;key->key=t' % times)
search = extras["alphanumeric"][0][0]
if rule == 'bind':
return (bind + search)
elif rule == 'find':
return (find + search)
elif rule == 'bank':
return (bank + search)
elif rule == 'tank':
return (tank + search)
def _process_recognition(self, node, extras):
self.value(node, extras).execute()
find_rule = RuleRef(name="find_rule", rule=FindRule(name="i"))
class ClipRule(CompoundRule):
spec = ("(clip | dip) <find_rule>")
extras = [find_rule]
def _process_recognition(self, node, extras):
words = node.words()
if words[0] == 'clip':
action = Events('key->key=c')
elif words[0] == 'dip':
action = Events('key->key=d')
(action + extras["find_rule"]).execute()
The code is here to give an idea of what I am trying to do, since it's not runnable w/out all the bells and whistles of dragonfly and some of the ALPHABETS, DIGITS, and SYMBOLS that I've defined.
I can use the FindRule just as I expect, but when I attempt to use the ClipRule, I get the following error:
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\dragonfly\engines\engine_natlink.py", line 248, in results_callback
r.process_recognition(root)
File "C:\Python27\lib\site-packages\dragonfly\grammar\rule_compound.py", line 143, in process_recognition
self._process_recognition(node, extras)
File "C:\NatLink\NatLink\MacroSystem\_vim.py", line 232, in _process_recognition
(action + extras["find_rule"]).execute()
File "C:\Python27\lib\site-packages\dragonfly\actions\action_base.py", line 84, in __add__
copy.append(other)
File "C:\Python27\lib\site-packages\dragonfly\actions\action_base.py", line 79, in append
assert isinstance(other, ActionBase)
AssertionError
When I do => print extras['find_rule'] in ClipRule._process_recognition, I get 'None'. I assume this means that I have incorrectly overridden the value method in FindRule. Wondering if anyone else has had some experience with this. Thanks

Categories

Resources