Repository navigation
Migration guide
This page describes what you have to change in your code when you update the eventregistry package to a new major version. It covers the two latest major versions:
If you are updating from version 9 directly to version 11, go through both sections. The complete list of changes of each version is in the change log.
To see which version you have installed:
import eventregistry
print(eventregistry.__version__)v10 to v11
- You use Python 3.9 or newer.
- Scripts that use
from eventregistry import *importdatetime,json,time,os, ... themselves. - Loops over
QueryArticlesIter,QueryEventsIter,QueryMentionsIterandQueryEventArticlesIter(and calls of theircount()) handleQueryError. - Calls of
execQuery()on the iterator classes and ofRequestEventArticles()use only existing argument names (a misspelled one now raises aTypeError). - The arguments of the
*InfoFlagsclasses are spelled with the right letter case (bodyLen, notbodylen). - If you relied on the package to set up logging or on the
LOGLEVELenvironment variable, you configure theloggingmodule yourself. - If you relied on failed requests being repeated forever, you create
EventRegistry(repeatFailedRequestCount = -1)- or, better, handle the exceptions. - Code that inspected the text of the raised exception uses the typed exceptions and their
statusCodeinstead. - Code that compared the sent time values with strings that contain a timezone offset expects UTC without the offset.
-
GetTopSharedArticles,GetTopSharedEventsandRequestMentionsConceptGraphare not used.
v9 to v10
- You use Python 3 (Python 2 is not supported anymore).
-
except AssertionErroraround calls of the package is replaced withexcept (TypeError, ValueError). -
RequestEventsEventClustersand theAnalytics.trainTopic*()methods are not used. -
EventRegistry.getArticleUris()is called with a single URL. -
RequestArticlesInfoandRequestMentionsInfoare created withcountof at most 100. - The iterator classes are iterated only after calling
execQuery(). - If you depended on the old default hosts, or on
settings.json/ the request log being in the package folder, you checked the new defaults.
Version 10 supported Python 3.8. Update Python, or stay with pip install "eventregistry<11" on Python 3.8.
Before, the star import also brought along the modules that the package uses itself (datetime, json, os, time, re, requests, ...). This could overwrite names in your code, for example a datetime imported with from datetime import datetime. Now only the public classes, functions and constants of the package are imported.
What to do: import the standard modules that your script uses.
# before: datetime came from the star import
from eventregistry import *
q = QueryArticles(keywords = "Tesla", dateStart = datetime.date(2026, 9, 1))# after
import datetime
from eventregistry import *
q = QueryArticles(keywords = "Tesla", dateStart = datetime.date(2026, 9, 1))A missing import shows up as NameError: name 'datetime' is not defined.
When the server returned an error (for example because of an invalid URI in the query), the iterator classes only logged it and the iteration ended as if there were no (more) results; count() returned 0. Now a QueryError is raised, both while iterating and in count().
What to do: decide what should happen when the query fails, and catch the exception where needed.
# before: an error looked the same as "no results"
from eventregistry import *
er = EventRegistry(apiKey = YOUR_API_KEY)
q = QueryArticlesIter(conceptUri = er.getConceptUri("Tesla"))
for art in q.execQuery(er, sortBy = "date", maxItems = 500):
print(art["title"])# after
from eventregistry import *
er = EventRegistry(apiKey = YOUR_API_KEY)
q = QueryArticlesIter(conceptUri = er.getConceptUri("Tesla"))
try:
for art in q.execQuery(er, sortBy = "date", maxItems = 500):
print(art["title"])
except QueryError as ex:
print("The query failed:", ex)The execQuery() methods of the iterator classes accepted arbitrary keyword arguments and silently ignored them, so a misspelled argument had no effect. The same was true for RequestEventArticles. Now an unknown argument raises a TypeError.
What to do: fix the name of the argument. The accepted arguments of execQuery() are sortBy, sortByAsc, returnInfo and maxItems.
# before: "sortby" was ignored and the articles were sorted by relevance
for art in q.execQuery(er, sortby = "date", maxItems = 100):
print(art["title"])# after
for art in q.execQuery(er, sortBy = "date", maxItems = 100):
print(art["title"])Conditions that limit the articles of an event (keywords, sources, language, ...) are given to the constructor of QueryEventArticlesIter, not to execQuery():
# after
iter = QueryEventArticlesIter("eng-2940883", lang = "eng", keywords = "Obama")
for art in iter.execQuery(er, sortBy = "date"):
print(art["title"])The *InfoFlags classes (ArticleInfoFlags, ConceptInfoFlags, ...) send unknown keyword arguments to the server as they are, and the server ignores the flags that it does not know. Now an argument that differs from a known one only in the letter case raises a TypeError, and for other unknown arguments a warning is logged (they are still sent to the server). The full names of the API parameters (starting with include) are accepted without a warning.
# before: no effect - the full body was returned
info = ReturnInfo(articleInfo = ArticleInfoFlags(bodylen = 500))# after ("bodylen" raises a TypeError)
info = ReturnInfo(articleInfo = ArticleInfoFlags(bodyLen = 500))Before, the package added its own handler to the eventregistry logger and read the logging level from the LOGLEVEL environment variable. As a library it now leaves the configuration to the application. Warnings and errors are still printed by default (by Python itself), but info and debug messages are shown only if you configure the logging.
# before: the level was set with the LOGLEVEL environment variable, e.g. LOGLEVEL=DEBUG
from eventregistry import *
er = EventRegistry(apiKey = YOUR_API_KEY)# after
import logging
from eventregistry import *
logging.basicConfig(level = logging.INFO)
logging.getLogger("eventregistry").setLevel(logging.DEBUG)
er = EventRegistry(apiKey = YOUR_API_KEY)A datetime with a timezone is converted to UTC and sent without the offset (2026-10-02T04:30:00 instead of 2026-10-02T04:30:00+00:00). A datetime without a timezone is considered to be in UTC, as before. For date conditions (dateStart, dateEnd, ...) the UTC date of a timezone-aware datetime is used (before, its local date was used). Strings with Z or an offset ("2026-10-02T06:30:00+02:00") are now accepted where a time is expected.
What to do: usually nothing. If you passed timezone-aware datetimes, check that the conversion to UTC is what you want; if your code inspects the query parameters (for example in tests), expect the new format.
# before: sent as 2026-10-02T06:30:00+02:00
# after: sent as 2026-10-02T04:30:00
import datetime
from eventregistry import *
tz = datetime.timezone(datetime.timedelta(hours = 2))
req = RequestArticlesRecentActivity(updatesAfterTm = datetime.datetime(2026, 10, 2, 6, 30, tzinfo = tz))The default value of the repeatFailedRequestCount parameter of EventRegistry changed from -1 (repeat indefinitely) to 3. In addition:
- only temporary errors are repeated: status 5xx, a response that is not valid json, connection problems and timeouts. Before, every status code except 204, 400, 401 and 403 was repeated (for example also 404 and 422);
- status 429 (too many simultaneous requests) is still repeated until the request succeeds, regardless of
repeatFailedRequestCount; - the delay before a repeat grows exponentially (2, 4, 8, ... seconds, at most 60) instead of a fixed 5 seconds, and follows the
Retry-Afterheader of the server when present.
What to do: a script that ran unattended and relied on the package to wait until the service is reachable again will now get an exception after about 14 seconds of waiting (2 + 4 + 8). Handle the exception, increase the number of repeats, or restore the old behavior:
# before: repeated forever by default
from eventregistry import *
er = EventRegistry(apiKey = YOUR_API_KEY)# after: the old behavior has to be requested
from eventregistry import *
er = EventRegistry(apiKey = YOUR_API_KEY, repeatFailedRequestCount = -1)A failed request used to raise a plain Exception with the status code in its text. Now the exceptions are subclasses of EventRegistryError: NoDataError (204), InvalidRequestError (400 and other 4xx), UnauthorizedError (401) and ForbiddenError (403) (both are AccessError), RateLimitError (429), ServerError (5xx), InvalidResponseError (invalid json) and NetworkError (connection problems and timeouts). They have the statusCode, responseText, url and retryAfter attributes. The requests of the Analytics class raise the same exceptions.
What to do: nothing, if you catch Exception - the new exceptions derive from it. Code that looked for the status code in the text of the exception should use the exception classes or the statusCode attribute. Code that caught the exceptions of the requests library (e.g. requests.exceptions.ConnectionError) around calls of the package should catch NetworkError.
# before
try:
res = er.execQuery(q)
except Exception as ex:
if "401" in str(ex) or "403" in str(ex):
print("no more tokens")
else:
raise# after
try:
res = er.execQuery(q)
except AccessError as ex:
print("no more tokens:", ex.responseText)See Errors and troubleshooting for the details.
execQuery() of the iterator classes returned the query object itself; now it returns a separate iterator (QueryResultsIter) and the query is not changed by iterating. The usual code (for art in q.execQuery(er):) works as before, and iterating over the query object after calling execQuery() still works too. The new behavior makes it possible to execute the same query several times, also at the same time:
# after: two independent iterations over the same query
newest = q.execQuery(er, sortBy = "date", maxItems = 10)
mostRelevant = q.execQuery(er, sortBy = "rel", maxItems = 10)
for artNew, artRel in zip(newest, mostRelevant):
print(artNew["title"], "|", artRel["title"])What to do: only code that called methods of the query on the value returned by execQuery() has to be changed - call them on the query object.
The data about the shares on social media is no longer collected and the server ignores sorting by the social score, so GetTopSharedArticles and GetTopSharedEvents did not return the most shared content anymore - only the articles or events of the given day in no particular order. RequestMentionsConceptGraph was never supported by the server and only returned an error.
What to do: if you need the articles or the events of a day, search for them with QueryArticles / QueryEvents and the dateStart and dateEnd conditions.
# before
q = GetTopSharedArticles(date = "2026-10-01", count = 30)
# after
q = QueryArticles(dateStart = "2026-10-01", dateEnd = "2026-10-01",
requestedResult = RequestArticlesInfo(count = 30, sortBy = "sourceImportance"))-
QueryEventssent theignoreKeywordscondition with a wrong parameter name. It is fixed, so queries for events that useignoreKeywordscan now return fewer events. -
QueryEventArticlesIterreplaced theQueryItems.OR()/QueryItems.AND()operators of the conditions with the default ones. The operators that you specify are now used. - An empty list (or an empty
QueryItems) given as a condition is ignored instead of being sent to the server. - The example file
examples/QueryMentions.pywas renamed toQueryMentionsExamples.py. The example files now contain functions and make no requests when they are imported or run without arguments.
None of these require a change, but they can simplify your code:
- The API key can be given with the
EVENTREGISTRY_API_KEYenvironment variable - see Authorization. -
er.execQuery(q, raiseOnError = True)raises aQueryErrorwhen the server returns an error instead of the results. -
GetRecentArticlesandGetRecentEventsaccept the conditions as named parameters - see Feed of new articles/events.
# before: raw API parameters
recentQ = GetRecentArticles(er, recentActivityArticlesMaxArticleCount = 200, conceptUri = er.getConceptUri("Tesla"))# after: named parameters, validated in the same way as in QueryArticles
recentQ = GetRecentArticles(er, maxArticleCount = 200, conceptUri = er.getConceptUri("Tesla"))-
TopicPage.getArticles()andgetEvents()have theuri,onlyAfterTmandmaxDaysBackparameters - see Topic pages. - New result types:
RequestArticlesLangAggr,RequestArticlesSentimentAggr,RequestArticlesAuthorAggr,RequestArticlesLocAggr,RequestArticlesSourceExAggr,RequestEventsSentimentAggrandRequestEventsAuthorAggr. -
BaseQueryhas thekeywordSearchModeparameter. - The package contains type information (
py.typed), so type checkers such asmypyuse its type hints.
Version 10.0 requires Python 3.8 or newer (version 11.0 requires Python 3.9). The six and pytz dependencies were removed - if your own code imports them, add them to your own requirements. If you have to stay on Python 2, use pip install "eventregistry<10".
The arguments were checked with assert statements. Now a wrong type raises a TypeError and an invalid value raises a ValueError (also when Python runs with the -O option, which removes the asserts).
# before
try:
q = QueryArticles(keywords = "Tesla", minSentiment = -2)
except AssertionError:
print("invalid query")# after
try:
q = QueryArticles(keywords = "Tesla", minSentiment = -2)
except (TypeError, ValueError) as ex:
print("invalid query:", ex)The result type is not available anymore.
# before
q = QueryEvents(conceptUri = er.getConceptUri("Obama"))
q.setRequestedResult(RequestEventsEventClusters())What to do: remove its use. To get an overview of a larger set of events, use one of the aggregates instead, for example the top concepts or categories of the events:
# after
q = QueryEvents(conceptUri = er.getConceptUri("Obama"))
q.setRequestedResult(RequestEventsConceptAggr(conceptCount = 50))
res = er.execQuery(q)Analytics.trainTopicOnTweets(), trainTopicCreateTopic(), trainTopicClearTopic(), trainTopicAddDocument() and trainTopicGetTrainedTopic() were removed. There is no replacement in the Analytics class.
# before
analytics = Analytics(er)
ret = analytics.trainTopicCreateTopic("my topic")What to do: remove the calls. To follow the content about a topic described with weighted concepts and keywords, use a topic page:
# after
topic = TopicPage(er)
topic.addConcept(er.getConceptUri("renewable energy"), 50)
topic.addKeyword("photovoltaic", 20)
res = topic.getArticles(page = 1)The method accepted a list of URLs, but the endpoint maps one URL per call. It now accepts only a string.
# before
res = er.getArticleUris(["https://www.example.com/article1", "https://www.example.com/article2"])# after
uris = {}
for url in ["https://www.example.com/article1", "https://www.example.com/article2"]:
uris.update(er.getArticleUris(url))You can also use the ArticleMapper class, which remembers the mappings.
The API never returned more than 100 articles or mentions per call, so a higher count was misleading. It now raises a ValueError.
# before: only 100 articles were returned anyway
q.setRequestedResult(RequestArticlesInfo(count = 200))# after: ask for the pages, or use the iterator that does it for you
q.setRequestedResult(RequestArticlesInfo(page = 1, count = 100))
res1 = er.execQuery(q)
q.setRequestedResult(RequestArticlesInfo(page = 2, count = 100))
res2 = er.execQuery(q)
q = QueryArticlesIter(keywords = "Tesla")
for art in q.execQuery(er, maxItems = 200):
print(art["title"])Iterating over an instance of QueryArticlesIter, QueryEventsIter, QueryMentionsIter or QueryEventArticlesIter without calling execQuery() first now raises a RuntimeError.
# before: wrong use that did not report an error
q = QueryArticlesIter(keywords = "Tesla")
for art in q:
print(art["title"])# after
q = QueryArticlesIter(keywords = "Tesla")
for art in q.execQuery(er):
print(art["title"])The default hosts are now https://eventregistry.org and https://analytics.eventregistry.org. What to do: nothing in most cases. If your network setup (firewall or proxy rules) allowed only the previously used addresses, allow these two. If you need a different host, pass it with the host and hostAnalytics arguments or set it in settings.json:
# after: only if you need a host different from the default one
er = EventRegistry(apiKey = YOUR_API_KEY, host = "https://eventregistry.org", hostAnalytics = "https://analytics.eventregistry.org")The settings.json file with the API key is now first looked up in the .eventregistry folder of your home directory and only then in the folder of the package. The request log (turned on with EventRegistry.setLogging(True)) is written to ~/.eventregistry/requests_log.txt instead of the package folder.
What to do: a settings.json in the package folder still works, unless there is also one in ~/.eventregistry/ - that one is now used. Since the package folder is replaced when the package is updated, move the file to ~/.eventregistry/settings.json. If you read the request log, look for it in the new place.
# before and after: the code is the same, only the location of the file changed
from eventregistry import *
er = EventRegistry() # reads the key from ~/.eventregistry/settings.json
er.setLogging(True) # writes to ~/.eventregistry/requests_log.txt-
TopicPage.setArticleIsDuplicateFilter()wrote the value under a wrong key and the filter was ignored by the server. It now works, so topic pages that set it can return different articles. -
ReturnInfo.getConf()exported the article flags under a wrong name. -
count()on the iterator classes no longer changes the requested result type of the query. - Iterating over an iterator class a second time starts again from the first result.
- The first request of an
EventRegistryinstance is no longer delayed byminDelayBetweenRequests. -
KeyboardInterrupt(Ctrl+C) is no longer swallowed by the retry loop, so a script that repeats a failed request can be stopped. - The API key is no longer written into the parameter dict that you pass to
jsonRequest().
Core Information
Usage tracking
Terminology
EventRegistry class
ReturnInfo class
Data models for returned information
Finding concepts for keywords
Filtering content by news sources
Errors and troubleshooting
Migration guide (v10, v11)
Text analytics
Semantic annotation, categorization, sentiment
Searching
Searching for events
Searching for articles
Searching for mentions
Article/event info
Get event information
Get article information
Other
Supported languages
Different ways to search using keywords
Topic pages
Feed of new articles/events
Daily trends
Number of mentions in the news
Find the event for your own text
Article URL to URI mapping
API reference