Code Monkey home page Code Monkey logo

buscedv / ask Goto Github PK

View Code? Open in Web Editor NEW
9.0 3.0 5.0 991 KB

Ask is a modern open-source transpiled programming language, designed for building backend services and APIs. Ask reduces the amount of needed boilerplate code for setting up things like database connections and authentication to virtually zero lines.

Home Page: https://ask.edvard.dev

License: GNU General Public License v3.0

Python 100.00%
ask backend programming-language python flask backend-programming-language jwt databases hacktoberfest

ask's Introduction

Ask

Ask

Introduction

Ask is an open source, dynamic, and transpiled programming language built for building backends and APIs. Ask directly transpiles to Python, more specifically Flask.

Feature Highlights

  • Built-in JWT Authentication.
  • Super Simple Database Management.
  • Syntax Inspired by Python.
  • Built-in CORS Support.
  • Reduces Boilerplate.
  • Compatible with Python*

* = You can import external Python modules and call them from you Ask code.

Easy to Learn

Ask's syntax is heavily inspired by Python, and can almost be considered to be a superset of Python. This means that picking up Ask is super easy if you’re already familiar with Python.

The main idea behind Ask is to simplify common backend actions (e.g. working with databases). Building a full database CRUD REST API with JWT authentication in Ask is very straight forward and simple and requires virtually zero lines of boilerplate code and no setup whatsoever.

Extendable

Ask is a transpiled language (kind of like TypeScript) which means that it compiles the source code to another language that has a similar level of abstraction. In Ask's case, the target language is Python, more specifically a Flask app.

Flask is a very popular and well-established web framework for Python, so there's already a lot of tools, and services for deploying Flask apps.

The transpiled app is completely standalone and doesn't require Ask in any way.

Installation (normal usage)

  • You can install Ask from the PyPI. You can use pip but we recommend that you use pipx.
  • $ pipx install ask-lang.
  • Then run your apps with: $ ask [your file].ask.

Run locally (for development)

  1. Clone this repo: https://github.com/Buscedv/Ask.git.
  2. Install Poetry.
  3. Create a new virtual environment: python3 venv venv.
  4. Activate it: source venv/bin/activate.
  5. Install dependencies: poetry install.
  6. (Optional but helpful in some cases) Run Ask in development mode: Docs.

If you want to contribute please read the CONTRIBUTING.md file for code style, standards, etc.

Example (Ask vs Flask)

Here is the same basic app with one GET route written in Ask and in Python with Flask.

Ask

products = [
  {
    name: 'Product 1',
    price: 30.0,
    qty: 300
  },
  {
    name: 'Product 2',
    price: 15.5,
    qty: 20
  }
]

@get('/api/v1/products'):
  respond({products: products})

Flask

This is what the same application would look like in Flask.

from flask import Flask, jsonify

app = Flask(__name__)

products = [
  {
    'name': 'Product 1',
    'price': 30.0,
    'qty': 300
  },
  {
    'name': 'Product 2',
    'price': 15.5,
    'qty': 20
  }
]

@app.route('/api/v1/products', methods=['GET'])
def get_products():
  return jsonify({'products': products})

if __name__ == '__main__':
  app.run()

As you can see Ask hides away all the clutter and boilerplate.

Documentation

You can find the full documentation on docs.ask.edvard.dev.

Contact

ask's People

Contributors

0x0elliot avatar amroakmal avatar buscedv avatar dependabot[bot] avatar hk-jain avatar pillemer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ask's Issues

Add random number generating functions

Add a new module called _random. It should work like _hash and _env do (they get added in as boilerplate code on lines 514-662 in ask.py). Behind the scenes, this should use Pythons own built-in random library.

It should have the following functions:

# Single items
_random.int(0, 8) # Returns a random integer between 0 and 8.
_random.float(1.5, 3.8) # Returns a random float between 1.5 and 3.8.
_random.item(['a', 'b', 'c']) # Returns a random element from the passed in list.

# Multiple items
_random.ints(0, 8, 3) # Returns 3 random integers between 0 and 8 in a list.
_random.floats(1.5, 3.8, 8) # Returns 8 random floats between 1.5 and 3.8.
_random.items(['a', 'b', 'c'], 4) # Returns 4 random elements from the passed in list.

# You can add more functions if you want but at least these ones as a start...

Helpful links

Function for checking if the body contains a set of required values.

Remove the need for if 'name' in _body and 'bithday' in _body and 'email' in _body and so on with a simple expression like this:

@post('/user'):
  required = ['name', 'birthday', 'email']

  if require_keys(required, _body):
    print(...)
    ...

This can be built in a similar way as deep() and quick_set() are built.

New Feature: Built-in and custom decorators

Decorators

The ability to "insert" both built-in (part of Ask) and user-made code/functionality into functions.

Usage

Decorating a function and/or route

&[decorator goes here]
def [function]([params]): # OR: @[method]([route]): 

Creating a decorator

decorator [decorator name goes here]:
  # Code goes here...
  ...

Simple Example

decorator my_first_decorator:
  print('Before')
  _inner()
  print('After')

&my_first_decorator
def my_function(message):
  print(message)

my_function('Hello')

Transpiled result

...

def my_first_decorator(func):
  def wrapper(*args, *kwargs):
    print('Before')
    func(*args, *kwargs)
  return wrapper

@my_first_decorator
def my_function(message):
  print(message)

my_function('Hello')

...

Output

Before
Hello
After

Ideas

  • Built-in decorator names should start with: _, e.g. _a_built_in_decorator.
  • See issue #35 & #25 for more examples.

