Python library in Coda pack?

Hi,

Apologies if this has been asked before, I’ve not been able to find it.

I’m trying to pull data directly into Coda from Yahooquery. Yahooquery is a python interface to unofficial Yahoo Finance API endpoints. Unfortunately, going via Googlesheets, Zapier etc. is not an option for this project.

I can’t see a way to run/import python libraries either as a pack or natively in Coda.

Have I missed something? Is their a pack that will allow me to connect directly to these API endpoints? How would the community solve this?

I appreciate any suggestions or being pointed in the right direction!

thete is no pack for python libraries in coda (that i am aware of).

i am building a python to coda converter. but it is not going to be able to import python libraries, because it is designed mainly for migrating automation scripts written in python, rather that entire complex libraries. it translates python scripts into coda formulas and places that inside a button. not what you need.

however, i suspect you do not need the python libraries. instead, you need to know the API endpoint URLs and the parameters needed as inputs and the data structures returned by those endpoints, which are typically language independent.

so you need to find the documentation about the api endpoints and not the python libraries.

hoping this may help.

max

1 Like

Coda Packs are written in Javascript (they run in NodeJS), and can’t use Python. Options:

  1. Find a Node equivalent of the Python package. Does this NPM package give you what you need? You might be able to use it in a Coda Pack. Note that in order to use external libraries in your pack, you need to use the command line interface to build your packs. However another thing to note is that Packs are somewhat locked down in terms of what methods you can use to fetch external data, so I’m unsure if a package like this would work. Instead, you may need to peek under the hood to find out what endpoints it’s calling, and call those directly from Coda’s context.fetcher.fetch()
  2. Spin up your own server or cloud function that runs Python, as an intermediary. The Coda Pack would make requests to your server; you would take those requests, process them in Python (e.g. via Flask), and use Yahooquery to hit the Yahoo API, returning the result back to Coda.

Unsure your level of development experience so let me know if this makes sense or is gibberish or what!

3 Likes

I think these answers combined point me to the next step. Thanks both!

1 Like

Thanks again for the feedback. I’ve done some more research/digging based on the info provide but I was unable to find the python API endpoint URLs.

It’s been over a decade since I did any serious programming like this so wasn’t able to make much progress in the pack space with the Node equivalent of the Python package. I’ve forgotten most of the C, C++ and Python having been limited to just using basic HTML/CSS and Excel since uni.

I’ve built the Coda doc that does all the calcs but I’m currently importing the pricing data manually (copy and paste from a CSV). I basically just need to pull in the current price for a watchlist of stocks and be able to pull in 5 years worth of daily close pricing for the same watchlist. I can’t use the Stocks pack because it doesn’t have ASX data.

If you’re able to walk me through possible solutions for my level of programming or other ways I can solve this problem I’d really appreciate it! Thanks

1 Like

I had a look too and indeed the way the package accesses the Yahoo API is pretty complex (I think because it’s an unofficial API they have to do some convoluted stuff with cookies etc). Are there any other APIs that give you the info you need?

I had a quick look around and I think these might be possibilities:

Have a look at those and let me know if they seem to have the data you need - if so I can point you in the right direction for integrating them

2 Likes

Hi Nick,

The free version of the YahooFinance API you found should do the trick as I’m only looking for price data. I appreciate any help you can provide for next steps!

ps. congratulations on becoming a community champion!

1 Like

Ok great. I’ve used a RapidAPI api for a Pack before (I’ve since switched to another data provider, but here’s the code for an early version in case it’s helpful to you. Note I’m doing the CLI version of development, so that’s why you see multiple files. I don’t recommend using the CLI approach if you’re getting started though).

Aaaaanyway. Key things to get you in the right direction:

Authentication

If there were an unlimited number of API calls allowed for free, you would do System Authentication (single API key that you as the pack author control, and everyone gets to share). But there aren’t, it’s only 250 calls per month per API key. So you should direct each user to register for a key at rapidapi.com, and then ask them to enter it when installing the Pack, which means you’re gonna use User Authentication. In paticular, RapidAPI uses Single Token → Custom Header authentication. E.g.:

pack.setUserAuthentication({
  type: coda.AuthenticationType.CustomHeaderToken,
  headerName: "x-rapidapi-key",
  instructionsUrl: "https://...a public Coda doc explaining how to register at rapidapi",
});

Fetching Data

Details on Fetching data are here. This API doesn’t have anything too out of the ordinary going on, so I think the guides/samples should work for you. (Not saying you’ll necessarily get it instantly, more that I don’t expect major “gotchas”). You’ll need to understand how to manage the response that comes back (read some introductory stuff on Javascript objects and arrays, and JSON).

Tips

  • Start as simple as you can. Don’t try to build the whole thing right away, just get a minimal version like “no matter what you put in, it just responds with Hello World”. Then “no matter what you put in, it just sends you back a list of supported exchanges” (cause that’s a simpler endpoint in the API). Then once that works, change it to always show the price of $GME on Jan 1, 2022. Then once that works, actually take in user input for the stock and date. Etc etc

  • Make liberal use of console.log(some-message-or-variable) to troubleshoot. You can also use console.log(JSON.stringify(some-object-variable)) to print out the whole contents of an array or object into the logs. This will help you resolve the most common problem, which is like "oh instead of response.price I need to do response.body.price or response.body.prices[0].price or whatever it is.

Hope this helps! Feel free to post here with any questions, share sample code that’s broken and you don’t know why, etc. You definitely have what it takes to make this Pack! :raised_hands: And you’ll know some extra JavaScript when you’re done too :slight_smile:

3 Likes

That’s been super helpful to get started, thanks!

I’ve been able to get the systemwide authentication to work (it’s only me that will be using it) and it appears to be working.

Looking at example code it’s started jogging the programming memory about structures, types, objects etc.

I’ve Frankenstein-ed the following code together to try and get the exchange list as recommended but getting a “Expected value to be defined and non-null: No output from formula” error. I suspect this is because I’m returning the wrong value? Is there an obvious mistake in my code so far?

import * as coda from "@codahq/packs-sdk";

export const pack = coda.newPack();

// Allow the pack to make requests to RapidAPI.
pack.addNetworkDomain("rapidapi.com");

pack.setSystemAuthentication({
  type: coda.AuthenticationType.CustomHeaderToken,
  headerName: "X-RapidAPI-Key",
});

pack.addFormula({
   name: "ExchangeList",
  description: "Get a lits of all exchanges.",

    parameters: [
    coda.makeParameter({
      type: coda.ParameterType.String,
      name: "text",
      description: "input text",
    }),
  ],

   resultType: coda.ValueType.String,
   
 execute: async function (text, context) {
 let response = await context.fetcher.fetch({
      method: "GET",
      url: "https://yahoofinance-stocks1.p.rapidapi.com/exchanges",
      cacheTtlSecs: 0, // Don't cache the result
    });
    
   console.log(JSON.stringify(response.body.url))
    
    return response.body.url;
    
  },
});
1 Like

I don’t think response.body has the subproperty url in this case. (You sent the property url to the fetch which is correct, but response.body is what the API sends back)

Try console.log(JSON.stringify(response.body)) and you’ll see what the API is returning. Then you can return one of those properties instead of “url”.

1 Like

Thanks Nick, that was the step I was missing!