A working Flask app

master
Drew Bednar 3 years ago
parent 1e7fa3310a
commit 4d955389bc

@ -2,12 +2,76 @@
Repo for learning Bazel
## Basics
https://bazel.build/start/bazel-intro
Rules are defined in a DSL called [Starlark](https://bazel.build/rules/language)
- A WORKSPACE is a hierarchy of directories
- Contains Packages
- Contains source files
- Denoted by a one BUILD file.
- Build files contain Rules
- Targets: Identified by labels.
- Labels
- Sub directories containing a BUILD file are different packages. A file can only belong to one package.
- Ignores sub dirs that contain another workspace
## Builds
https://bazel.build/concepts/build-ref
### Workspaces
Alias `@`
Denoted by WORKSPACE or WORKSPACE.bazel file. Subdirectories under the Workspace that contain a WORKSPACE are ignored as they are considered different workspaces.
External repositoies are defined in the WORKSPACE using workspace rules
### Packages
The primary unit of code organization in a repository is the package. A package is a collection of related files and a specification of how they can be used to produce output artifacts.
A package is defined as a directory containing a file named BUILD (or BUILD.bazel). A package includes all files in its directory, plus all subdirectories beneath it, except those which themselves contain a BUILD file. From this definition, no file or directory may be a part of two different packages.
### Targets
A package is a container of targets, which are defined in the package's BUILD file. Most targets are one of two principal kinds, files and rules.
Files are further divided into two kinds. Source files are usually written by the efforts of people, and checked in to the repository. Generated files, sometimes called derived files or output files, are not checked in, but are generated from source files.
The second kind of target is declared with a rule. Each rule instance specifies the relationship between a set of input and a set of output files. The inputs to a rule may be source files, but they also may be the outputs of other rules.
All targets belong to exactly one package. The name of a target is called its [label](https://bazel.build/concepts/labels). Every label uniquely identifies a target. A typical label in canonical form looks like:
```
@myrepo//my/app/main:app_binary
```
### Build rules
A build rule specifies the build tools Bazel will use, such as compilers and linkers, and their configurations. Bazel ships with a number of build rules covering the most common artifact types in the supported languages on supported platforms.
## Commands
From top level dir
Build all packages(Denoted by BUILD.bazel files) in this project.
Build all packages(Denoted by BUILD.bazel files) in this project. `...` refers to all targets
Targets all Build files:
```
bazel build //...
```
Building just the `c_project` but using it's package's label
```
bazel build //c_project/...
```
# Python Builds
https://bazel.build/reference/be/python

@ -0,0 +1,24 @@
# https://github.com/bazelbuild/rules_python#Migrating-from-the-bundled-rules
# We will use the future interface for Python Rules in Bazel I am not focusing on
# a hermetic build yet.
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "rules_python",
sha256 = "9fcf91dbcc31fde6d1edb15f117246d912c33c36f44cf681976bd886538deba6",
strip_prefix = "rules_python-0.8.0",
url = "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.8.0.tar.gz",
)
# PIP STUFFS https://github.com/bazelbuild/rules_python#using-the-packaging-rules
load("@rules_python//python:pip.bzl", "pip_install")
# Create a central external repo, @my_deps, that contains Bazel targets for all the
# third-party packages specified in the requirements.txt file.
pip_install(
name = "my_py_app_deps",
requirements = "//third_party_py:requirements.txt",
)

@ -0,0 +1,8 @@
#import <stdio.h>
int main()
{
char name[10] = "Laura";
printf("Hello %s!\n", name);
return 0;
}

@ -0,0 +1,14 @@
genrule(
name = "foo",
srcs = [],
outs = ["foo.txt"],
cmd = "sleep 3 && echo 'Hello Bazel!' > $@ ",
)
# This is a comment?
genrule(
name = "bar",
srcs = [],
outs = ["bar.txt"],
cmd = "printenv > $@ ",
)

@ -0,0 +1,13 @@
Just an example of a Rule producing a file.
https://bazel.build/reference/be/general#genrule
See also: https://bazel.build/reference/be/make-variables
```
bazel build //gen_package:foo
```
```
bazel build //gen_package:foo
```

@ -0,0 +1,5 @@
This entire workspace should be ignored by the workspace at this git repo root.
This means this entire tree can be committed to our version control system without it and it's containing packages from being reviewed by the workspace in the repo root.
As far as I can tell if you want to use this sub workspace you have to cd to this dir.

@ -0,0 +1,11 @@
# Load Deps
load("@my_py_app_deps//:requirements.bzl", "requirement")
py_binary(
name = "main",
srcs = ["main.py"],
deps = [
"//py_project:calculator",
requirement("Flask"),
],
)

@ -0,0 +1,19 @@
This app is a simple flask application. It specifies Flask as a dependency which is provided in the `third_party_py` package at the root of our workspace. We also rely on `py_project:calculator` target. This is possible because we have set the visibility for this project `py_library` to public.
In the `WORKSPACE` file we have specified an `external` repo called `my_py_app_deps` this is where all of our pip installed libs
will be downloaded, and converted into Bazel packages automatically.
```
drewbednar@MacBook-Pro learn_bazel % ls ./bazel-learn_bazel/external/my_py_app_deps
BUILD.bazel pypi__click pypi__itsdangerous pypi__werkzeug
WORKSPACE pypi__flask pypi__jinja2 pypi__zipp
annotations.json pypi__importlib_metadata pypi__markupsafe requirements.bzl
```
## Executing
You can run the built Flask app with:
```
FLASK_ENV="development" bazel run my_py_app:main
```

@ -0,0 +1,20 @@
from flask import Flask
from random import randint
from py_project.calculator import Calculator
app = Flask(__name__)
my_calculator = Calculator()
@app.route("/")
def index():
num1 = randint(0, 100)
num2 = randint(0, 100)
_sum = my_calculator.add(num1, num2)
message = f" {num1} + {num2} = {_sum}"
return message
if __name__ == "__main__":
app.run()

@ -0,0 +1,15 @@
py_library(
name = "calculator",
srcs = ["calculator.py"],
# visibility
visibility = ["//visibility:public"],
)
py_test(
name = "calculator_test",
srcs = ["calculator_test.py"],
deps = [
# These are dependencies spelled out as targets?
"//py_project:calculator",
],
)

@ -0,0 +1,9 @@
# Pyproject
This package gives us two targets `calculator` and `calculator_test`.
## Tests
```
bazel test py_project/...
```

@ -0,0 +1,3 @@
class Calculator:
def add(self, x, y):
return x+y

@ -0,0 +1,17 @@
from calendar import c
import unittest
from py_project.calculator import Calculator
class TestCalculator(unittest.TestCase):
def test_sum(self):
calc = Calculator()
self.assertEqual(calc.add(3, 4), 7)
# def test_sub(self):
# calc = Calculator()
# self.assertEqual(calc.sub(4, 2), 2)
if __name__ == "__main__":
unittest.main()
Loading…
Cancel
Save