Make login & signup routes easier to create

Make it easier to create basic login & signup routes. This could be solved with templating (a new concept that doesn't exist yet)

With a decorator:

&_login
@post('/login'):

With templating

&protected
@post('/login'):
  %_login%

Update the documentation

A few new features are missing in the documentation.

  • Decorators.
  • the &basic decorator.
  • Relationships (not ready yet see: #51).
  • The custom db property in the Askfile.
  • Sending request with an API token.
  • HTTP status codes.
  • the require_keys() function.
  • DateTime db datatype.
  • Random.
  • Auto docs.

pip install ask-lang error

macuser@Macs-MacBook-Air ask % pip install ask-lang

ERROR: Could not find a version that satisfies the requirement ask-lang (from versions: none)
ERROR: No matching distribution found for ask-lang

Ask config file

Build support for an "Askfile" that gives configuration options to the transpiler. Ex. support for naming the database file something else.

Better error messages and correct line numbers, clean up traceback

Right now errors are shown like "normal" python errors, and the traceback comes from the app.py file, this is a problem since the function names, line numbers, etc. doesn't match the source .ask file. The line numbers are incorrect due to the boilerplate code that gets inserted into app.py but also other stuff like routes (they are defined on one line in Ask but two in Flask/Python).

TODO

  • Correct line numbers.
  • "Clean up" the traceback, make it easier to read.
  • Add a flag (e.g. -e) that allows the user to see the full error messages if they please.
  • Catch all errors and show Ask customized/cleaned up messages in their place.
  • Log files, activate by either a flag (-l) or a config in the Askfile (or both).

First steps

  • Figure out a way to calculate which line number in app.py corresponds to which line in the source .ask file.
  • Capture the error messages.
  • Parse the error messages.

Helpful links:

https://flask.palletsprojects.com/en/master/errorhandling/#generic-exception-handlers

Ideas and thoughts are welcome. This might be a bit hard for new contributors but feel free to comment and help out if you want.

Create unit tests

We need unit tests!

Specs

  • Preferably use Pythons built-in unittest framework.
  • The tests should be in a script called: test_ask.py
  • The most important methods to test are (in no particular order):
    • get_root_from_file_path()
    • route_path_to_func_name()
    • maybe_place_space_before()
    • route_params()
    • get_current_tab_level()
    • parser() ❗️
    • lex_var_keyword()
    • add_part()
    • fix_up_code_line()
    • lexer() ❗️

(❗️= complicated tests required)

Support both running in a dev server and a production ready server e.g Gunicorn

Ask should start a development server (flask run) if the transpiler is running in dev mode or if production configurations aren't present in the Askfile. The production server should then start automatically with a NO SETUP REQUIRED approach (but it should be customizable if the user wants to). The production server could e.g. be Gunicorn.

The transpiler enters DEV mode when the user runs ask with the -d flag:

$ python3 ask.py main.ask -d

Production "mode" could be activated in the Askfile like this:

{
  "run": {
    "production": true,
    ...
  },
  ...
}

Make it possible to store lists in the database

Make a built-in solution for storing lists in the database.

Do this with tables. Here is a working example but this needs to get implemented into Ask as a built-in behind the scenes feature.

db_class GenericList:
	id = _db.col(_db.int, _db.pk)

	def set_list(self, entry):
		if entry:
			for item in entry:
				self.push(item)

	def s(self):
		return {
			id: self.id,
			list: self.list()
		}

	def list(self):
		return [self.get(item.index) for item in GenericListItem._db.get_by(parent_id=self.id)]

	def push(self, item):
		new_item = GenericListItem(item, self.id)
		_db.add(new_item)

		return self.s()

	def get(self, index):
		item = GenericListItem._db.get_by(parent_id=self.id, index=index).first()

		return item.in_type()

	def remove(self, index):
		item = GenericListItem._db.get_by(parent_id=self.id, index=index).first()

		_db.delete(item)

db_class GenericListItem:
	id = _db.col(_db.int, _db.pk)
	index = _db.col(_db.int)
	item = _db.col(_db.bytes)
	parent_id = _db.col(_db.int)

	def _init(self, item, parent_id):
		self.item = pickle.dumps(item)
		self.parent_id = parent_id
		self.index = self.get_last_index() + 1

	def s(self):
		return {
			id: self.id,
			index: self.index,
			item: self.in_type(),
			parent_id: self.parent_id
		}

	def get_last_index(self):
		last_item = GenericListItem._db.get_by(parent_id=self.parent_id).order_by(_db.desc(GenericListItem.id)).first()

		if _db.exists(last_item):
			return last_item.index

		return -1

	def in_type(self):
		return pickle.loads(self.item)


def generic_list_factory(entry):
	generic_list = GenericList()
	_db.add(generic_list)
	generic_list.set_list(entry)

	return generic_list

Usage

my_list = generic_list_factory([1, 2, 3, 4])
print(my_list).list() # [1, 2, 3, 4]

my_list.push(5)
print(my_list).list() # [1, 2, 3, 4, 5]

my_list.remove(4)
print(my_list).list() # [1, 2, 3, 4]

print(my_list.get(0)) # 1

How it should work when it's built-in to Ask

my_list = _db.list([1, 2, 3, 4]) # or a single function e.g. my_list = make_list([1, 2, 3, 4])
my_list.push(5)
my_list.remove(4)
my_list.get(0)
my_list.list()

Another thought is that maybe we should add an alias for the _db.int type e.g. _db.list_id just for readabilities sake.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.