Commit 6e15d3ee authored by Ali Saeed's avatar Ali Saeed

upload todo project

parents

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

syntax = "proto3";
package auth;
option go_package = "/auth";
message RegisterRequest {
string username = 1;
string password = 2;
}
message RegisterResponse {
bool success = 1;
string message = 2;
}
message LoginRequest {
string username = 1;
string password = 2;
}
message LoginResponse {
bool success = 1;
string message = 2;
string token = 3;
}
message ValidateTokenRequest {
string token = 1;
}
message ValidateTokenResponse {
bool success = 1;
string message = 2;
}
service AuthService {
rpc Register(RegisterRequest) returns (RegisterResponse) {}
rpc Login(LoginRequest) returns (LoginResponse) {}
rpc ValidateToken(ValidateTokenRequest) returns (ValidateTokenResponse) {}
}
\ No newline at end of file
package auth
import (
"my-auth/usecase"
"log"
"golang.org/x/net/context"
)
type Server struct {
userUsecase usecase.UserUsecase
UnimplementedAuthServiceServer
}
func InitServer(userUsecase usecase.UserUsecase) Server {
return Server{
userUsecase,
UnimplementedAuthServiceServer{},
}
}
func (s *Server) Register(ctx context.Context, request *RegisterRequest) (*RegisterResponse, error) {
_, err := s.userUsecase.Register(request.Username, request.Password)
if err != nil {
log.Println("Error to register user", err)
return &RegisterResponse{Success: false, Message: "Failed to register"}, err
}
return &RegisterResponse{Success: true, Message: "Succeed to register"}, nil
}
func (s *Server) Login(ctx context.Context, request *LoginRequest) (*LoginResponse, error) {
token, err := s.userUsecase.Login(request.Username, request.Password)
if err != nil {
log.Println("Error to register user", err)
return &LoginResponse{Success: false, Message: "Failed to login", Token: ""}, err
}
return &LoginResponse{Success: true, Message: "Login success", Token: token}, nil
}
func (s *Server) ValidateToken(ctx context.Context, request *ValidateTokenRequest) (*ValidateTokenResponse, error) {
result, err := s.userUsecase.ValidateToken(request.Token)
if err != nil {
log.Println("Error to validate token", err)
return &ValidateTokenResponse{Success: false, Message: "Invalid token"}, err
}
return &ValidateTokenResponse{Success: true, Message: result}, nil
}
\ No newline at end of file
This diff is collapsed.
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc v3.12.4
// source: auth.proto
package auth
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
const (
AuthService_Register_FullMethodName = "/auth.AuthService/Register"
AuthService_Login_FullMethodName = "/auth.AuthService/Login"
AuthService_ValidateToken_FullMethodName = "/auth.AuthService/ValidateToken"
)
// AuthServiceClient is the client API for AuthService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type AuthServiceClient interface {
Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error)
Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error)
ValidateToken(ctx context.Context, in *ValidateTokenRequest, opts ...grpc.CallOption) (*ValidateTokenResponse, error)
}
type authServiceClient struct {
cc grpc.ClientConnInterface
}
func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient {
return &authServiceClient{cc}
}
func (c *authServiceClient) Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) {
out := new(RegisterResponse)
err := c.cc.Invoke(ctx, AuthService_Register_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authServiceClient) Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error) {
out := new(LoginResponse)
err := c.cc.Invoke(ctx, AuthService_Login_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authServiceClient) ValidateToken(ctx context.Context, in *ValidateTokenRequest, opts ...grpc.CallOption) (*ValidateTokenResponse, error) {
out := new(ValidateTokenResponse)
err := c.cc.Invoke(ctx, AuthService_ValidateToken_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// AuthServiceServer is the server API for AuthService service.
// All implementations must embed UnimplementedAuthServiceServer
// for forward compatibility
type AuthServiceServer interface {
Register(context.Context, *RegisterRequest) (*RegisterResponse, error)
Login(context.Context, *LoginRequest) (*LoginResponse, error)
ValidateToken(context.Context, *ValidateTokenRequest) (*ValidateTokenResponse, error)
mustEmbedUnimplementedAuthServiceServer()
}
// UnimplementedAuthServiceServer must be embedded to have forward compatible implementations.
type UnimplementedAuthServiceServer struct {
}
func (UnimplementedAuthServiceServer) Register(context.Context, *RegisterRequest) (*RegisterResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Register not implemented")
}
func (UnimplementedAuthServiceServer) Login(context.Context, *LoginRequest) (*LoginResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Login not implemented")
}
func (UnimplementedAuthServiceServer) ValidateToken(context.Context, *ValidateTokenRequest) (*ValidateTokenResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ValidateToken not implemented")
}
func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {}
// UnsafeAuthServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to AuthServiceServer will
// result in compilation errors.
type UnsafeAuthServiceServer interface {
mustEmbedUnimplementedAuthServiceServer()
}
func RegisterAuthServiceServer(s grpc.ServiceRegistrar, srv AuthServiceServer) {
s.RegisterService(&AuthService_ServiceDesc, srv)
}
func _AuthService_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RegisterRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthServiceServer).Register(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthService_Register_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthServiceServer).Register(ctx, req.(*RegisterRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthService_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(LoginRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthServiceServer).Login(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthService_Login_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthServiceServer).Login(ctx, req.(*LoginRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthService_ValidateToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ValidateTokenRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthServiceServer).ValidateToken(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthService_ValidateToken_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthServiceServer).ValidateToken(ctx, req.(*ValidateTokenRequest))
}
return interceptor(ctx, in, info, handler)
}
// AuthService_ServiceDesc is the grpc.ServiceDesc for AuthService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var AuthService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "auth.AuthService",
HandlerType: (*AuthServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Register",
Handler: _AuthService_Register_Handler,
},
{
MethodName: "Login",
Handler: _AuthService_Login_Handler,
},
{
MethodName: "ValidateToken",
Handler: _AuthService_ValidateToken_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "auth.proto",
}
package config
import (
"fmt"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
)
var DB *sqlx.DB
// ConnectDB to get all needed db connections for application
func ConnectDB() *sqlx.DB {
DB = getDBConnection()
return DB
}
func getDBConnection() *sqlx.DB {
var dbConnectionStr string
dbConnectionStr = fmt.Sprintf(
"host=%s port=%d dbname=%s user=%s password=%s sslmode=disable",
"localhost",
5432,
"grpc_authen",
"postgres",
"postgres",
)
// fmt.Sprintf(dbConnectionStr)
db, err := sqlx.Open("postgres", dbConnectionStr)
if err != nil {
panic(err)
}
err = db.Ping()
if err != nil {
panic(err)
}
//TODO: experiment with correct values
db.SetMaxIdleConns(1)
db.SetMaxOpenConns(5)
fmt.Println("Connected to DB")
return db
}
\ No newline at end of file
module my-auth
go 1.21.3
require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/jmoiron/sqlx v1.3.5 // indirect
github.com/lib/pq v1.10.9 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
)
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
package main
import (
"fmt"
"log"
"net"
"my-auth/auth"
"my-auth/config"
"my-auth/repository"
"my-auth/usecase"
"google.golang.org/grpc"
)
func main() {
db := config.ConnectDB()
userRepository := repository.InitUserRepository(db)
userUsecase := usecase.InitUserUsecase(userRepository)
s := auth.InitServer(userUsecase)
grpcServer := grpc.NewServer()
auth.RegisterAuthServiceServer(grpcServer, &s)
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", 9000))
if err != nil {
log.Printf("failed to listen: %v\n", err)
}
fmt.Println("Listen to port 9000")
if err := grpcServer.Serve(lis); err != nil {
log.Printf("failed to serve: %s\n", err)
}
}
\ No newline at end of file
package models
type User struct {
ID int64
Username string
Password string
}
\ No newline at end of file
package repository
import (
"my-auth/models"
"database/sql"
"log"
"github.com/jmoiron/sqlx"
)
type userRepository struct {
db *sqlx.DB
}
type UserRepository interface {
CreateUser(username string, password string) (bool, error)
GetUserByUsername(username string) (models.User, error)
}
func InitUserRepository(db *sqlx.DB) UserRepository {
return &userRepository{
db,
}
}
func (userRepository *userRepository) CreateUser(username string, password string) (bool, error) {
var err error
var result bool
tx, errTx := userRepository.db.Begin()
if errTx != nil {
log.Println("Error create user: ", errTx)
} else {
err = insertUser(tx, username, password)
if err != nil {
log.Println("Error create user: ", err)
}
}
if err == nil {
result = true
tx.Commit()
} else {
result = false
tx.Rollback()
log.Println("Error create user: ", err)
}
return result, err
}
func insertUser(tx *sql.Tx, username string, password string) error {
_, err := tx.Exec(`
INSERT INTO users (
username,
password
)
VALUES(
$1,
$2
);
`,
username,
password,
)
return err
}
func (userRepository *userRepository) GetUserByUsername(username string) (models.User, error) {
var user models.User
var id int64
err := userRepository.db.QueryRow(`
SELECT id, username, password FROM users WHERE username=$1;
`, username).Scan(&id, &(user.Username), &(user.Password))
user.ID = id
if err != nil {
log.Println("Error to get user by username", err)
}
return user, err
}
\ No newline at end of file
package usecase
import (
"my-auth/models"
"my-auth/repository"
"my-auth/utils"
"encoding/json"
"errors"
"log"
)
type userUsecase struct {
userRepository repository.UserRepository
}
type UserUsecase interface {
Register(username, password string) (bool, error)
Login(username, password string) (string, error)
ValidateToken(token string) (string, error)
}
func InitUserUsecase(userRepository repository.UserRepository) UserUsecase {
return &userUsecase{
userRepository,
}
}
func (userUsecase *userUsecase) Register(username, password string) (bool, error) {
hashedPassword, err := utils.HashPassword(password)
if err != nil {
log.Println("Error to register user: ", err)
return false, err
}
_, err = userUsecase.userRepository.CreateUser(username, hashedPassword)
if err != nil {
log.Println("Error to register user: ", err)
return false, err
}
return true, nil
}
func (userUsecase *userUsecase) Login(username, password string) (string, error) {
user, err := userUsecase.userRepository.GetUserByUsername(username)
if err != nil {
log.Println("Error getting user by username:", err)
return "", err
}
ok := utils.CheckPasswordHash(password, user.Password)
if !ok {
log.Println("Wrong password")
return "", errors.New("Wrong password")
}
tokenString, err := utils.GenerateToken(models.User{
ID: user.ID,
Username: user.Username,
})
if err != nil {
log.Println("Error generating token:", err)
return "", err
}
return tokenString, nil
}
func (userUsecase *userUsecase) ValidateToken(token string) (string, error) {
user, err := utils.ParseToken(token)
if err != nil {
log.Println("Error validating token:", err)
return "", errors.New("Invalid token. Please provide a valid token.")
}
result, err := json.Marshal(&user)
if err != nil {
log.Println("Error marshaling user data:", err)
return "", errors.New("Error processing user data.")
}
return string(result), nil
}
\ No newline at end of file
package utils
import "golang.org/x/crypto/bcrypt"
func HashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
return string(bytes), err
}
func CheckPasswordHash(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
\ No newline at end of file
package utils
import (
"my-auth/models"
"fmt"
"log"
"strconv"
"time"
"strings"
"errors"
"github.com/dgrijalva/jwt-go"
)
var (
SecretKey = []byte("ThisIsASecretKey")
)
func GenerateToken(tokenResult models.User) (string, error) {
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
claims["id"] = tokenResult.ID
claims["username"] = tokenResult.Username
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
tokenString, err := token.SignedString(SecretKey)
if err != nil {
log.Println("Error in generating key")
return "", err
}
return tokenString, nil
}
func ParseToken(tokenStr string) (models.User, error) {
tokenSegments := strings.Split(tokenStr, ".")
if len(tokenSegments) != 3 {
return models.User{}, errors.New("Invalid token")
}
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
return SecretKey, nil
})
if err != nil {
log.Println("Error parsing token:", err)
return models.User{}, err
}
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
idStr := fmt.Sprintf("%v", claims["id"])
id, _ := strconv.ParseInt(idStr, 10, 64)
username := claims["username"].(string)
return models.User{Username: username, ID: id}, nil
}
return models.User{}, errors.New("Invalid token")
}
\ No newline at end of file
from flask import Flask, jsonify, render_template
from auth.auth import auth_blueprint
from todo.todo import todo_blueprint
app = Flask(__name__)
app.secret_key = "ThisIsExtremelySecretKey"
app.register_blueprint(auth_blueprint, url_prefix="/auth")
app.register_blueprint(todo_blueprint, url_prefix="/todo")
@app.route('/', methods=['GET'])
def root_route():
return render_template('home.html')
if __name__ == '__main__':
app.run(debug=True)
\ No newline at end of file
syntax = "proto3";
package auth;
option go_package = "/auth";
message RegisterRequest {
string username = 1;
string password = 2;
}
message RegisterResponse {
bool success = 1;
string message = 2;
}
message LoginRequest {
string username = 1;
string password = 2;
}
message LoginResponse {
bool success = 1;
string message = 2;
string token = 3;
}
message ValidateTokenRequest {
string token = 1;
}
message ValidateTokenResponse {
bool success = 1;
string message = 2;
}
service AuthService {
rpc Register(RegisterRequest) returns (RegisterResponse) {}
rpc Login(LoginRequest) returns (LoginResponse) {}
rpc ValidateToken(ValidateTokenRequest) returns (ValidateTokenResponse) {}
}
\ No newline at end of file
from flask import render_template
from flask import Blueprint, request, jsonify
from flask import redirect, url_for, session
from auth.client import AuthClient
auth_blueprint = Blueprint('auth_blueprint', __name__)
@auth_blueprint.route('/register', methods=['GET','POST'])
def register():
if request.method == 'POST':
try:
if request.form['username'] == '' or request.form['password'] == '':
raise ValueError('Please provide your username and password')
auth_client = AuthClient()
result = auth_client.register(username=request.form['username'],
password=request.form['password'])
return redirect(url_for('auth_blueprint.login'))
except Exception as error:
return render_template('auth/register.html', error=str(error))
return render_template('auth/register.html')
@auth_blueprint.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
try:
if request.form['username'] == '' or request.form['password'] == '':
raise ValueError('Please provide your username and password')
auth_client = AuthClient()
result = auth_client.login(username=request.form['username'],
password=request.form['password'])
session['token'] = result.token
return redirect(url_for('todo_blueprint.get_todos'))
except Exception as error:
return render_template('auth/login.html', error=str(error))
return render_template('auth/login.html')
@auth_blueprint.route('/logout', methods=['GET'])
def logout():
session.clear()
return redirect(url_for('auth_blueprint.login'))
\ No newline at end of file
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: auth.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nauth.proto\x12\x04\x61uth\"5\n\x0fRegisterRequest\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\"4\n\x10RegisterResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t\"2\n\x0cLoginRequest\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\"@\n\rLoginResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\r\n\x05token\x18\x03 \x01(\t\"%\n\x14ValidateTokenRequest\x12\r\n\x05token\x18\x01 \x01(\t\"9\n\x15ValidateTokenResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t2\xca\x01\n\x0b\x41uthService\x12;\n\x08Register\x12\x15.auth.RegisterRequest\x1a\x16.auth.RegisterResponse\"\x00\x12\x32\n\x05Login\x12\x12.auth.LoginRequest\x1a\x13.auth.LoginResponse\"\x00\x12J\n\rValidateToken\x12\x1a.auth.ValidateTokenRequest\x1a\x1b.auth.ValidateTokenResponse\"\x00\x42\x07Z\x05/authb\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'auth_pb2', _globals)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'Z\005/auth'
_globals['_REGISTERREQUEST']._serialized_start=20
_globals['_REGISTERREQUEST']._serialized_end=73
_globals['_REGISTERRESPONSE']._serialized_start=75
_globals['_REGISTERRESPONSE']._serialized_end=127
_globals['_LOGINREQUEST']._serialized_start=129
_globals['_LOGINREQUEST']._serialized_end=179
_globals['_LOGINRESPONSE']._serialized_start=181
_globals['_LOGINRESPONSE']._serialized_end=245
_globals['_VALIDATETOKENREQUEST']._serialized_start=247
_globals['_VALIDATETOKENREQUEST']._serialized_end=284
_globals['_VALIDATETOKENRESPONSE']._serialized_start=286
_globals['_VALIDATETOKENRESPONSE']._serialized_end=343
_globals['_AUTHSERVICE']._serialized_start=346
_globals['_AUTHSERVICE']._serialized_end=548
# @@protoc_insertion_point(module_scope)
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
import auth.auth_pb2 as auth__pb2
class AuthServiceStub(object):
"""Missing associated documentation comment in .proto file."""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.Register = channel.unary_unary(
'/auth.AuthService/Register',
request_serializer=auth__pb2.RegisterRequest.SerializeToString,
response_deserializer=auth__pb2.RegisterResponse.FromString,
)
self.Login = channel.unary_unary(
'/auth.AuthService/Login',
request_serializer=auth__pb2.LoginRequest.SerializeToString,
response_deserializer=auth__pb2.LoginResponse.FromString,
)
self.ValidateToken = channel.unary_unary(
'/auth.AuthService/ValidateToken',
request_serializer=auth__pb2.ValidateTokenRequest.SerializeToString,
response_deserializer=auth__pb2.ValidateTokenResponse.FromString,
)
class AuthServiceServicer(object):
"""Missing associated documentation comment in .proto file."""
def Register(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def Login(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def ValidateToken(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_AuthServiceServicer_to_server(servicer, server):
rpc_method_handlers = {
'Register': grpc.unary_unary_rpc_method_handler(
servicer.Register,
request_deserializer=auth__pb2.RegisterRequest.FromString,
response_serializer=auth__pb2.RegisterResponse.SerializeToString,
),
'Login': grpc.unary_unary_rpc_method_handler(
servicer.Login,
request_deserializer=auth__pb2.LoginRequest.FromString,
response_serializer=auth__pb2.LoginResponse.SerializeToString,
),
'ValidateToken': grpc.unary_unary_rpc_method_handler(
servicer.ValidateToken,
request_deserializer=auth__pb2.ValidateTokenRequest.FromString,
response_serializer=auth__pb2.ValidateTokenResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'auth.AuthService', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
# This class is part of an EXPERIMENTAL API.
class AuthService(object):
"""Missing associated documentation comment in .proto file."""
@staticmethod
def Register(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/auth.AuthService/Register',
auth__pb2.RegisterRequest.SerializeToString,
auth__pb2.RegisterResponse.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def Login(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/auth.AuthService/Login',
auth__pb2.LoginRequest.SerializeToString,
auth__pb2.LoginResponse.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def ValidateToken(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/auth.AuthService/ValidateToken',
auth__pb2.ValidateTokenRequest.SerializeToString,
auth__pb2.ValidateTokenResponse.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
import grpc
from auth import auth_pb2 as pb2
from auth import auth_pb2_grpc as pb2_grpc
class AuthClient:
def __init__(self):
self.host = '192.168.181.134'
self.server_port = 9000
self.channel = grpc.insecure_channel(f'{self.host}:{self.server_port}')
self.stub = pb2_grpc.AuthServiceStub(self.channel)
def register(self, username, password):
register_request = pb2.RegisterRequest(username=username,
password=password)
return self.stub.Register(register_request)
def login(self, username, password):
login_request = pb2.LoginRequest(username=username, password=password)
return self.stub.Login(login_request)
def validate_token(self, token):
validate_token_request = pb2.ValidateTokenRequest(token=token)
return self.stub.ValidateToken(validate_token_request)
\ No newline at end of file
import json
import functools
from flask import request, Response, jsonify, session, redirect, url_for
from auth.auth import AuthClient
def token_required(func):
"""To validate user with token authentication"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
token = session.get('token') or ''
auth_client = AuthClient()
result = auth_client.validate_token(token=token)
session['user_data'] = json.loads(result.message)
return func(*args, **kwargs)
except Exception as error:
print('error', error)
return redirect(url_for('auth_blueprint.login'))
return wrapper
\ No newline at end of file
html, body {
box-sizing: border-box;
padding: 0;
margin: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
/* =================== Content =================== */
.content-container {
min-height: 100vh;
width: 100%;
background-color: salmon;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.content {
width: 500px;
height: 80vh;
background-color: white;
border-radius: 10px;
overflow-y: auto;
display: flex;
align-items: center;
flex-direction: column;
padding: 20px;
}
.content-title {
border-bottom: 2px solid red;
padding-bottom: 8px;
}
/* =================== Form/Macros =================== */
form {
padding: 20px;
width: 100%;
}
div.input {
margin: 20px auto;
width: 300px;
display: flex;
flex-direction: column;
}
div > label {
padding-bottom: 5px;
font-size: 24px;
}
div > input {
padding: 10px 5px;
border-radius: 5px;
font-size: 22px;
}
div > textarea {
padding: 10px 5px;
border-radius: 5px;
font-size: 22px;
}
button.form-btn {
display: block;
border: none;
background-color: coral;
margin: 10px auto;
margin-top: 50px;
width: 200px;
padding: 10px 20px;
border-radius: 5px;
color: white;
cursor: pointer;
font-size: 24px;
transition: 0.2s;
}
button.form-btn:hover {
background-color: blueviolet;
}
.form-error {
text-align: center;
color: crimson;
font-size: 24px;
}
/* =================== Navbar =================== */
nav ul {
display: flex;
}
nav ul li {
display: block;
}
nav ul li a {
text-decoration: none;
background-color: blueviolet;
color: white;
margin: 10px 20px;
padding: 5px 10px;
font-size: 24px;
border-radius: 5px;
}
/* =================== Todo =================== */
a.item-todo {
text-decoration: none;
color: black;
min-width: 250px;
}
a.item-todo > div {
background-color: #999;
color: white;
padding: 5px 10px;
margin: 10px 10px;
border-radius: 10px;
}
.item-todo h3 {
text-align: center;
}
.item-todo p {
text-align: center;
}
.todo-list {
display: flex;
flex-wrap: wrap;
}
a.goback-btn {
text-decoration: none;
color: black;
display: inline-block;
background-color: blueviolet;
color: white;
padding: 5px 10px;
border-radius: 5px;
}
a.delete-btn {
text-decoration: none;
color: black;
display: inline-block;
background-color: crimson;
color: white;
padding: 5px 10px;
border-radius: 5px;
}
.detail-bottom {
display: flex;
justify-content: space-between;
}
\ No newline at end of file
{% import 'forms.html' as forms %}
{% extends "layout.html" %}
{% block title %}Login Account{% endblock title %}
{% block content_title %}Login{% endblock content_title %}
{% block content %}
{{ forms.form() }}
{% if error %}
<p class="form-error">{{ error }}</p>
{% endif %}
{% endblock content %}
\ No newline at end of file
{% import 'forms.html' as forms %}
{% extends "layout.html" %}
{% block title %}Register Account{% endblock title %}
{% block content_title %}Register{% endblock content_title %}
{% block content %}
{{ forms.form() }}
{% if error %}
<p class="form-error">{{ error }}</p>
{% endif %}
{% endblock content %}
\ No newline at end of file
{% import 'macros.html' as macros %}
{% macro form(action) -%}
<form action="{{ action }}" method="POST">
{{ macros.input('username', 'username', 'Username:') }}
{{ macros.input('password', 'password', 'Password:', type='password') }}
{{ macros.button('Submit') }}
</form>
{%- endmacro %}
\ No newline at end of file
{% extends "layout.html" %}
{% block title %}Welcome Folks{% endblock title %}
{% block content_title %}Hello World{% endblock content_title %}
{% block content %}
<div>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quo, alias quia! Beatae, vel dolores harum, laudantium iusto deserunt illo voluptatibus aut nisi, sit labore officia sequi ducimus repellendus? Maiores, molestias!</p>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quo, alias quia! Beatae, vel dolores harum, laudantium iusto deserunt illo voluptatibus aut nisi, sit labore officia sequi ducimus repellendus? Maiores, molestias!</p>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quo, alias quia! Beatae, vel dolores harum, laudantium iusto deserunt illo voluptatibus aut nisi, sit labore officia sequi ducimus repellendus? Maiores, molestias!</p>
</div>
{% endblock content %}
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
<title>{% block title %}{% endblock title %}</title>
</head>
<body>
<div class="content-container">
<div class="content">
<h1 class="content-title">{% block content_title %}{% endblock content_title %}</h1>
{% block content %}{% endblock content %}
</div>
<nav>
<ul>
{% if session['token'] %}
<li><a href="{{ url_for('todo_blueprint.get_todos') }}">Todos</a></li>
<li><a href="{{ url_for('todo_blueprint.create_todo') }}">Create</a></li>
<li><a href="{{ url_for('auth_blueprint.logout') }}">Logout</a></li>
{% else %}
<li><a href="{{ url_for('auth_blueprint.login') }}">Login</a></li>
<li><a href="{{ url_for('auth_blueprint.register') }}">Register</a></li>
{% endif %}
</ul>
</nav>
</div>
</body>
</html>
\ No newline at end of file
{% macro input(name, id, label, value='', type='text') -%}
<div class="input">
<label for="{{ id }}">{{ label }}</label>
<input type="{{ type }}" value="{{ value|e }}" name="{{ name }}">
</div>
{%- endmacro %}
{% macro textarea(name, id, label, value='') -%}
<div class="input">
<label for="{{ id }}">{{ label }}</label>
<textarea id="{{ id }}" name="{{ name }}" rows="8">{{ value }}</textarea>
</div>
{%- endmacro %}
{% macro button(title) -%}
<button class="form-btn">{{ title }}</button>
{%- endmacro %}
{% macro todo_item(href, title, description) -%}
<a href="{{ href }}" class="item-todo">
<div>
<h3>{{ title }}</h3>
<p>{{ description }}</p>
</div>
</a>
{%- endmacro %}
\ No newline at end of file
{% import 'forms.html' as forms %}
{% import 'macros.html' as macros %}
{% extends "layout.html" %}
{% block title %}Create Todo{% endblock title %}
{% block content_title %}Create Todo{% endblock content_title %}
{% block content %}
<div>
<form action="{{ action }}" method="POST">
{{ macros.input('title', 'title', 'Title:') }}
{{ macros.textarea('description', 'description', 'Description:') }}
{{ macros.button('Submit') }}
</form>
{% if error %}
<p class="form-error">{{ error }}</p>
{% endif %}
</div>
{% endblock content %}
\ No newline at end of file
{% import 'forms.html' as forms %}
{% import 'macros.html' as macros %}
{% extends "layout.html" %}
{% block title %}Detail Todo{% endblock title %}
{% block content_title %}Detail Todo{% endblock content_title %}
{% block content %}
<div>
<form action="{{ url_for('todo_blueprint.update_todo', todo_id=todo.id) }}" method="POST">
{{ macros.input('title', 'title-', 'Title:', value=todo.title) }}
{{ macros.textarea('description', 'description-', 'Description:', value=todo.description) }}
{{ macros.button('Submit') }}
</form>
<div class="detail-bottom">
<a href="{{ url_for('todo_blueprint.get_todos') }}" class="goback-btn">Go back</a>
<a href="{{ url_for('todo_blueprint.delete_todo', todo_id=todo.id) }}" class="delete-btn">Delete</a>
</div>
{% if error %}
<p class="form-error">{{ error }}</p>
{% endif %}
</div>
{% endblock content %}
\ No newline at end of file
{% import 'forms.html' as forms %}
{% import 'macros.html' as macros %}
{% extends "layout.html" %}
{% block title %}Todos List{% endblock title %}
{% block content_title %}Todos List{% endblock content_title %}
{% block content %}
<div class="todo-list">
{% if todos %}
{% for todo in todos -%}
{{ macros.todo_item(url_for('todo_blueprint.get_todo', todo_id=todo.id), todo.title, todo.description)}}
{%- endfor %}
{% else %}
<p>No todos</p>
{% endif %}
</div>
{% endblock content %}
\ No newline at end of file
syntax = "proto3";
package todo;
option go_package = "/todo";
message CreateTodoRequest {
int64 userID = 1;
string title = 2;
string description = 3;
}
message CreateTodoResponse {
bool success = 1;
string message = 2;
}
message GetTodosRequest {
int64 userID = 1;
}
message GetTodosResponse {
bool success = 1;
string message = 2;
string data = 3;
}
message UpdateTodoRequest {
int64 id = 1;
string title = 2;
string description = 3;
}
message UpdateTodoResponse {
bool success = 1;
string message = 2;
}
message DeleteTodoRequest {
int64 id = 1;
}
message DeleteTodoResponse {
bool success = 1;
string message = 2;
}
message GetTodoRequest {
int64 itemID = 1;
int64 userID = 2;
}
message GetTodoResponse {
bool success = 1;
string message = 2;
string data = 3;
}
service TodoService {
rpc CreateTodo(CreateTodoRequest) returns (CreateTodoResponse) {}
rpc GetTodos(GetTodosRequest) returns (GetTodosResponse) {}
rpc GetTodo(GetTodoRequest) returns (GetTodoResponse) {}
rpc UpdateTodo(UpdateTodoRequest) returns (UpdateTodoResponse) {}
rpc DeleteTodo(DeleteTodoRequest) returns (DeleteTodoResponse) {}
}
\ No newline at end of file
import grpc
from . import todo_pb2 as pb2, todo_pb2_grpc as pb2_grpc
class TodoClient:
def __init__(self):
self.host = '192.168.181.134'
self.server_port = 3000
self.channel = grpc.insecure_channel(f'{self.host}:{self.server_port}')
self.stub = pb2_grpc.TodoServiceStub(self.channel)
def create_todo(self, title, description, user_id):
request = pb2.CreateTodoRequest(title=title,
description=description,
userID=user_id)
return self.stub.CreateTodo(request)
def get_todos(self, user_id):
request = pb2.GetTodosRequest(userID=user_id)
return self.stub.GetTodos(request)
def update_todo(self, id, title, description):
request = pb2.UpdateTodoRequest(id=id,
title=title,
description=description)
return self.stub.UpdateTodo(request)
def delete_todo(self, id):
request = pb2.DeleteTodoRequest(id=id)
return self.stub.DeleteTodo(request)
def get_todo(self, item_id, user_id):
request = pb2.GetTodoRequest(itemID=item_id, userID=user_id)
return self.stub.GetTodo(request)
\ No newline at end of file
import json
from flask import (
Blueprint,
g,
jsonify,
request,
render_template,
session,
redirect,
url_for,
)
from todo.client import TodoClient
from middleware.middleware import token_required
todo_blueprint = Blueprint("todo_blueprint", __name__)
@todo_blueprint.route("/create", methods=["GET", "POST"])
@token_required
def create_todo():
if request.method == "POST":
try:
title = request.form["title"]
description = request.form["description"]
user_data = session["user_data"]
if title == "" or description == "":
raise ValueError("Please fill the title and description")
client = TodoClient()
client.create_todo(
title=request.form["title"],
description=description,
user_id=user_data.get("ID"),
)
return redirect(url_for("todo_blueprint.get_todos"))
except Exception as error:
return render_template("todo/create.html", error=str(error))
return render_template("todo/create.html")
@todo_blueprint.route("/get", methods=["GET"])
@token_required
def get_todos():
try:
user_data = session["user_data"]
client = TodoClient()
result = client.get_todos(user_id=user_data.get("ID"))
data = json.loads(result.data)
return render_template("todo/list.html", todos=data)
except Exception as error:
return render_template("todo/list.html", error=str(error))
@todo_blueprint.route("/get/<int:todo_id>", methods=["GET"])
@token_required
def get_todo(todo_id):
try:
user_data = session["user_data"]
client = TodoClient()
result = client.get_todo(item_id=todo_id, user_id=user_data.get("ID"))
data = json.loads(result.data)
return render_template("todo/item.html", todo=data)
except Exception as error:
return render_template("todo/item.html", error=str(error))
@todo_blueprint.route("/update/<int:todo_id>", methods=["POST"])
@token_required
def update_todo(todo_id):
try:
user_data = session["user_data"]
client = TodoClient()
client.update_todo(todo_id, request.form["title"], request.form["description"])
result_get = client.get_todo(todo_id, user_data.get("ID"))
json.loads(result_get.data)
return redirect(url_for("todo_blueprint.get_todos"))
except Exception as error:
return render_template("todo/item.html", error=str(error))
@todo_blueprint.route("/delete/<int:todo_id>", methods=["GET"])
@token_required
def delete_todo(todo_id):
try:
client = TodoClient()
client.delete_todo(todo_id)
return redirect(url_for("todo_blueprint.get_todos"))
except Exception as error:
return render_template("todo/item.html", error=str(error))
\ No newline at end of file
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: todo.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\ntodo.proto\x12\x04todo\"G\n\x11\x43reateTodoRequest\x12\x0e\n\x06userID\x18\x01 \x01(\x03\x12\r\n\x05title\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\"6\n\x12\x43reateTodoResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t\"!\n\x0fGetTodosRequest\x12\x0e\n\x06userID\x18\x01 \x01(\x03\"B\n\x10GetTodosResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\t\"C\n\x11UpdateTodoRequest\x12\n\n\x02id\x18\x01 \x01(\x03\x12\r\n\x05title\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\"6\n\x12UpdateTodoResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t\"\x1f\n\x11\x44\x65leteTodoRequest\x12\n\n\x02id\x18\x01 \x01(\x03\"6\n\x12\x44\x65leteTodoResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t\"0\n\x0eGetTodoRequest\x12\x0e\n\x06itemID\x18\x01 \x01(\x03\x12\x0e\n\x06userID\x18\x02 \x01(\x03\"A\n\x0fGetTodoResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\t2\xcd\x02\n\x0bTodoService\x12\x41\n\nCreateTodo\x12\x17.todo.CreateTodoRequest\x1a\x18.todo.CreateTodoResponse\"\x00\x12;\n\x08GetTodos\x12\x15.todo.GetTodosRequest\x1a\x16.todo.GetTodosResponse\"\x00\x12\x38\n\x07GetTodo\x12\x14.todo.GetTodoRequest\x1a\x15.todo.GetTodoResponse\"\x00\x12\x41\n\nUpdateTodo\x12\x17.todo.UpdateTodoRequest\x1a\x18.todo.UpdateTodoResponse\"\x00\x12\x41\n\nDeleteTodo\x12\x17.todo.DeleteTodoRequest\x1a\x18.todo.DeleteTodoResponse\"\x00\x42\x07Z\x05/todob\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'todo_pb2', _globals)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'Z\005/todo'
_globals['_CREATETODOREQUEST']._serialized_start=20
_globals['_CREATETODOREQUEST']._serialized_end=91
_globals['_CREATETODORESPONSE']._serialized_start=93
_globals['_CREATETODORESPONSE']._serialized_end=147
_globals['_GETTODOSREQUEST']._serialized_start=149
_globals['_GETTODOSREQUEST']._serialized_end=182
_globals['_GETTODOSRESPONSE']._serialized_start=184
_globals['_GETTODOSRESPONSE']._serialized_end=250
_globals['_UPDATETODOREQUEST']._serialized_start=252
_globals['_UPDATETODOREQUEST']._serialized_end=319
_globals['_UPDATETODORESPONSE']._serialized_start=321
_globals['_UPDATETODORESPONSE']._serialized_end=375
_globals['_DELETETODOREQUEST']._serialized_start=377
_globals['_DELETETODOREQUEST']._serialized_end=408
_globals['_DELETETODORESPONSE']._serialized_start=410
_globals['_DELETETODORESPONSE']._serialized_end=464
_globals['_GETTODOREQUEST']._serialized_start=466
_globals['_GETTODOREQUEST']._serialized_end=514
_globals['_GETTODORESPONSE']._serialized_start=516
_globals['_GETTODORESPONSE']._serialized_end=581
_globals['_TODOSERVICE']._serialized_start=584
_globals['_TODOSERVICE']._serialized_end=917
# @@protoc_insertion_point(module_scope)
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
import todo.todo_pb2 as todo__pb2
class TodoServiceStub(object):
"""Missing associated documentation comment in .proto file."""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.CreateTodo = channel.unary_unary(
'/todo.TodoService/CreateTodo',
request_serializer=todo__pb2.CreateTodoRequest.SerializeToString,
response_deserializer=todo__pb2.CreateTodoResponse.FromString,
)
self.GetTodos = channel.unary_unary(
'/todo.TodoService/GetTodos',
request_serializer=todo__pb2.GetTodosRequest.SerializeToString,
response_deserializer=todo__pb2.GetTodosResponse.FromString,
)
self.GetTodo = channel.unary_unary(
'/todo.TodoService/GetTodo',
request_serializer=todo__pb2.GetTodoRequest.SerializeToString,
response_deserializer=todo__pb2.GetTodoResponse.FromString,
)
self.UpdateTodo = channel.unary_unary(
'/todo.TodoService/UpdateTodo',
request_serializer=todo__pb2.UpdateTodoRequest.SerializeToString,
response_deserializer=todo__pb2.UpdateTodoResponse.FromString,
)
self.DeleteTodo = channel.unary_unary(
'/todo.TodoService/DeleteTodo',
request_serializer=todo__pb2.DeleteTodoRequest.SerializeToString,
response_deserializer=todo__pb2.DeleteTodoResponse.FromString,
)
class TodoServiceServicer(object):
"""Missing associated documentation comment in .proto file."""
def CreateTodo(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def GetTodos(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def GetTodo(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def UpdateTodo(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def DeleteTodo(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_TodoServiceServicer_to_server(servicer, server):
rpc_method_handlers = {
'CreateTodo': grpc.unary_unary_rpc_method_handler(
servicer.CreateTodo,
request_deserializer=todo__pb2.CreateTodoRequest.FromString,
response_serializer=todo__pb2.CreateTodoResponse.SerializeToString,
),
'GetTodos': grpc.unary_unary_rpc_method_handler(
servicer.GetTodos,
request_deserializer=todo__pb2.GetTodosRequest.FromString,
response_serializer=todo__pb2.GetTodosResponse.SerializeToString,
),
'GetTodo': grpc.unary_unary_rpc_method_handler(
servicer.GetTodo,
request_deserializer=todo__pb2.GetTodoRequest.FromString,
response_serializer=todo__pb2.GetTodoResponse.SerializeToString,
),
'UpdateTodo': grpc.unary_unary_rpc_method_handler(
servicer.UpdateTodo,
request_deserializer=todo__pb2.UpdateTodoRequest.FromString,
response_serializer=todo__pb2.UpdateTodoResponse.SerializeToString,
),
'DeleteTodo': grpc.unary_unary_rpc_method_handler(
servicer.DeleteTodo,
request_deserializer=todo__pb2.DeleteTodoRequest.FromString,
response_serializer=todo__pb2.DeleteTodoResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'todo.TodoService', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
# This class is part of an EXPERIMENTAL API.
class TodoService(object):
"""Missing associated documentation comment in .proto file."""
@staticmethod
def CreateTodo(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/todo.TodoService/CreateTodo',
todo__pb2.CreateTodoRequest.SerializeToString,
todo__pb2.CreateTodoResponse.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def GetTodos(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/todo.TodoService/GetTodos',
todo__pb2.GetTodosRequest.SerializeToString,
todo__pb2.GetTodosResponse.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def GetTodo(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/todo.TodoService/GetTodo',
todo__pb2.GetTodoRequest.SerializeToString,
todo__pb2.GetTodoResponse.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def UpdateTodo(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/todo.TodoService/UpdateTodo',
todo__pb2.UpdateTodoRequest.SerializeToString,
todo__pb2.UpdateTodoResponse.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def DeleteTodo(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/todo.TodoService/DeleteTodo',
todo__pb2.DeleteTodoRequest.SerializeToString,
todo__pb2.DeleteTodoResponse.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
<#
.Synopsis
Activate a Python virtual environment for the current PowerShell session.
.Description
Pushes the python executable for a virtual environment to the front of the
$Env:PATH environment variable and sets the prompt to signify that you are
in a Python virtual environment. Makes use of the command line switches as
well as the `pyvenv.cfg` file values present in the virtual environment.
.Parameter VenvDir
Path to the directory that contains the virtual environment to activate. The
default value for this is the parent of the directory that the Activate.ps1
script is located within.
.Parameter Prompt
The prompt prefix to display when this virtual environment is activated. By
default, this prompt is the name of the virtual environment folder (VenvDir)
surrounded by parentheses and followed by a single space (ie. '(.venv) ').
.Example
Activate.ps1
Activates the Python virtual environment that contains the Activate.ps1 script.
.Example
Activate.ps1 -Verbose
Activates the Python virtual environment that contains the Activate.ps1 script,
and shows extra information about the activation as it executes.
.Example
Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
Activates the Python virtual environment located in the specified location.
.Example
Activate.ps1 -Prompt "MyPython"
Activates the Python virtual environment that contains the Activate.ps1 script,
and prefixes the current prompt with the specified string (surrounded in
parentheses) while the virtual environment is active.
.Notes
On Windows, it may be required to enable this Activate.ps1 script by setting the
execution policy for the user. You can do this by issuing the following PowerShell
command:
PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
For more information on Execution Policies:
https://go.microsoft.com/fwlink/?LinkID=135170
#>
Param(
[Parameter(Mandatory = $false)]
[String]
$VenvDir,
[Parameter(Mandatory = $false)]
[String]
$Prompt
)
<# Function declarations --------------------------------------------------- #>
<#
.Synopsis
Remove all shell session elements added by the Activate script, including the
addition of the virtual environment's Python executable from the beginning of
the PATH variable.
.Parameter NonDestructive
If present, do not remove this function from the global namespace for the
session.
#>
function global:deactivate ([switch]$NonDestructive) {
# Revert to original values
# The prior prompt:
if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
}
# The prior PYTHONHOME:
if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
}
# The prior PATH:
if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
Remove-Item -Path Env:_OLD_VIRTUAL_PATH
}
# Just remove the VIRTUAL_ENV altogether:
if (Test-Path -Path Env:VIRTUAL_ENV) {
Remove-Item -Path env:VIRTUAL_ENV
}
# Just remove VIRTUAL_ENV_PROMPT altogether.
if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
Remove-Item -Path env:VIRTUAL_ENV_PROMPT
}
# Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
}
# Leave deactivate function in the global namespace if requested:
if (-not $NonDestructive) {
Remove-Item -Path function:deactivate
}
}
<#
.Description
Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
given folder, and returns them in a map.
For each line in the pyvenv.cfg file, if that line can be parsed into exactly
two strings separated by `=` (with any amount of whitespace surrounding the =)
then it is considered a `key = value` line. The left hand string is the key,
the right hand is the value.
If the value starts with a `'` or a `"` then the first and last character is
stripped from the value before being captured.
.Parameter ConfigDir
Path to the directory that contains the `pyvenv.cfg` file.
#>
function Get-PyVenvConfig(
[String]
$ConfigDir
) {
Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
# Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
$pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
# An empty map will be returned if no config file is found.
$pyvenvConfig = @{ }
if ($pyvenvConfigPath) {
Write-Verbose "File exists, parse `key = value` lines"
$pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
$pyvenvConfigContent | ForEach-Object {
$keyval = $PSItem -split "\s*=\s*", 2
if ($keyval[0] -and $keyval[1]) {
$val = $keyval[1]
# Remove extraneous quotations around a string value.
if ("'""".Contains($val.Substring(0, 1))) {
$val = $val.Substring(1, $val.Length - 2)
}
$pyvenvConfig[$keyval[0]] = $val
Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
}
}
}
return $pyvenvConfig
}
<# Begin Activate script --------------------------------------------------- #>
# Determine the containing directory of this script
$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
$VenvExecDir = Get-Item -Path $VenvExecPath
Write-Verbose "Activation script is located in path: '$VenvExecPath'"
Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
# Set values required in priority: CmdLine, ConfigFile, Default
# First, get the location of the virtual environment, it might not be
# VenvExecDir if specified on the command line.
if ($VenvDir) {
Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
}
else {
Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
$VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
Write-Verbose "VenvDir=$VenvDir"
}
# Next, read the `pyvenv.cfg` file to determine any required value such
# as `prompt`.
$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
# Next, set the prompt from the command line, or the config file, or
# just use the name of the virtual environment folder.
if ($Prompt) {
Write-Verbose "Prompt specified as argument, using '$Prompt'"
}
else {
Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
$Prompt = $pyvenvCfg['prompt'];
}
else {
Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
$Prompt = Split-Path -Path $venvDir -Leaf
}
}
Write-Verbose "Prompt = '$Prompt'"
Write-Verbose "VenvDir='$VenvDir'"
# Deactivate any currently active virtual environment, but leave the
# deactivate function in place.
deactivate -nondestructive
# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
# that there is an activated venv.
$env:VIRTUAL_ENV = $VenvDir
if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
Write-Verbose "Setting prompt to '$Prompt'"
# Set the prompt to include the env name
# Make sure _OLD_VIRTUAL_PROMPT is global
function global:_OLD_VIRTUAL_PROMPT { "" }
Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
function global:prompt {
Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
_OLD_VIRTUAL_PROMPT
}
$env:VIRTUAL_ENV_PROMPT = $Prompt
}
# Clear PYTHONHOME
if (Test-Path -Path Env:PYTHONHOME) {
Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
Remove-Item -Path Env:PYTHONHOME
}
# Add the venv to the PATH
Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
# This file must be used with "source bin/activate" *from bash*
# you cannot run it directly
deactivate () {
# reset old environment variables
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
PATH="${_OLD_VIRTUAL_PATH:-}"
export PATH
unset _OLD_VIRTUAL_PATH
fi
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
export PYTHONHOME
unset _OLD_VIRTUAL_PYTHONHOME
fi
# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
hash -r 2> /dev/null
fi
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
PS1="${_OLD_VIRTUAL_PS1:-}"
export PS1
unset _OLD_VIRTUAL_PS1
fi
unset VIRTUAL_ENV
unset VIRTUAL_ENV_PROMPT
if [ ! "${1:-}" = "nondestructive" ] ; then
# Self destruct!
unset -f deactivate
fi
}
# unset irrelevant variables
deactivate nondestructive
VIRTUAL_ENV="/home/ahmad/my-main-service/venv"
export VIRTUAL_ENV
_OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/bin:$PATH"
export PATH
# unset PYTHONHOME if set
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
# could use `if (set -u; : $PYTHONHOME) ;` in bash
if [ -n "${PYTHONHOME:-}" ] ; then
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
unset PYTHONHOME
fi
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
_OLD_VIRTUAL_PS1="${PS1:-}"
PS1="(venv) ${PS1:-}"
export PS1
VIRTUAL_ENV_PROMPT="(venv) "
export VIRTUAL_ENV_PROMPT
fi
# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
hash -r 2> /dev/null
fi
# This file must be used with "source bin/activate.csh" *from csh*.
# You cannot run it directly.
# Created by Davide Di Blasi <davidedb@gmail.com>.
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'
# Unset irrelevant variables.
deactivate nondestructive
setenv VIRTUAL_ENV "/home/ahmad/my-main-service/venv"
set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/bin:$PATH"
set _OLD_VIRTUAL_PROMPT="$prompt"
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
set prompt = "(venv) $prompt"
setenv VIRTUAL_ENV_PROMPT "(venv) "
endif
alias pydoc python -m pydoc
rehash
# This file must be used with "source <venv>/bin/activate.fish" *from fish*
# (https://fishshell.com/); you cannot run it directly.
function deactivate -d "Exit virtual environment and return to normal shell environment"
# reset old environment variables
if test -n "$_OLD_VIRTUAL_PATH"
set -gx PATH $_OLD_VIRTUAL_PATH
set -e _OLD_VIRTUAL_PATH
end
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
set -e _OLD_VIRTUAL_PYTHONHOME
end
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
set -e _OLD_FISH_PROMPT_OVERRIDE
# prevents error when using nested fish instances (Issue #93858)
if functions -q _old_fish_prompt
functions -e fish_prompt
functions -c _old_fish_prompt fish_prompt
functions -e _old_fish_prompt
end
end
set -e VIRTUAL_ENV
set -e VIRTUAL_ENV_PROMPT
if test "$argv[1]" != "nondestructive"
# Self-destruct!
functions -e deactivate
end
end
# Unset irrelevant variables.
deactivate nondestructive
set -gx VIRTUAL_ENV "/home/ahmad/my-main-service/venv"
set -gx _OLD_VIRTUAL_PATH $PATH
set -gx PATH "$VIRTUAL_ENV/bin" $PATH
# Unset PYTHONHOME if set.
if set -q PYTHONHOME
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
set -e PYTHONHOME
end
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
# fish uses a function instead of an env var to generate the prompt.
# Save the current fish_prompt function as the function _old_fish_prompt.
functions -c fish_prompt _old_fish_prompt
# With the original prompt function renamed, we can override with our own.
function fish_prompt
# Save the return status of the last command.
set -l old_status $status
# Output the venv prompt; color taken from the blue of the Python logo.
printf "%s%s%s" (set_color 4B8BBE) "(venv) " (set_color normal)
# Restore the return status of the previous command.
echo "exit $old_status" | .
# Output the original/"old" prompt.
_old_fish_prompt
end
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
set -gx VIRTUAL_ENV_PROMPT "(venv) "
end
#!/home/ahmad/my-main-service/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from flask.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
#!/home/ahmad/my-main-service/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
#!/home/ahmad/my-main-service/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
#!/home/ahmad/my-main-service/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
Copyright 2007 Pallets
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Metadata-Version: 2.1
Name: Jinja2
Version: 3.1.2
Summary: A very fast and expressive template engine.
Home-page: https://palletsprojects.com/p/jinja/
Author: Armin Ronacher
Author-email: armin.ronacher@active-4.com
Maintainer: Pallets
Maintainer-email: contact@palletsprojects.com
License: BSD-3-Clause
Project-URL: Donate, https://palletsprojects.com/donate
Project-URL: Documentation, https://jinja.palletsprojects.com/
Project-URL: Changes, https://jinja.palletsprojects.com/changes/
Project-URL: Source Code, https://github.com/pallets/jinja/
Project-URL: Issue Tracker, https://github.com/pallets/jinja/issues/
Project-URL: Twitter, https://twitter.com/PalletsTeam
Project-URL: Chat, https://discord.gg/pallets
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Text Processing :: Markup :: HTML
Requires-Python: >=3.7
Description-Content-Type: text/x-rst
License-File: LICENSE.rst
Requires-Dist: MarkupSafe (>=2.0)
Provides-Extra: i18n
Requires-Dist: Babel (>=2.7) ; extra == 'i18n'
Jinja
=====
Jinja is a fast, expressive, extensible templating engine. Special
placeholders in the template allow writing code similar to Python
syntax. Then the template is passed data to render the final document.
It includes:
- Template inheritance and inclusion.
- Define and import macros within templates.
- HTML templates can use autoescaping to prevent XSS from untrusted
user input.
- A sandboxed environment can safely render untrusted templates.
- AsyncIO support for generating templates and calling async
functions.
- I18N support with Babel.
- Templates are compiled to optimized Python code just-in-time and
cached, or can be compiled ahead-of-time.
- Exceptions point to the correct line in templates to make debugging
easier.
- Extensible filters, tests, functions, and even syntax.
Jinja's philosophy is that while application logic belongs in Python if
possible, it shouldn't make the template designer's job difficult by
restricting functionality too much.
Installing
----------
Install and update using `pip`_:
.. code-block:: text
$ pip install -U Jinja2
.. _pip: https://pip.pypa.io/en/stable/getting-started/
In A Nutshell
-------------
.. code-block:: jinja
{% extends "base.html" %}
{% block title %}Members{% endblock %}
{% block content %}
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>
{% endblock %}
Donate
------
The Pallets organization develops and supports Jinja and other popular
packages. In order to grow the community of contributors and users, and
allow the maintainers to devote more time to the projects, `please
donate today`_.
.. _please donate today: https://palletsprojects.com/donate
Links
-----
- Documentation: https://jinja.palletsprojects.com/
- Changes: https://jinja.palletsprojects.com/changes/
- PyPI Releases: https://pypi.org/project/Jinja2/
- Source Code: https://github.com/pallets/jinja/
- Issue Tracker: https://github.com/pallets/jinja/issues/
- Website: https://palletsprojects.com/p/jinja/
- Twitter: https://twitter.com/PalletsTeam
- Chat: https://discord.gg/pallets
Jinja2-3.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
Jinja2-3.1.2.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475
Jinja2-3.1.2.dist-info/METADATA,sha256=PZ6v2SIidMNixR7MRUX9f7ZWsPwtXanknqiZUmRbh4U,3539
Jinja2-3.1.2.dist-info/RECORD,,
Jinja2-3.1.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
Jinja2-3.1.2.dist-info/entry_points.txt,sha256=zRd62fbqIyfUpsRtU7EVIFyiu1tPwfgO7EvPErnxgTE,59
Jinja2-3.1.2.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7
jinja2/__init__.py,sha256=8vGduD8ytwgD6GDSqpYc2m3aU-T7PKOAddvVXgGr_Fs,1927
jinja2/__pycache__/__init__.cpython-310.pyc,,
jinja2/__pycache__/_identifier.cpython-310.pyc,,
jinja2/__pycache__/async_utils.cpython-310.pyc,,
jinja2/__pycache__/bccache.cpython-310.pyc,,
jinja2/__pycache__/compiler.cpython-310.pyc,,
jinja2/__pycache__/constants.cpython-310.pyc,,
jinja2/__pycache__/debug.cpython-310.pyc,,
jinja2/__pycache__/defaults.cpython-310.pyc,,
jinja2/__pycache__/environment.cpython-310.pyc,,
jinja2/__pycache__/exceptions.cpython-310.pyc,,
jinja2/__pycache__/ext.cpython-310.pyc,,
jinja2/__pycache__/filters.cpython-310.pyc,,
jinja2/__pycache__/idtracking.cpython-310.pyc,,
jinja2/__pycache__/lexer.cpython-310.pyc,,
jinja2/__pycache__/loaders.cpython-310.pyc,,
jinja2/__pycache__/meta.cpython-310.pyc,,
jinja2/__pycache__/nativetypes.cpython-310.pyc,,
jinja2/__pycache__/nodes.cpython-310.pyc,,
jinja2/__pycache__/optimizer.cpython-310.pyc,,
jinja2/__pycache__/parser.cpython-310.pyc,,
jinja2/__pycache__/runtime.cpython-310.pyc,,
jinja2/__pycache__/sandbox.cpython-310.pyc,,
jinja2/__pycache__/tests.cpython-310.pyc,,
jinja2/__pycache__/utils.cpython-310.pyc,,
jinja2/__pycache__/visitor.cpython-310.pyc,,
jinja2/_identifier.py,sha256=_zYctNKzRqlk_murTNlzrju1FFJL7Va_Ijqqd7ii2lU,1958
jinja2/async_utils.py,sha256=dHlbTeaxFPtAOQEYOGYh_PHcDT0rsDaUJAFDl_0XtTg,2472
jinja2/bccache.py,sha256=mhz5xtLxCcHRAa56azOhphIAe19u1we0ojifNMClDio,14061
jinja2/compiler.py,sha256=Gs-N8ThJ7OWK4-reKoO8Wh1ZXz95MVphBKNVf75qBr8,72172
jinja2/constants.py,sha256=GMoFydBF_kdpaRKPoM5cl5MviquVRLVyZtfp5-16jg0,1433
jinja2/debug.py,sha256=iWJ432RadxJNnaMOPrjIDInz50UEgni3_HKuFXi2vuQ,6299
jinja2/defaults.py,sha256=boBcSw78h-lp20YbaXSJsqkAI2uN_mD_TtCydpeq5wU,1267
jinja2/environment.py,sha256=6uHIcc7ZblqOMdx_uYNKqRnnwAF0_nzbyeMP9FFtuh4,61349
jinja2/exceptions.py,sha256=ioHeHrWwCWNaXX1inHmHVblvc4haO7AXsjCp3GfWvx0,5071
jinja2/ext.py,sha256=ivr3P7LKbddiXDVez20EflcO3q2aHQwz9P_PgWGHVqE,31502
jinja2/filters.py,sha256=9js1V-h2RlyW90IhLiBGLM2U-k6SCy2F4BUUMgB3K9Q,53509
jinja2/idtracking.py,sha256=GfNmadir4oDALVxzn3DL9YInhJDr69ebXeA2ygfuCGA,10704
jinja2/lexer.py,sha256=DW2nX9zk-6MWp65YR2bqqj0xqCvLtD-u9NWT8AnFRxQ,29726
jinja2/loaders.py,sha256=BfptfvTVpClUd-leMkHczdyPNYFzp_n7PKOJ98iyHOg,23207
jinja2/meta.py,sha256=GNPEvifmSaU3CMxlbheBOZjeZ277HThOPUTf1RkppKQ,4396
jinja2/nativetypes.py,sha256=DXgORDPRmVWgy034H0xL8eF7qYoK3DrMxs-935d0Fzk,4226
jinja2/nodes.py,sha256=i34GPRAZexXMT6bwuf5SEyvdmS-bRCy9KMjwN5O6pjk,34550
jinja2/optimizer.py,sha256=tHkMwXxfZkbfA1KmLcqmBMSaz7RLIvvItrJcPoXTyD8,1650
jinja2/parser.py,sha256=nHd-DFHbiygvfaPtm9rcQXJChZG7DPsWfiEsqfwKerY,39595
jinja2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
jinja2/runtime.py,sha256=5CmD5BjbEJxSiDNTFBeKCaq8qU4aYD2v6q2EluyExms,33476
jinja2/sandbox.py,sha256=Y0xZeXQnH6EX5VjaV2YixESxoepnRbW_3UeQosaBU3M,14584
jinja2/tests.py,sha256=Am5Z6Lmfr2XaH_npIfJJ8MdXtWsbLjMULZJulTAj30E,5905
jinja2/utils.py,sha256=u9jXESxGn8ATZNVolwmkjUVu4SA-tLgV0W7PcSfPfdQ,23965
jinja2/visitor.py,sha256=MH14C6yq24G_KVtWzjwaI7Wg14PCJIYlWW1kpkxYak0,3568
Wheel-Version: 1.0
Generator: bdist_wheel (0.37.1)
Root-Is-Purelib: true
Tag: py3-none-any
Copyright 2010 Pallets
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Metadata-Version: 2.1
Name: MarkupSafe
Version: 2.1.3
Summary: Safely add untrusted strings to HTML/XML markup.
Home-page: https://palletsprojects.com/p/markupsafe/
Maintainer: Pallets
Maintainer-email: contact@palletsprojects.com
License: BSD-3-Clause
Project-URL: Donate, https://palletsprojects.com/donate
Project-URL: Documentation, https://markupsafe.palletsprojects.com/
Project-URL: Changes, https://markupsafe.palletsprojects.com/changes/
Project-URL: Source Code, https://github.com/pallets/markupsafe/
Project-URL: Issue Tracker, https://github.com/pallets/markupsafe/issues/
Project-URL: Chat, https://discord.gg/pallets
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Text Processing :: Markup :: HTML
Requires-Python: >=3.7
Description-Content-Type: text/x-rst
License-File: LICENSE.rst
MarkupSafe
==========
MarkupSafe implements a text object that escapes characters so it is
safe to use in HTML and XML. Characters that have special meanings are
replaced so that they display as the actual characters. This mitigates
injection attacks, meaning untrusted user input can safely be displayed
on a page.
Installing
----------
Install and update using `pip`_:
.. code-block:: text
pip install -U MarkupSafe
.. _pip: https://pip.pypa.io/en/stable/getting-started/
Examples
--------
.. code-block:: pycon
>>> from markupsafe import Markup, escape
>>> # escape replaces special characters and wraps in Markup
>>> escape("<script>alert(document.cookie);</script>")
Markup('&lt;script&gt;alert(document.cookie);&lt;/script&gt;')
>>> # wrap in Markup to mark text "safe" and prevent escaping
>>> Markup("<strong>Hello</strong>")
Markup('<strong>hello</strong>')
>>> escape(Markup("<strong>Hello</strong>"))
Markup('<strong>hello</strong>')
>>> # Markup is a str subclass
>>> # methods and operators escape their arguments
>>> template = Markup("Hello <em>{name}</em>")
>>> template.format(name='"World"')
Markup('Hello <em>&#34;World&#34;</em>')
Donate
------
The Pallets organization develops and supports MarkupSafe and other
popular packages. In order to grow the community of contributors and
users, and allow the maintainers to devote more time to the projects,
`please donate today`_.
.. _please donate today: https://palletsprojects.com/donate
Links
-----
- Documentation: https://markupsafe.palletsprojects.com/
- Changes: https://markupsafe.palletsprojects.com/changes/
- PyPI Releases: https://pypi.org/project/MarkupSafe/
- Source Code: https://github.com/pallets/markupsafe/
- Issue Tracker: https://github.com/pallets/markupsafe/issues/
- Chat: https://discord.gg/pallets
MarkupSafe-2.1.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
MarkupSafe-2.1.3.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475
MarkupSafe-2.1.3.dist-info/METADATA,sha256=Wvvh4Tz-YtW24YagYdqrrrBdm9m-DjTdqJWhxlbU6-0,3003
MarkupSafe-2.1.3.dist-info/RECORD,,
MarkupSafe-2.1.3.dist-info/WHEEL,sha256=iZaXX0Td62Nww8bojl0E84uJHjT41csHPKZmbUBbJPs,152
MarkupSafe-2.1.3.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11
markupsafe/__init__.py,sha256=xIItqrn1Bwi7FxPJO9rCVQBG0Evewue1Tl4BV0l9xEs,10338
markupsafe/__pycache__/__init__.cpython-310.pyc,,
markupsafe/__pycache__/_native.cpython-310.pyc,,
markupsafe/_native.py,sha256=GR86Qvo_GcgKmKreA1WmYN9ud17OFwkww8E-fiW-57s,1713
markupsafe/_speedups.c,sha256=X2XvQVtIdcK4Usz70BvkzoOfjTCmQlDkkjYSn-swE0g,7083
markupsafe/_speedups.cpython-310-x86_64-linux-gnu.so,sha256=huh9xBZy3L1q1ar3y-f44Ozfa25Rg6xiomsq8MThk_Y,44240
markupsafe/_speedups.pyi,sha256=vfMCsOgbAXRNLUXkyuyonG8uEWKYU4PDqNuMaDELAYw,229
markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
Wheel-Version: 1.0
Generator: bdist_wheel (0.40.0)
Root-Is-Purelib: false
Tag: cp310-cp310-manylinux_2_17_x86_64
Tag: cp310-cp310-manylinux2014_x86_64
import sys
import os
import re
import importlib
import warnings
is_pypy = '__pypy__' in sys.builtin_module_names
warnings.filterwarnings('ignore',
r'.+ distutils\b.+ deprecated',
DeprecationWarning)
def warn_distutils_present():
if 'distutils' not in sys.modules:
return
if is_pypy and sys.version_info < (3, 7):
# PyPy for 3.6 unconditionally imports distutils, so bypass the warning
# https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250
return
warnings.warn(
"Distutils was imported before Setuptools, but importing Setuptools "
"also replaces the `distutils` module in `sys.modules`. This may lead "
"to undesirable behaviors or errors. To avoid these issues, avoid "
"using distutils directly, ensure that setuptools is installed in the "
"traditional way (e.g. not an editable install), and/or make sure "
"that setuptools is always imported before distutils.")
def clear_distutils():
if 'distutils' not in sys.modules:
return
warnings.warn("Setuptools is replacing distutils.")
mods = [name for name in sys.modules if re.match(r'distutils\b', name)]
for name in mods:
del sys.modules[name]
def enabled():
"""
Allow selection of distutils by environment variable.
"""
which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'stdlib')
return which == 'local'
def ensure_local_distutils():
clear_distutils()
# With the DistutilsMetaFinder in place,
# perform an import to cause distutils to be
# loaded from setuptools._distutils. Ref #2906.
add_shim()
importlib.import_module('distutils')
remove_shim()
# check that submodules load as expected
core = importlib.import_module('distutils.core')
assert '_distutils' in core.__file__, core.__file__
def do_override():
"""
Ensure that the local copy of distutils is preferred over stdlib.
See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401
for more motivation.
"""
if enabled():
warn_distutils_present()
ensure_local_distutils()
class DistutilsMetaFinder:
def find_spec(self, fullname, path, target=None):
if path is not None:
return
method_name = 'spec_for_{fullname}'.format(**locals())
method = getattr(self, method_name, lambda: None)
return method()
def spec_for_distutils(self):
import importlib.abc
import importlib.util
class DistutilsLoader(importlib.abc.Loader):
def create_module(self, spec):
return importlib.import_module('setuptools._distutils')
def exec_module(self, module):
pass
return importlib.util.spec_from_loader('distutils', DistutilsLoader())
def spec_for_pip(self):
"""
Ensure stdlib distutils when running under pip.
See pypa/pip#8761 for rationale.
"""
if self.pip_imported_during_build():
return
clear_distutils()
self.spec_for_distutils = lambda: None
@staticmethod
def pip_imported_during_build():
"""
Detect if pip is being imported in a build script. Ref #2355.
"""
import traceback
return any(
frame.f_globals['__file__'].endswith('setup.py')
for frame, line in traceback.walk_stack(None)
)
DISTUTILS_FINDER = DistutilsMetaFinder()
def add_shim():
sys.meta_path.insert(0, DISTUTILS_FINDER)
def remove_shim():
try:
sys.meta_path.remove(DISTUTILS_FINDER)
except ValueError:
pass
Copyright 2010 Jason Kirtland
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Metadata-Version: 2.1
Name: blinker
Version: 1.6.3
Summary: Fast, simple object-to-object and broadcast signaling
Keywords: signal,emit,events,broadcast
Author-email: Jason Kirtland <jek@discorporate.us>
Maintainer-email: Pallets Ecosystem <contact@palletsprojects.com>
Requires-Python: >=3.7
Description-Content-Type: text/x-rst
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries
Project-URL: Chat, https://discord.gg/pallets
Project-URL: Documentation, https://blinker.readthedocs.io
Project-URL: Homepage, https://blinker.readthedocs.io
Project-URL: Issue Tracker, https://github.com/pallets-eco/blinker/issues/
Project-URL: Source Code, https://github.com/pallets-eco/blinker/
Blinker
=======
Blinker provides a fast dispatching system that allows any number of
interested parties to subscribe to events, or "signals".
Signal receivers can subscribe to specific senders or receive signals
sent by any sender.
.. code-block:: pycon
>>> from blinker import signal
>>> started = signal('round-started')
>>> def each(round):
... print(f"Round {round}")
...
>>> started.connect(each)
>>> def round_two(round):
... print("This is round two.")
...
>>> started.connect(round_two, sender=2)
>>> for round in range(1, 4):
... started.send(round)
...
Round 1!
Round 2!
This is round two.
Round 3!
Links
-----
- Documentation: https://blinker.readthedocs.io/
- Changes: https://blinker.readthedocs.io/#changes
- PyPI Releases: https://pypi.org/project/blinker/
- Source Code: https://github.com/pallets-eco/blinker/
- Issue Tracker: https://github.com/pallets-eco/blinker/issues/
blinker-1.6.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
blinker-1.6.3.dist-info/LICENSE.rst,sha256=nrc6HzhZekqhcCXSrhvjg5Ykx5XphdTw6Xac4p-spGc,1054
blinker-1.6.3.dist-info/METADATA,sha256=yDLuXpi6nLMwYYWJlGDIBvbZxFZH23JHbdxPGzIU4vg,1918
blinker-1.6.3.dist-info/RECORD,,
blinker-1.6.3.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
blinker/__init__.py,sha256=E7dbyl7JyaK4RbWHlGrWY3mQ8d3BEnxRCeKQnqMa0bw,408
blinker/__pycache__/__init__.cpython-310.pyc,,
blinker/__pycache__/_saferef.cpython-310.pyc,,
blinker/__pycache__/_utilities.cpython-310.pyc,,
blinker/__pycache__/base.cpython-310.pyc,,
blinker/_saferef.py,sha256=kWOTIWnCY3kOb8lZP74Rbx7bR_BLVg4TjwzNCRLhKHs,9096
blinker/_utilities.py,sha256=GPXtJzykzVotoxHC79mgFQMPJtICwpVDCCpus4_JtsA,4110
blinker/base.py,sha256=ZfN6L36P0BzPaQAcAF0tSNAicxiG4f7xLPug6iLsjjE,20293
blinker/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
Wheel-Version: 1.0
Generator: flit 3.9.0
Root-Is-Purelib: true
Tag: py3-none-any
from blinker.base import ANY
from blinker.base import NamedSignal
from blinker.base import Namespace
from blinker.base import receiver_connected
from blinker.base import Signal
from blinker.base import signal
from blinker.base import WeakNamespace
__all__ = [
"ANY",
"NamedSignal",
"Namespace",
"Signal",
"WeakNamespace",
"receiver_connected",
"signal",
]
__version__ = "1.6.3"
# extracted from Louie, http://pylouie.org/
# updated for Python 3
#
# Copyright (c) 2006 Patrick K. O'Brien, Mike C. Fletcher,
# Matthew R. Scott
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
#
# * Neither the name of the <ORGANIZATION> nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
"""Refactored 'safe reference from dispatcher.py"""
import operator
import sys
import traceback
import weakref
get_self = operator.attrgetter("__self__")
get_func = operator.attrgetter("__func__")
def safe_ref(target, on_delete=None):
"""Return a *safe* weak reference to a callable target.
- ``target``: The object to be weakly referenced, if it's a bound
method reference, will create a BoundMethodWeakref, otherwise
creates a simple weakref.
- ``on_delete``: If provided, will have a hard reference stored to
the callable to be called after the safe reference goes out of
scope with the reference object, (either a weakref or a
BoundMethodWeakref) as argument.
"""
try:
im_self = get_self(target)
except AttributeError:
if callable(on_delete):
return weakref.ref(target, on_delete)
else:
return weakref.ref(target)
else:
if im_self is not None:
# Turn a bound method into a BoundMethodWeakref instance.
# Keep track of these instances for lookup by disconnect().
assert hasattr(target, "im_func") or hasattr(target, "__func__"), (
f"safe_ref target {target!r} has im_self, but no im_func, "
"don't know how to create reference"
)
reference = BoundMethodWeakref(target=target, on_delete=on_delete)
return reference
class BoundMethodWeakref:
"""'Safe' and reusable weak references to instance methods.
BoundMethodWeakref objects provide a mechanism for referencing a
bound method without requiring that the method object itself
(which is normally a transient object) is kept alive. Instead,
the BoundMethodWeakref object keeps weak references to both the
object and the function which together define the instance method.
Attributes:
- ``key``: The identity key for the reference, calculated by the
class's calculate_key method applied to the target instance method.
- ``deletion_methods``: Sequence of callable objects taking single
argument, a reference to this object which will be called when
*either* the target object or target function is garbage
collected (i.e. when this object becomes invalid). These are
specified as the on_delete parameters of safe_ref calls.
- ``weak_self``: Weak reference to the target object.
- ``weak_func``: Weak reference to the target function.
Class Attributes:
- ``_all_instances``: Class attribute pointing to all live
BoundMethodWeakref objects indexed by the class's
calculate_key(target) method applied to the target objects.
This weak value dictionary is used to short-circuit creation so
that multiple references to the same (object, function) pair
produce the same BoundMethodWeakref instance.
"""
_all_instances = weakref.WeakValueDictionary() # type: ignore[var-annotated]
def __new__(cls, target, on_delete=None, *arguments, **named):
"""Create new instance or return current instance.
Basically this method of construction allows us to
short-circuit creation of references to already-referenced
instance methods. The key corresponding to the target is
calculated, and if there is already an existing reference,
that is returned, with its deletion_methods attribute updated.
Otherwise the new instance is created and registered in the
table of already-referenced methods.
"""
key = cls.calculate_key(target)
current = cls._all_instances.get(key)
if current is not None:
current.deletion_methods.append(on_delete)
return current
else:
base = super().__new__(cls)
cls._all_instances[key] = base
base.__init__(target, on_delete, *arguments, **named)
return base
def __init__(self, target, on_delete=None):
"""Return a weak-reference-like instance for a bound method.
- ``target``: The instance-method target for the weak reference,
must have im_self and im_func attributes and be
reconstructable via the following, which is true of built-in
instance methods::
target.im_func.__get__( target.im_self )
- ``on_delete``: Optional callback which will be called when
this weak reference ceases to be valid (i.e. either the
object or the function is garbage collected). Should take a
single argument, which will be passed a pointer to this
object.
"""
def remove(weak, self=self):
"""Set self.isDead to True when method or instance is destroyed."""
methods = self.deletion_methods[:]
del self.deletion_methods[:]
try:
del self.__class__._all_instances[self.key]
except KeyError:
pass
for function in methods:
try:
if callable(function):
function(self)
except Exception:
try:
traceback.print_exc()
except AttributeError:
e = sys.exc_info()[1]
print(
f"Exception during saferef {self} "
f"cleanup function {function}: {e}"
)
self.deletion_methods = [on_delete]
self.key = self.calculate_key(target)
im_self = get_self(target)
im_func = get_func(target)
self.weak_self = weakref.ref(im_self, remove)
self.weak_func = weakref.ref(im_func, remove)
self.self_name = str(im_self)
self.func_name = str(im_func.__name__)
@classmethod
def calculate_key(cls, target):
"""Calculate the reference key for this reference.
Currently this is a two-tuple of the id()'s of the target
object and the target function respectively.
"""
return (id(get_self(target)), id(get_func(target)))
def __str__(self):
"""Give a friendly representation of the object."""
return "{}({}.{})".format(
self.__class__.__name__,
self.self_name,
self.func_name,
)
__repr__ = __str__
def __hash__(self):
return hash((self.self_name, self.key))
def __nonzero__(self):
"""Whether we are still a valid reference."""
return self() is not None
def __eq__(self, other):
"""Compare with another reference."""
if not isinstance(other, self.__class__):
return operator.eq(self.__class__, type(other))
return operator.eq(self.key, other.key)
def __call__(self):
"""Return a strong reference to the bound method.
If the target cannot be retrieved, then will return None,
otherwise returns a bound instance method for our object and
function.
Note: You may call this method any number of times, as it does
not invalidate the reference.
"""
target = self.weak_self()
if target is not None:
function = self.weak_func()
if function is not None:
return function.__get__(target)
return None
from __future__ import annotations
import asyncio
import inspect
import sys
import typing as t
from functools import partial
from weakref import ref
from blinker._saferef import BoundMethodWeakref
IdentityType = t.Union[t.Tuple[int, int], str, int]
class _symbol:
def __init__(self, name):
"""Construct a new named symbol."""
self.__name__ = self.name = name
def __reduce__(self):
return symbol, (self.name,)
def __repr__(self):
return self.name
_symbol.__name__ = "symbol"
class symbol:
"""A constant symbol.
>>> symbol('foo') is symbol('foo')
True
>>> symbol('foo')
foo
A slight refinement of the MAGICCOOKIE=object() pattern. The primary
advantage of symbol() is its repr(). They are also singletons.
Repeated calls of symbol('name') will all return the same instance.
"""
symbols = {} # type: ignore[var-annotated]
def __new__(cls, name):
try:
return cls.symbols[name]
except KeyError:
return cls.symbols.setdefault(name, _symbol(name))
def hashable_identity(obj: object) -> IdentityType:
if hasattr(obj, "__func__"):
return (id(obj.__func__), id(obj.__self__)) # type: ignore[attr-defined]
elif hasattr(obj, "im_func"):
return (id(obj.im_func), id(obj.im_self)) # type: ignore[attr-defined]
elif isinstance(obj, (int, str)):
return obj
else:
return id(obj)
WeakTypes = (ref, BoundMethodWeakref)
class annotatable_weakref(ref):
"""A weakref.ref that supports custom instance attributes."""
receiver_id: t.Optional[IdentityType]
sender_id: t.Optional[IdentityType]
def reference( # type: ignore[no-untyped-def]
object, callback=None, **annotations
) -> annotatable_weakref:
"""Return an annotated weak ref."""
if callable(object):
weak = callable_reference(object, callback)
else:
weak = annotatable_weakref(object, callback)
for key, value in annotations.items():
setattr(weak, key, value)
return weak # type: ignore[no-any-return]
def callable_reference(object, callback=None):
"""Return an annotated weak ref, supporting bound instance methods."""
if hasattr(object, "im_self") and object.im_self is not None:
return BoundMethodWeakref(target=object, on_delete=callback)
elif hasattr(object, "__self__") and object.__self__ is not None:
return BoundMethodWeakref(target=object, on_delete=callback)
return annotatable_weakref(object, callback)
class lazy_property:
"""A @property that is only evaluated once."""
def __init__(self, deferred):
self._deferred = deferred
self.__doc__ = deferred.__doc__
def __get__(self, obj, cls):
if obj is None:
return self
value = self._deferred(obj)
setattr(obj, self._deferred.__name__, value)
return value
def is_coroutine_function(func: t.Any) -> bool:
# Python < 3.8 does not correctly determine partially wrapped
# coroutine functions are coroutine functions, hence the need for
# this to exist. Code taken from CPython.
if sys.version_info >= (3, 8):
return asyncio.iscoroutinefunction(func)
else:
# Note that there is something special about the AsyncMock
# such that it isn't determined as a coroutine function
# without an explicit check.
try:
from unittest.mock import AsyncMock # type: ignore[attr-defined]
if isinstance(func, AsyncMock):
return True
except ImportError:
# Not testing, no asynctest to import
pass
while inspect.ismethod(func):
func = func.__func__
while isinstance(func, partial):
func = func.func
if not inspect.isfunction(func):
return False
if func.__code__.co_flags & inspect.CO_COROUTINE:
return True
acic = asyncio.coroutines._is_coroutine # type: ignore[attr-defined]
return getattr(func, "_is_coroutine", None) is acic
Copyright 2014 Pallets
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Metadata-Version: 2.1
Name: click
Version: 8.1.7
Summary: Composable command line interface toolkit
Home-page: https://palletsprojects.com/p/click/
Maintainer: Pallets
Maintainer-email: contact@palletsprojects.com
License: BSD-3-Clause
Project-URL: Donate, https://palletsprojects.com/donate
Project-URL: Documentation, https://click.palletsprojects.com/
Project-URL: Changes, https://click.palletsprojects.com/changes/
Project-URL: Source Code, https://github.com/pallets/click/
Project-URL: Issue Tracker, https://github.com/pallets/click/issues/
Project-URL: Chat, https://discord.gg/pallets
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Requires-Python: >=3.7
Description-Content-Type: text/x-rst
License-File: LICENSE.rst
Requires-Dist: colorama ; platform_system == "Windows"
Requires-Dist: importlib-metadata ; python_version < "3.8"
\$ click\_
==========
Click is a Python package for creating beautiful command line interfaces
in a composable way with as little code as necessary. It's the "Command
Line Interface Creation Kit". It's highly configurable but comes with
sensible defaults out of the box.
It aims to make the process of writing command line tools quick and fun
while also preventing any frustration caused by the inability to
implement an intended CLI API.
Click in three points:
- Arbitrary nesting of commands
- Automatic help page generation
- Supports lazy loading of subcommands at runtime
Installing
----------
Install and update using `pip`_:
.. code-block:: text
$ pip install -U click
.. _pip: https://pip.pypa.io/en/stable/getting-started/
A Simple Example
----------------
.. code-block:: python
import click
@click.command()
@click.option("--count", default=1, help="Number of greetings.")
@click.option("--name", prompt="Your name", help="The person to greet.")
def hello(count, name):
"""Simple program that greets NAME for a total of COUNT times."""
for _ in range(count):
click.echo(f"Hello, {name}!")
if __name__ == '__main__':
hello()
.. code-block:: text
$ python hello.py --count=3
Your name: Click
Hello, Click!
Hello, Click!
Hello, Click!
Donate
------
The Pallets organization develops and supports Click and other popular
packages. In order to grow the community of contributors and users, and
allow the maintainers to devote more time to the projects, `please
donate today`_.
.. _please donate today: https://palletsprojects.com/donate
Links
-----
- Documentation: https://click.palletsprojects.com/
- Changes: https://click.palletsprojects.com/changes/
- PyPI Releases: https://pypi.org/project/click/
- Source Code: https://github.com/pallets/click
- Issue Tracker: https://github.com/pallets/click/issues
- Chat: https://discord.gg/pallets
click-8.1.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
click-8.1.7.dist-info/LICENSE.rst,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475
click-8.1.7.dist-info/METADATA,sha256=qIMevCxGA9yEmJOM_4WHuUJCwWpsIEVbCPOhs45YPN4,3014
click-8.1.7.dist-info/RECORD,,
click-8.1.7.dist-info/WHEEL,sha256=5sUXSg9e4bi7lTLOHcm6QEYwO5TIF1TNbTSVFVjcJcc,92
click-8.1.7.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6
click/__init__.py,sha256=YDDbjm406dTOA0V8bTtdGnhN7zj5j-_dFRewZF_pLvw,3138
click/__pycache__/__init__.cpython-310.pyc,,
click/__pycache__/_compat.cpython-310.pyc,,
click/__pycache__/_termui_impl.cpython-310.pyc,,
click/__pycache__/_textwrap.cpython-310.pyc,,
click/__pycache__/_winconsole.cpython-310.pyc,,
click/__pycache__/core.cpython-310.pyc,,
click/__pycache__/decorators.cpython-310.pyc,,
click/__pycache__/exceptions.cpython-310.pyc,,
click/__pycache__/formatting.cpython-310.pyc,,
click/__pycache__/globals.cpython-310.pyc,,
click/__pycache__/parser.cpython-310.pyc,,
click/__pycache__/shell_completion.cpython-310.pyc,,
click/__pycache__/termui.cpython-310.pyc,,
click/__pycache__/testing.cpython-310.pyc,,
click/__pycache__/types.cpython-310.pyc,,
click/__pycache__/utils.cpython-310.pyc,,
click/_compat.py,sha256=5318agQpbt4kroKsbqDOYpTSWzL_YCZVUQiTT04yXmc,18744
click/_termui_impl.py,sha256=3dFYv4445Nw-rFvZOTBMBPYwB1bxnmNk9Du6Dm_oBSU,24069
click/_textwrap.py,sha256=10fQ64OcBUMuK7mFvh8363_uoOxPlRItZBmKzRJDgoY,1353
click/_winconsole.py,sha256=5ju3jQkcZD0W27WEMGqmEP4y_crUVzPCqsX_FYb7BO0,7860
click/core.py,sha256=j6oEWtGgGna8JarD6WxhXmNnxLnfRjwXglbBc-8jr7U,114086
click/decorators.py,sha256=-ZlbGYgV-oI8jr_oH4RpuL1PFS-5QmeuEAsLDAYgxtw,18719
click/exceptions.py,sha256=fyROO-47HWFDjt2qupo7A3J32VlpM-ovJnfowu92K3s,9273
click/formatting.py,sha256=Frf0-5W33-loyY_i9qrwXR8-STnW3m5gvyxLVUdyxyk,9706
click/globals.py,sha256=TP-qM88STzc7f127h35TD_v920FgfOD2EwzqA0oE8XU,1961
click/parser.py,sha256=LKyYQE9ZLj5KgIDXkrcTHQRXIggfoivX14_UVIn56YA,19067
click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
click/shell_completion.py,sha256=Ty3VM_ts0sQhj6u7eFTiLwHPoTgcXTGEAUg2OpLqYKw,18460
click/termui.py,sha256=H7Q8FpmPelhJ2ovOhfCRhjMtCpNyjFXryAMLZODqsdc,28324
click/testing.py,sha256=1Qd4kS5bucn1hsNIRryd0WtTMuCpkA93grkWxT8POsU,16084
click/types.py,sha256=TZvz3hKvBztf-Hpa2enOmP4eznSPLzijjig5b_0XMxE,36391
click/utils.py,sha256=1476UduUNY6UePGU4m18uzVHLt1sKM2PP3yWsQhbItM,20298
Wheel-Version: 1.0
Generator: bdist_wheel (0.41.1)
Root-Is-Purelib: true
Tag: py3-none-any
"""
Click is a simple Python module inspired by the stdlib optparse to make
writing command line scripts fun. Unlike other modules, it's based
around a simple API that does not come with too much magic and is
composable.
"""
from .core import Argument as Argument
from .core import BaseCommand as BaseCommand
from .core import Command as Command
from .core import CommandCollection as CommandCollection
from .core import Context as Context
from .core import Group as Group
from .core import MultiCommand as MultiCommand
from .core import Option as Option
from .core import Parameter as Parameter
from .decorators import argument as argument
from .decorators import command as command
from .decorators import confirmation_option as confirmation_option
from .decorators import group as group
from .decorators import help_option as help_option
from .decorators import make_pass_decorator as make_pass_decorator
from .decorators import option as option
from .decorators import pass_context as pass_context
from .decorators import pass_obj as pass_obj
from .decorators import password_option as password_option
from .decorators import version_option as version_option
from .exceptions import Abort as Abort
from .exceptions import BadArgumentUsage as BadArgumentUsage
from .exceptions import BadOptionUsage as BadOptionUsage
from .exceptions import BadParameter as BadParameter
from .exceptions import ClickException as ClickException
from .exceptions import FileError as FileError
from .exceptions import MissingParameter as MissingParameter
from .exceptions import NoSuchOption as NoSuchOption
from .exceptions import UsageError as UsageError
from .formatting import HelpFormatter as HelpFormatter
from .formatting import wrap_text as wrap_text
from .globals import get_current_context as get_current_context
from .parser import OptionParser as OptionParser
from .termui import clear as clear
from .termui import confirm as confirm
from .termui import echo_via_pager as echo_via_pager
from .termui import edit as edit
from .termui import getchar as getchar
from .termui import launch as launch
from .termui import pause as pause
from .termui import progressbar as progressbar
from .termui import prompt as prompt
from .termui import secho as secho
from .termui import style as style
from .termui import unstyle as unstyle
from .types import BOOL as BOOL
from .types import Choice as Choice
from .types import DateTime as DateTime
from .types import File as File
from .types import FLOAT as FLOAT
from .types import FloatRange as FloatRange
from .types import INT as INT
from .types import IntRange as IntRange
from .types import ParamType as ParamType
from .types import Path as Path
from .types import STRING as STRING
from .types import Tuple as Tuple
from .types import UNPROCESSED as UNPROCESSED
from .types import UUID as UUID
from .utils import echo as echo
from .utils import format_filename as format_filename
from .utils import get_app_dir as get_app_dir
from .utils import get_binary_stream as get_binary_stream
from .utils import get_text_stream as get_text_stream
from .utils import open_file as open_file
__version__ = "8.1.7"
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment