├── tools ├── schematics │ └── .gitkeep └── tsconfig.tools.json ├── .github └── FUNDING.yml ├── .prettierrc ├── packages ├── nx-python │ ├── src │ │ ├── schematics │ │ │ └── nx-python │ │ │ │ ├── files │ │ │ │ ├── flask │ │ │ │ │ ├── src │ │ │ │ │ │ ├── tests │ │ │ │ │ │ │ └── gabbi │ │ │ │ │ │ │ │ ├── index.yaml.template │ │ │ │ │ │ │ │ └── name.yaml.template │ │ │ │ │ │ └── name │ │ │ │ │ │ │ ├── api_doc.py.template │ │ │ │ │ │ │ ├── application.py.template │ │ │ │ │ │ │ ├── manage.py.template │ │ │ │ │ │ │ └── __init__.py.template │ │ │ │ │ ├── wadl │ │ │ │ │ │ ├── name-wadl.xml.template │ │ │ │ │ │ └── wadl.xsl.template │ │ │ │ │ ├── requirements.txt │ │ │ │ │ ├── Readme.md.template │ │ │ │ │ └── setup.py.template │ │ │ │ ├── default │ │ │ │ │ └── src │ │ │ │ │ │ ├── hello.py.template │ │ │ │ │ │ └── test_hello.py.template │ │ │ │ └── django │ │ │ │ │ ├── src │ │ │ │ │ ├── asgi.py.template │ │ │ │ │ ├── wsgi.py.template │ │ │ │ │ ├── urls.py.template │ │ │ │ │ └── settings.py.template │ │ │ │ │ └── manage.py.template │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schematic.spec.ts │ │ │ │ ├── target-options.ts │ │ │ │ ├── schema.json │ │ │ │ └── schematic.ts │ │ ├── index.ts │ │ ├── builders │ │ │ ├── lint │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ ├── builder.ts │ │ │ │ └── builder.spec.ts │ │ │ ├── test │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ ├── builder.ts │ │ │ │ └── builder.spec.ts │ │ │ ├── build │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ ├── builder.ts │ │ │ │ └── builder.spec.ts │ │ │ └── serve │ │ │ │ ├── schema.json │ │ │ │ ├── schema.d.ts │ │ │ │ ├── builder.ts │ │ │ │ └── builder.spec.ts │ │ ├── project-graph │ │ │ ├── has-python-files.ts │ │ │ └── index.ts │ │ └── utils │ │ │ ├── py-utils.ts │ │ │ └── command.ts │ ├── .eslintrc │ ├── README.md │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ ├── jest.config.js │ ├── collection.json │ ├── package.json │ ├── builders.json │ └── READM.md └── python-graph │ ├── .eslintrc │ ├── README.md │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ ├── jest.config.js │ ├── src │ ├── has-python-files.ts │ └── index.ts │ └── package.json ├── .prettierignore ├── nx-python-nx-python-1.0.2.tgz ├── e2e └── nx-python-e2e │ ├── tsconfig.spec.json │ ├── tsconfig.json │ ├── jest.config.js │ └── tests │ └── nx-python.test.ts ├── .editorconfig ├── jest.config.js ├── tsconfig.base.json ├── .gitignore ├── PULL_REQUEST_TEMPLATE.md ├── nx.json ├── LICENSE ├── ISSUE_TEMPLATE.md ├── .eslintrc ├── package.json ├── migrations.json ├── CODE_OF_CONDUCT.md ├── workspace.json └── README.md /tools/schematics/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: alphacentauri82 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/flask/src/tests/gabbi/index.yaml.template: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/flask/src/tests/gabbi/name.yaml.template: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/nx-python/src/index.ts: -------------------------------------------------------------------------------- 1 | export type CommandType = 'build' | 'lint' | 'serve' | 'test'; 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | 3 | /dist 4 | /coverage 5 | -------------------------------------------------------------------------------- /packages/nx-python/.eslintrc: -------------------------------------------------------------------------------- 1 | { "extends": "../../.eslintrc", "rules": {}, "ignorePatterns": ["!**/*"] } 2 | -------------------------------------------------------------------------------- /packages/python-graph/.eslintrc: -------------------------------------------------------------------------------- 1 | { "extends": "../../.eslintrc", "rules": {}, "ignorePatterns": ["!**/*"] } 2 | -------------------------------------------------------------------------------- /nx-python-nx-python-1.0.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hogarthww-labs/nx-python/HEAD/nx-python-nx-python-1.0.2.tgz -------------------------------------------------------------------------------- /packages/nx-python/src/builders/lint/schema.d.ts: -------------------------------------------------------------------------------- 1 | import { JsonObject } from '@angular-devkit/core' 2 | 3 | export interface LintBuilderSchema extends JsonObject { 4 | outputPath?: string 5 | main?: string 6 | } -------------------------------------------------------------------------------- /packages/nx-python/src/builders/test/schema.d.ts: -------------------------------------------------------------------------------- 1 | import { JsonObject } from '@angular-devkit/core' 2 | 3 | export interface TestBuilderSchema extends JsonObject { 4 | outputPath?: string 5 | main?: string 6 | } -------------------------------------------------------------------------------- /packages/nx-python/README.md: -------------------------------------------------------------------------------- 1 | # nx-python 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `ng test nx-python` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /packages/nx-python/src/builders/build/schema.d.ts: -------------------------------------------------------------------------------- 1 | import { JsonObject } from '@angular-devkit/core'; 2 | 3 | export interface BuildBuilderSchema extends JsonObject { 4 | outputPath?: string 5 | main?: string 6 | } 7 | -------------------------------------------------------------------------------- /packages/python-graph/README.md: -------------------------------------------------------------------------------- 1 | # nx-python 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `ng test nx-python-project-graph` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /e2e/nx-python-e2e/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/flask/src/name/api_doc.py.template: -------------------------------------------------------------------------------- 1 | """Index Doc module for the `<%= snakeName %>` service.""" 2 | # -*- coding: utf-8 -*- 3 | 4 | INDEX_DOC = """
5 | /api/<%= snakeName %>/v1/ 6 |
7 | """ # noqa: ignore=E501 8 | -------------------------------------------------------------------------------- /e2e/nx-python-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.e2e.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/nx-python/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/python-graph/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc/tools", 5 | "rootDir": ".", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": ["node"] 9 | }, 10 | "include": ["**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /e2e/nx-python-e2e/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'nx-python-e2e', 3 | preset: '../../jest.config.js', 4 | globals: { 5 | 'ts-jest': { 6 | tsConfig: '/tsconfig.spec.json', 7 | }, 8 | }, 9 | coverageDirectory: '../../coverage/e2e/nx-python-e2e', 10 | }; 11 | -------------------------------------------------------------------------------- /packages/nx-python/src/builders/build/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft-07/schema", 3 | "$id": "https://json-schema.org/draft-07/schema", 4 | "title": "Build builder", 5 | "description": "", 6 | "type": "object", 7 | "properties": {}, 8 | "required": [] 9 | } 10 | -------------------------------------------------------------------------------- /packages/nx-python/src/builders/lint/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft-07/schema", 3 | "$id": "https://json-schema.org/draft-07/schema", 4 | "title": "Build builder", 5 | "description": "", 6 | "type": "object", 7 | "properties": {}, 8 | "required": [] 9 | } -------------------------------------------------------------------------------- /packages/nx-python/src/builders/test/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft-07/schema", 3 | "$id": "https://json-schema.org/draft-07/schema", 4 | "title": "Build builder", 5 | "description": "", 6 | "type": "object", 7 | "properties": {}, 8 | "required": [] 9 | } -------------------------------------------------------------------------------- /packages/nx-python/src/builders/serve/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft-07/schema", 3 | "$id": "https://json-schema.org/draft-07/schema", 4 | "title": "Build builder", 5 | "description": "", 6 | "type": "object", 7 | "properties": {}, 8 | "required": [] 9 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'], 3 | testTimeout: 60000, 4 | transform: { 5 | '^.+\\.(ts|js|html)$': 'ts-jest', 6 | }, 7 | resolver: '@nrwl/jest/plugins/resolver', 8 | moduleFileExtensions: ['ts', 'js', 'html'], 9 | coverageReporters: ['html'], 10 | }; 11 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/schema.d.ts: -------------------------------------------------------------------------------- 1 | export type NxPythonTemplate = 'default' | 'django' | 'flask'; 2 | export interface NxPythonSchematicSchema { 3 | name: string; 4 | tags?: string; 5 | description?: string; 6 | repoUrl?: string; 7 | directory?: string; 8 | template?: NxPythonTemplate; 9 | } 10 | -------------------------------------------------------------------------------- /packages/nx-python/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../dist/out-tsc", 6 | "declaration": true, 7 | "rootDir": ".", 8 | "types": ["node"] 9 | }, 10 | "exclude": ["**/*.spec.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/python-graph/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../dist/out-tsc", 6 | "declaration": true, 7 | "rootDir": ".", 8 | "types": ["node"] 9 | }, 10 | "exclude": ["**/*.spec.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/flask/src/name/application.py.template: -------------------------------------------------------------------------------- 1 | """Main module for the `<%= snakeName %>` service.""" 2 | import logging 3 | # TODO 4 | 5 | from <%= snakeName %> import api, app 6 | 7 | log = logging.getLogger("<%= snakeName %>") 8 | 9 | # TODO 10 | 11 | if __name__ == "__main__": 12 | app.run() 13 | -------------------------------------------------------------------------------- /packages/nx-python/src/builders/serve/schema.d.ts: -------------------------------------------------------------------------------- 1 | import { JsonObject } from '@angular-devkit/core' 2 | import { NxPythonTemplate } from '../../schematics/nx-python/schema'; 3 | 4 | export interface ServeBuilderSchema extends JsonObject { 5 | main?: string 6 | outputPath?: string 7 | cwd?: string 8 | cmd?: string 9 | templateType?: NxPythonTemplate 10 | } -------------------------------------------------------------------------------- /packages/nx-python/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.spec.ts", 10 | "**/*.spec.tsx", 11 | "**/*.spec.js", 12 | "**/*.spec.jsx", 13 | "**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/python-graph/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.spec.ts", 10 | "**/*.spec.tsx", 11 | "**/*.spec.js", 12 | "**/*.spec.jsx", 13 | "**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/default/src/hello.py.template: -------------------------------------------------------------------------------- 1 | class HelloFactory: 2 | def __init__(self, **args): 3 | for key, value in args.items(): 4 | setattr(self, key, 'Hello {}'.format(value)) 5 | 6 | 7 | if __name__ == '__main__': 8 | hello = HelloFactory(application="<%= projectName %>", user="Human") 9 | print(hello.application) 10 | -------------------------------------------------------------------------------- /packages/nx-python/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'nx-python', 3 | preset: '../../jest.config.js', 4 | globals: { 5 | 'ts-jest': { 6 | tsConfig: '/tsconfig.spec.json', 7 | }, 8 | }, 9 | transform: { 10 | '^.+\\.[tj]sx?$': 'ts-jest', 11 | }, 12 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], 13 | coverageDirectory: '../../coverage/packages/nx-python', 14 | }; 15 | -------------------------------------------------------------------------------- /packages/python-graph/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'nx-python-project-graph', 3 | preset: '../../jest.config.js', 4 | globals: { 5 | 'ts-jest': { 6 | tsConfig: '/tsconfig.spec.json', 7 | }, 8 | }, 9 | transform: { 10 | '^.+\\.[tj]sx?$': 'ts-jest', 11 | }, 12 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], 13 | coverageDirectory: '../../coverage/packages/nx-python-project-graph', 14 | }; 15 | -------------------------------------------------------------------------------- /packages/nx-python/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/@angular-devkit/schematics/collection-schema.json", 3 | "name": "nx-python", 4 | "version": "0.0.1", 5 | "schematics": { 6 | "nx-python": { 7 | "aliases": ["app"], 8 | "factory": "./src/schematics/nx-python/schematic", 9 | "schema": "./src/schematics/nx-python/schema.json", 10 | "description": "Creates a new Python Application" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/default/src/test_hello.py.template: -------------------------------------------------------------------------------- 1 | from hello import HelloFactory 2 | import unittest 3 | 4 | 5 | class HelloTest(unittest.TestCase): 6 | def test_message(self): 7 | try: 8 | hello = HelloFactory(user="Human") 9 | self.assertEqual(hello.user, 'Hello Human') 10 | except Exception as e: 11 | print('Error: {}'.format(str(e))) 12 | self.assertTrue(False) 13 | 14 | 15 | if __name__ == '__main__': 16 | unittest.main() 17 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/django/src/asgi.py.template: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for <%= projectName %> project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'src.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/django/src/wsgi.py.template: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for <%= projectName %> project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', '<%= projectName %>.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/flask/wadl/name-wadl.xml.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | ="API_URL" xmlns="http://wadl.dev.java.net/2009/02"> 7 | 8 | 9 | <%= projectDescription %> 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/flask/requirements.txt: -------------------------------------------------------------------------------- 1 | aniso8601==2.0.0 2 | certifi==2017.11.5 3 | chardet==3.0.4 4 | click==6.7 5 | cryptography==3.0 6 | dnspython==1.16.0 7 | furl==2.1.0 8 | Flask==1.0.2 9 | Flask-RESTful==0.3.6 10 | Flask-Script==2.0.6 11 | gevent==1.2.2 12 | greenlet==0.4.12 13 | gunicorn==19.7.1 14 | idna==2.6 15 | itsdangerous==0.24 16 | Jinja2==2.10 17 | MarkupSafe==1.1.1 18 | mock==3.0.5 19 | python-dateutil 20 | PyJWT==1.7.1 21 | pytz==2017.3 22 | requests==2.18.4 23 | six==1.11.0 24 | urllib3==1.22 25 | voluptuous==0.11.5 26 | Werkzeug==0.14.1 27 | xmltodict==0.11.0 28 | 29 | -------------------------------------------------------------------------------- /packages/python-graph/src/has-python-files.ts: -------------------------------------------------------------------------------- 1 | import recursive from 'recursive-readdir'; 2 | import * as path from 'path'; 3 | 4 | function notPythonFile(file, stats) { 5 | // `file` is the path to the file, and `stats` is an `fs.Stats` 6 | // object returned from `fs.lstat()`. 7 | return stats.isDirectory() || path.extname(file) !== '.py'; 8 | } 9 | 10 | export const hasPythonFiles = (folder: string): Promise => 11 | new Promise((resolve, reject) => { 12 | recursive(folder, [notPythonFile], (err, files) => { 13 | if (err) reject(err.message); 14 | resolve(files); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/nx-python/src/project-graph/has-python-files.ts: -------------------------------------------------------------------------------- 1 | import recursive from 'recursive-readdir'; 2 | import * as path from 'path'; 3 | 4 | function notPythonFile(file, stats) { 5 | // `file` is the path to the file, and `stats` is an `fs.Stats` 6 | // object returned from `fs.lstat()`. 7 | return stats.isDirectory() || path.extname(file) !== '.py'; 8 | } 9 | 10 | export const hasPythonFiles = (folder: string): Promise => 11 | new Promise((resolve, reject) => { 12 | recursive(folder, [notPythonFile], (err, files) => { 13 | if (err) reject(err.message); 14 | resolve(files); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "importHelpers": true, 11 | "target": "es2015", 12 | "module": "esnext", 13 | "typeRoots": ["node_modules/@types"], 14 | "lib": ["es2017", "dom"], 15 | "skipLibCheck": true, 16 | "skipDefaultLibCheck": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "nx-python/nx-python": ["packages/nx-python/src/index.ts"] 20 | } 21 | }, 22 | "exclude": ["node_modules", "tmp"] 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | #github 4 | .github 5 | 6 | # compiled output 7 | /dist 8 | /tmp 9 | /out-tsc 10 | 11 | # dependencies 12 | /node_modules 13 | 14 | # IDEs and editors 15 | /.idea 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # IDE - VSCode 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | 30 | # misc 31 | /.sass-cache 32 | /connect.lock 33 | /coverage 34 | /libpeerconnection.log 35 | npm-debug.log 36 | yarn-error.log 37 | testem.log 38 | /typings 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /packages/python-graph/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nx-python/nx-python-project-graph", 3 | "version": "1.0.1", 4 | "main": "src/index.js", 5 | "license": "MIT", 6 | "description": "This library was generated with [Nx](https://nx.dev).", 7 | "scripts": { 8 | "test": "nx test" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/codeonrocks/nx-python.git" 13 | }, 14 | "keywords": [ 15 | "nx", 16 | "python" 17 | ], 18 | "author": "Code On LLC", 19 | "bugs": { 20 | "url": "https://github.com/codeonrocks/nx-python/issues" 21 | }, 22 | "homepage": "https://github.com/codeonrocks/nx-python#readme", 23 | "devDependencies": { 24 | "nxpm": "^1.15.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | * **Please check if the PR fulfills these requirements** 2 | - [ ] The commit message is clear and concise 3 | - [ ] Tests for the changes have been added (for bug fixes / features) 4 | - [ ] Docs/Readme have been added / updated (for bug fixes / features) 5 | 6 | 7 | * **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...) 8 | 9 | 10 | 11 | * **What is the current behavior?** (You can also link to an open issue here) 12 | 13 | 14 | 15 | * **What is the new behavior (if this is a feature change)?** 16 | 17 | 18 | 19 | * **Does this PR introduce a breaking change?** (What changes might users need to make in their application due to this PR?) 20 | 21 | 22 | 23 | * **Other information**: 24 | -------------------------------------------------------------------------------- /packages/nx-python/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nx-python/nx-python", 3 | "version": "1.0.1", 4 | "main": "src/index.js", 5 | "schematics": "./collection.json", 6 | "builders": "./builders.json", 7 | "license": "MIT", 8 | "description": "This library was generated with [Nx](https://nx.dev).", 9 | "scripts": { 10 | "test": "nx test" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/codeonrocks/nx-python.git" 15 | }, 16 | "keywords": [ 17 | "nx", 18 | "python" 19 | ], 20 | "author": "Code On LLC", 21 | "bugs": { 22 | "url": "https://github.com/codeonrocks/nx-python/issues" 23 | }, 24 | "homepage": "https://github.com/codeonrocks/nx-python#readme", 25 | "devDependencies": { 26 | "nxpm": "^1.15.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/django/manage.py.template: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'src.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmScope": "nx-python", 3 | "affected": { 4 | "defaultBase": "master" 5 | }, 6 | "implicitDependencies": { 7 | "workspace.json": "*", 8 | "package.json": { 9 | "dependencies": "*", 10 | "devDependencies": "*" 11 | }, 12 | "tsconfig.base.json": "*", 13 | "tslint.json": "*", 14 | "nx.json": "*" 15 | }, 16 | "tasksRunnerOptions": { 17 | "default": { 18 | "runner": "@nrwl/workspace/tasks-runners/default", 19 | "options": { 20 | "cacheableOperations": ["build", "lint", "test", "e2e"] 21 | } 22 | } 23 | }, 24 | "projects": { 25 | "nx-python": { 26 | "tags": [] 27 | }, 28 | "nx-python-e2e": { 29 | "tags": [], 30 | "implicitDependencies": ["nx-python"] 31 | } 32 | }, 33 | "workspaceLayout": { 34 | "appsDir": "e2e", 35 | "libsDir": "packages" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/nx-python/builders.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/@angular-devkit/architect/src/builders-schema.json", 3 | "builders": { 4 | "build": { 5 | "implementation": "./src/builders/build/builder", 6 | "schema": "./src/builders/build/schema.json", 7 | "description": "build builder" 8 | }, 9 | "lint": { 10 | "implementation": "./src/builders/lint/builder", 11 | "schema": "./src/builders/lint/schema.json", 12 | "description": "lint builder" 13 | }, 14 | "serve": { 15 | "implementation": "./src/builders/serve/builder", 16 | "schema": "./src/builders/serve/schema.json", 17 | "description": "serve builder" 18 | }, 19 | "test": { 20 | "implementation": "./src/builders/test/builder", 21 | "schema": "./src/builders/test/schema.json", 22 | "description": "test builder" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/django/src/urls.py.template: -------------------------------------------------------------------------------- 1 | """<%= projectName %> URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.1/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path 18 | 19 | urlpatterns = [ 20 | path('admin/', admin.site.urls), 21 | ] 22 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/schematic.spec.ts: -------------------------------------------------------------------------------- 1 | import { Tree } from '@angular-devkit/schematics'; 2 | import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; 3 | import { createEmptyWorkspace } from '@nrwl/workspace/testing'; 4 | import { join } from 'path'; 5 | 6 | import { NxPythonSchematicSchema } from './schema'; 7 | 8 | describe('nx-python schematic', () => { 9 | let appTree: Tree; 10 | const options: NxPythonSchematicSchema = { name: 'test' }; 11 | 12 | const testRunner = new SchematicTestRunner( 13 | '@nx-python/nx-python', 14 | join(__dirname, '../../../collection.json') 15 | ); 16 | 17 | beforeEach(() => { 18 | appTree = createEmptyWorkspace(Tree.empty()); 19 | }); 20 | 21 | it('should run successfully', async () => { 22 | await expect( 23 | testRunner.runSchematicAsync('nx-python', options, appTree).toPromise() 24 | ).resolves.not.toThrowError(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/nx-python/src/builders/serve/builder.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BuilderContext, 3 | BuilderOutput, 4 | createBuilder, 5 | } from '@angular-devkit/architect'; 6 | 7 | import { from, Observable } from 'rxjs'; 8 | import { map } from 'rxjs/operators'; 9 | 10 | import { getCliOptions, runPythonCommand } from '../../utils/py-utils'; 11 | 12 | import { ServeBuilderSchema } from './schema'; 13 | 14 | export function runBuilder( 15 | options: ServeBuilderSchema, 16 | context: BuilderContext 17 | ): Observable { 18 | const projMetadata = context.getProjectMetadata(context?.target?.project); 19 | return from(projMetadata).pipe( 20 | map((project) => { 21 | const mainFile = `${options.main}`; 22 | 23 | return runPythonCommand( 24 | context, 25 | 'serve', 26 | [mainFile], 27 | getCliOptions(options), 28 | project 29 | ); 30 | }) 31 | ); 32 | } 33 | 34 | export default createBuilder(runBuilder); 35 | -------------------------------------------------------------------------------- /packages/nx-python/src/builders/test/builder.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BuilderContext, 3 | BuilderOutput, 4 | createBuilder, 5 | } from '@angular-devkit/architect'; 6 | 7 | import { from, Observable } from 'rxjs'; 8 | import { map } from 'rxjs/operators'; 9 | 10 | import { getCliOptions, runPythonCommand } from '../../utils/py-utils'; 11 | 12 | import { TestBuilderSchema } from './schema'; 13 | 14 | export function runBuilder( 15 | options: TestBuilderSchema, 16 | context: BuilderContext 17 | ): Observable { 18 | const projMetadata = context.getProjectMetadata(context?.target?.project); 19 | return from(projMetadata).pipe( 20 | map((project) => { 21 | const root = project.root; 22 | const sources = `${root}/src/*test*.py`; 23 | 24 | return runPythonCommand( 25 | context, 26 | 'test', 27 | [sources], 28 | getCliOptions(options), 29 | project 30 | ); 31 | }) 32 | ); 33 | } 34 | 35 | export default createBuilder(runBuilder); 36 | -------------------------------------------------------------------------------- /packages/nx-python/src/builders/build/builder.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BuilderContext, 3 | BuilderOutput, 4 | createBuilder, 5 | } from '@angular-devkit/architect'; 6 | 7 | import { Observable, from } from 'rxjs'; 8 | import { map } from 'rxjs/operators'; 9 | 10 | import { getCliOptions, runPythonCommand } from '../../utils/py-utils'; 11 | 12 | import { BuildBuilderSchema } from './schema'; 13 | 14 | export function runBuilder( 15 | options: BuildBuilderSchema, 16 | context: BuilderContext 17 | ): Observable { 18 | const projMetadata = context.getProjectMetadata(context?.target?.project); 19 | return from(projMetadata).pipe( 20 | map((project) => { 21 | const mainFile = `${options.main}`; 22 | const output = `${options.outputPath}`; 23 | //Compile files using the native py_compile module 24 | return runPythonCommand( 25 | context, 26 | 'build', 27 | [mainFile], 28 | getCliOptions(options), 29 | project 30 | ); 31 | }) 32 | ); 33 | } 34 | 35 | export default createBuilder(runBuilder); 36 | -------------------------------------------------------------------------------- /packages/nx-python/src/builders/lint/builder.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BuilderContext, 3 | BuilderOutput, 4 | createBuilder, 5 | } from '@angular-devkit/architect'; 6 | 7 | import { from, Observable } from 'rxjs'; 8 | import { map } from 'rxjs/operators'; 9 | 10 | import { getCliOptions, runPythonCommand } from '../../utils/py-utils'; 11 | 12 | import { LintBuilderSchema } from './schema'; 13 | 14 | export function runBuilder( 15 | options: LintBuilderSchema, 16 | context: BuilderContext 17 | ): Observable { 18 | const projMetadata = context.getProjectMetadata(context?.target?.project); 19 | return from(projMetadata).pipe( 20 | map((project) => { 21 | const root = project.root; 22 | // Route of python files 23 | const sources = `${root}/src/*.py`; 24 | 25 | // Executing linting using the flake8 module 26 | return runPythonCommand( 27 | context, 28 | 'lint', 29 | [sources], 30 | getCliOptions(options), 31 | project 32 | ); 33 | }) 34 | ); 35 | } 36 | 37 | export default createBuilder(runBuilder); 38 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/flask/src/name/manage.py.template: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | manage.py is a thin wrapper that takes care of several things. 5 | It provides runserver and more. 6 | Please run `manage.py help` to see all options. 7 | """ 8 | 9 | from flask_script import Manager, Server, Shell 10 | 11 | from <%= snakeName %>.application import app 12 | from <%= snakeName %> import settings 13 | 14 | manager = Manager(app) 15 | 16 | 17 | def make_shell_context(): 18 | """Make a flask-script shell context containing app.""" 19 | return dict(app=app) 20 | 21 | 22 | manager.add_command('shell', Shell(make_context=make_shell_context)) 23 | manager.add_command( 24 | 'runserver', Server(host='0.0.0.0', port=7000, use_debugger=True) 25 | ) 26 | 27 | 28 | def main(): 29 | """Run development server.""" 30 | if settings.TEST_MODE is True: 31 | from <%= snakeName %>.gabbi_utils import enable_test_mode 32 | enable_test_mode() 33 | manager.run(default_command='runserver') 34 | 35 | 36 | if __name__ == '__main__': 37 | main() 38 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/flask/Readme.md.template: -------------------------------------------------------------------------------- 1 | # <%= projectName %> 2 | 3 | <%= projectDescription %> 4 | 5 | ## Endpoints 6 | 7 | TODO 8 | 9 | ## Setup locally 10 | 11 | ### Create virtualenv and install dependencies 12 | 13 | ```bash 14 | virtualenv venv 15 | source venv/bin/activate 16 | # pip install ... 17 | pip install -r requirements.txt 18 | ``` 19 | 20 | ### Setup env variable 21 | 22 | ```bash 23 | # TODO 24 | ``` 25 | 26 | ### Run server 27 | 28 | Go to project root and run: 29 | 30 | ```bash 31 | export PYTHONPATH=`pwd`/src 32 | python src/manage.py 33 | ``` 34 | 35 | It should start at `localhost:7000` 36 | 37 | ### API tests mode 38 | 39 | It assumes you have done previous steps. 40 | To run api test mode, it is required to set `mode` parameter to `gabbi` 41 | in test config (take a look at example_config.ini). 42 | 43 | #### Run tests 44 | 45 | 1. Run server 46 | 2. Activate virtualenv `source venv/bin/activate` 47 | 3. Install gabbi package `pip install gabbi` 48 | 4. Run tests using unittest 49 | 50 | ```bash 51 | gabbi-run localhost:7000 -- src/tests/gabbi/* 52 | ``` 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Code ON LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/flask/setup.py.template: -------------------------------------------------------------------------------- 1 | """Package configuration for `<%= snakeName %>`.""" 2 | import os 3 | 4 | import setuptools 5 | 6 | here = os.path.abspath(os.path.dirname(__file__)) 7 | 8 | setuptools.setup( 9 | name="<%= snakeName %>", 10 | version=open(os.path.join(here, 'VERSION')).read().strip(), 11 | url="<%= repoUrl %>", 12 | description='<%= description %>', 13 | long_description=open(os.path.join(here, 'README.md')).read(), 14 | classifiers=[ 15 | 'Programming Language :: Python', 16 | 'Programming Language :: Python :: 3', 17 | 'Programming Language :: Python :: 3.6', 18 | ], 19 | packages=setuptools.find_packages('src', exclude=('tests',)), 20 | package_dir={'': 'src'}, 21 | include_package_data=True, 22 | zip_safe=False, 23 | 24 | install_requires=[ 25 | 'Flask', 26 | 'flask-restful', 27 | 'Flask-script', 28 | 'gevent', 29 | 'Werkzeug>=0.14', 30 | "pillow>=2.3.0,<3.0.0", 31 | ], 32 | extras_require={ 33 | 'production': [ 34 | 'gunicorn', 35 | ], 36 | } 37 | ) 38 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | * **I'm submitting a ...** 3 | - [ ] bug report 4 | - [ ] feature request 5 | - [ ] support request 6 | 7 | * **Do you want to request a *feature* or report a *bug*?** 8 | 9 | 10 | 11 | * **What is the current behavior?** 12 | 13 | 14 | 15 | * **If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem** via 16 | https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5). 17 | 18 | 19 | 20 | * **What is the expected behavior?** 21 | 22 | 23 | 24 | * **What is the motivation / use case for changing the behavior?** 25 | 26 | 27 | 28 | * **Please tell us about your environment:** 29 | 30 | - Version: 31 | - Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ] 32 | - Language: [all | TypeScript X.X | ES6/7 | ES5 | Dart] 33 | 34 | 35 | * **Other information** (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow, gitter, etc) 36 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 2018, 6 | "sourceType": "module", 7 | "project": "./tsconfig.base.json" 8 | }, 9 | "ignorePatterns": ["**/*"], 10 | "plugins": ["@typescript-eslint", "@nrwl/nx"], 11 | "extends": [ 12 | "eslint:recommended", 13 | "plugin:@typescript-eslint/eslint-recommended", 14 | "plugin:@typescript-eslint/recommended", 15 | "prettier", 16 | "prettier/@typescript-eslint" 17 | ], 18 | "rules": { 19 | "@typescript-eslint/explicit-member-accessibility": "off", 20 | "@typescript-eslint/explicit-function-return-type": "off", 21 | "@typescript-eslint/no-parameter-properties": "off", 22 | "@nrwl/nx/enforce-module-boundaries": [ 23 | "error", 24 | { 25 | "enforceBuildableLibDependency": true, 26 | "allow": [], 27 | "depConstraints": [ 28 | { "sourceTag": "*", "onlyDependOnLibsWithTags": ["*"] } 29 | ] 30 | } 31 | ] 32 | }, 33 | "overrides": [ 34 | { 35 | "files": ["*.tsx"], 36 | "rules": { 37 | "@typescript-eslint/no-unused-vars": "off" 38 | } 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /packages/nx-python/src/project-graph/index.ts: -------------------------------------------------------------------------------- 1 | import { hasPythonFiles } from './has-python-files'; 2 | // import { BuilderContext } from '@angular-devkit/architect'; 3 | import { 4 | ProjectGraphBuilder, 5 | ProjectGraph, 6 | ProjectGraphProcessorContext, 7 | } from '@nrwl/devkit'; 8 | 9 | /** 10 | * Nx Project Graph plugin for go 11 | * 12 | * @param {import('@nrwl/devkit').ProjectGraph} graph 13 | * @param {import('@nrwl/devkit').ProjectGraphProcessorContext} context 14 | * @returns {import('@nrwl/devkit').ProjectGraph} 15 | */ 16 | export const processProjectGraph = ( 17 | graph: ProjectGraph, 18 | context: ProjectGraphProcessorContext 19 | ): ProjectGraph => { 20 | const builder = new ProjectGraphBuilder(graph); 21 | 22 | const projectNames = Object.keys(context.filesToProcess); 23 | 24 | const hasPythonCompiler = (project) => { 25 | const projectBuildOptions = project.targets['build'].options; 26 | return projectBuildOptions.compiler !== 'python'; 27 | }; 28 | 29 | const isPythonProject = (project) => 30 | hasPythonCompiler(project) || hasPythonFiles(project.root); 31 | 32 | projectNames.map((projName) => { 33 | const project = context.workspace.projects[projName]; 34 | if (!isPythonProject(project)) return; 35 | builder.addNode({ 36 | name: projName, 37 | type: 'python', 38 | data: { 39 | files: projectNames[projName], 40 | }, 41 | }); 42 | }); 43 | return builder.getUpdatedProjectGraph(); 44 | }; 45 | -------------------------------------------------------------------------------- /packages/nx-python/src/utils/py-utils.ts: -------------------------------------------------------------------------------- 1 | import { JsonObject } from '@angular-devkit/core'; 2 | import { BuilderContext } from '@angular-devkit/architect'; 3 | 4 | import { execSync } from 'child_process'; 5 | 6 | import { ServeBuilderSchema } from '../builders/serve/schema'; 7 | 8 | import { CommandType } from '..'; 9 | import { getExecuteCommand } from './command'; 10 | 11 | export function runPythonCommand( 12 | context: BuilderContext, 13 | command: CommandType, 14 | params: string[], 15 | options: ServeBuilderSchema = {}, 16 | projectMetadata: JsonObject 17 | ): { success: boolean } { 18 | // Take the parameters or set defaults 19 | const pythonRuntime = projectMetadata.python || 'python3'; 20 | const cmd = options.cmd || pythonRuntime; 21 | const cwd = options.cwd || process.cwd(); 22 | 23 | const execute = getExecuteCommand( 24 | cmd as string, 25 | command, 26 | params, 27 | projectMetadata 28 | ); 29 | try { 30 | context.logger.info(`Executing command: ${execute}`); 31 | execSync(execute, { cwd, stdio: [0, 1, 2] }); 32 | return { success: true }; 33 | } catch (e) { 34 | context.logger.error(`Failed to execute command: ${execute}`, e); 35 | return { success: false }; 36 | } 37 | } 38 | 39 | export function getCliOptions(options: ServeBuilderSchema): ServeBuilderSchema { 40 | const _options: ServeBuilderSchema = { ...options }; 41 | if (options.cmd) { 42 | _options.cmd = options.cmd; 43 | } 44 | if (options.cwd) { 45 | _options.cwd = options.cwd; 46 | } 47 | return _options; 48 | } 49 | -------------------------------------------------------------------------------- /packages/nx-python/src/builders/lint/builder.spec.ts: -------------------------------------------------------------------------------- 1 | import { Architect } from '@angular-devkit/architect' 2 | import { TestingArchitectHost } from '@angular-devkit/architect/testing' 3 | import { schema } from '@angular-devkit/core' 4 | import { join } from 'path' 5 | import { LintBuilderSchema } from './schema' 6 | 7 | const options: LintBuilderSchema = {} 8 | 9 | describe('Command Runner Builder', () => { 10 | let architect: Architect 11 | let architectHost: TestingArchitectHost 12 | 13 | beforeEach(async () => { 14 | const registry = new schema.CoreSchemaRegistry() 15 | registry.addPostTransform(schema.transforms.addUndefinedDefaults) 16 | 17 | architectHost = new TestingArchitectHost('/root', '/root') 18 | architect = new Architect(architectHost, registry) 19 | 20 | // This will either take a Node package name, or a path to the directory 21 | // for the package.json file. 22 | await architectHost.addBuilderFromPackage(join(__dirname, '../../..')) 23 | }) 24 | 25 | it('can run', async () => { 26 | // A "run" can have multiple outputs, and contains progress information. 27 | const run = await architect.scheduleBuilder('@nx-python/nx-python:lint', options) 28 | // The "result" member (of type BuilderOutput) is the next output. 29 | const output = await run.result 30 | 31 | // Stop the builder from running. This stops Architect from keeping 32 | // the builder-associated states in memory, since builders keep waiting 33 | // to be scheduled. 34 | await run.stop() 35 | 36 | // Expect that it succeeded. 37 | expect(output.success).toBe(true) 38 | }) 39 | }) -------------------------------------------------------------------------------- /packages/nx-python/src/builders/test/builder.spec.ts: -------------------------------------------------------------------------------- 1 | import { Architect } from '@angular-devkit/architect' 2 | import { TestingArchitectHost } from '@angular-devkit/architect/testing' 3 | import { schema } from '@angular-devkit/core' 4 | import { join } from 'path' 5 | import { TestBuilderSchema } from './schema' 6 | 7 | const options: TestBuilderSchema = {} 8 | 9 | describe('Command Runner Builder', () => { 10 | let architect: Architect 11 | let architectHost: TestingArchitectHost 12 | 13 | beforeEach(async () => { 14 | const registry = new schema.CoreSchemaRegistry() 15 | registry.addPostTransform(schema.transforms.addUndefinedDefaults) 16 | 17 | architectHost = new TestingArchitectHost('/root', '/root') 18 | architect = new Architect(architectHost, registry) 19 | 20 | // This will either take a Node package name, or a path to the directory 21 | // for the package.json file. 22 | await architectHost.addBuilderFromPackage(join(__dirname, '../../..')) 23 | }) 24 | 25 | it('can run', async () => { 26 | // A "run" can have multiple outputs, and contains progress information. 27 | const run = await architect.scheduleBuilder('@nx-python/nx-python:test', options) 28 | // The "result" member (of type BuilderOutput) is the next output. 29 | const output = await run.result 30 | 31 | // Stop the builder from running. This stops Architect from keeping 32 | // the builder-associated states in memory, since builders keep waiting 33 | // to be scheduled. 34 | await run.stop() 35 | 36 | // Expect that it succeeded. 37 | expect(output.success).toBe(true) 38 | }) 39 | }) -------------------------------------------------------------------------------- /packages/nx-python/src/builders/serve/builder.spec.ts: -------------------------------------------------------------------------------- 1 | import { Architect } from '@angular-devkit/architect' 2 | import { TestingArchitectHost } from '@angular-devkit/architect/testing' 3 | import { schema } from '@angular-devkit/core' 4 | import { join } from 'path' 5 | import { ServeBuilderSchema } from './schema' 6 | 7 | const options: ServeBuilderSchema = {} 8 | 9 | describe('Command Runner Builder', () => { 10 | let architect: Architect 11 | let architectHost: TestingArchitectHost 12 | 13 | beforeEach(async () => { 14 | const registry = new schema.CoreSchemaRegistry() 15 | registry.addPostTransform(schema.transforms.addUndefinedDefaults) 16 | 17 | architectHost = new TestingArchitectHost('/root', '/root') 18 | architect = new Architect(architectHost, registry) 19 | 20 | // This will either take a Node package name, or a path to the directory 21 | // for the package.json file. 22 | await architectHost.addBuilderFromPackage(join(__dirname, '../../..')) 23 | }) 24 | 25 | it('can run', async () => { 26 | // A "run" can have multiple outputs, and contains progress information. 27 | const run = await architect.scheduleBuilder('@nx-python/nx-python:serve', options) 28 | // The "result" member (of type BuilderOutput) is the next output. 29 | 30 | const output = await run.result 31 | 32 | // Stop the builder from running. This stops Architect from keeping 33 | // the builder-associated states in memory, since builders keep waiting 34 | // to be scheduled. 35 | await run.stop() 36 | 37 | // Expect that it succeeded. 38 | expect(output.success).toBe(true) 39 | }) 40 | }) -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/target-options.ts: -------------------------------------------------------------------------------- 1 | // TODO: remove `any` types later on 2 | 3 | import { join, normalize } from 'path'; 4 | 5 | import { NxPythonTemplate } from './schema'; 6 | 7 | interface IProject { 8 | root?: string; 9 | sourceRoot?: string; 10 | } 11 | 12 | export function getServeOptions( 13 | templateType: NxPythonTemplate, 14 | project: IProject 15 | ): any { 16 | return { 17 | main: getMainFilePath(templateType, project), 18 | templateType, 19 | }; 20 | } 21 | 22 | export function getBuildOptions( 23 | templateType: NxPythonTemplate, 24 | project: IProject, 25 | options: any 26 | ): any { 27 | return { 28 | outputPath: join(normalize('dist'), options.projectRoot), 29 | main: getMainFilePath(templateType, project), 30 | templateType, 31 | }; 32 | } 33 | 34 | export function getTestOptions( 35 | templateType: NxPythonTemplate, 36 | project: IProject 37 | ): any { 38 | return { 39 | main: getTestMainFilePath(templateType, project), 40 | templateType, 41 | }; 42 | } 43 | 44 | export function getLintOptions( 45 | templateType: NxPythonTemplate, 46 | project: IProject 47 | ): any { 48 | return { 49 | main: getMainFilePath(templateType, project), 50 | templateType, 51 | }; 52 | } 53 | 54 | function getTestMainFilePath(template: NxPythonTemplate, project): string { 55 | return join(project.sourceRoot, 'test_hello.py'); 56 | } 57 | 58 | function getMainFilePath(template: NxPythonTemplate, project): string { 59 | if (template === 'django' || template === 'flask') { 60 | return join(project.root, 'manage.py'); 61 | } 62 | return join(project.sourceRoot, 'hello.py'); 63 | } 64 | -------------------------------------------------------------------------------- /packages/nx-python/src/builders/build/builder.spec.ts: -------------------------------------------------------------------------------- 1 | import { Architect } from '@angular-devkit/architect'; 2 | import { TestingArchitectHost } from '@angular-devkit/architect/testing'; 3 | import { schema } from '@angular-devkit/core'; 4 | import { join } from 'path'; 5 | import { BuildBuilderSchema } from './schema'; 6 | 7 | const options: BuildBuilderSchema = {} 8 | 9 | describe('Command Runner Builder', () => { 10 | let architect: Architect; 11 | let architectHost: TestingArchitectHost; 12 | 13 | beforeEach(async () => { 14 | const registry = new schema.CoreSchemaRegistry(); 15 | registry.addPostTransform(schema.transforms.addUndefinedDefaults); 16 | 17 | architectHost = new TestingArchitectHost('/root', '/root'); 18 | architect = new Architect(architectHost, registry); 19 | 20 | // This will either take a Node package name, or a path to the directory 21 | // for the package.json file. 22 | await architectHost.addBuilderFromPackage(join(__dirname, '../../..')); 23 | }); 24 | 25 | it('can run', async () => { 26 | // A "run" can have multiple outputs, and contains progress information. 27 | const run = await architect.scheduleBuilder( 28 | '@nx-python/nx-python:build', 29 | options 30 | ); 31 | // The "result" member (of type BuilderOutput) is the next output. 32 | const output = await run.result; 33 | 34 | // Stop the builder from running. This stops Architect from keeping 35 | // the builder-associated states in memory, since builders keep waiting 36 | // to be scheduled. 37 | await run.stop(); 38 | 39 | // Expect that it succeeded. 40 | expect(output.success).toBe(true); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/nx-python/src/utils/command.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import { JsonObject } from '@angular-devkit/core'; 3 | 4 | import { cosmiconfigSync } from 'cosmiconfig'; 5 | 6 | import { CommandType } from '..'; 7 | 8 | const testers = { 9 | pytest: '-m pytest', 10 | unittest: '-m unittest discover -s ./ -p', 11 | }; 12 | 13 | const linters = { 14 | pylint: '-m pylint', 15 | flake8: '-m flake8', 16 | mypy: '-m mypy', 17 | }; 18 | 19 | const builders = { 20 | default: '-m py_compile', 21 | numba: '-m numba', 22 | cython: 'build_ext --inplace', 23 | }; 24 | 25 | const defaults: any = { 26 | python: { 27 | serve: ' ', 28 | build: builders.default, 29 | lint: linters.flake8, 30 | test: testers.unittest, 31 | }, 32 | }; 33 | 34 | defaults.django = { 35 | ...defaults.python, 36 | serve: 'runserver', 37 | }; 38 | 39 | defaults.flask = { 40 | ...defaults.python, 41 | pyServe: 'flask run', 42 | }; 43 | 44 | export function getExecuteCommand( 45 | cmd: string, 46 | command: CommandType, 47 | params: string[], 48 | projectMetadata: JsonObject 49 | ): string { 50 | let mutate_command = ''; 51 | const explorerSync = cosmiconfigSync('nx-python'); 52 | const { config } = explorerSync.search('commands'); 53 | const projCommands = (projectMetadata.commands as any) || {}; 54 | const commandsObj = { 55 | ...config, 56 | ...projCommands, 57 | }; 58 | const projectType: string = (projectMetadata.projectType as any) || 'python'; 59 | const pyOpts = { 60 | ...defaults[projectType], 61 | ...commandsObj, 62 | }; 63 | 64 | // Create the command to execute 65 | mutate_command = pyOpts[command] || command; 66 | return `${cmd} ${mutate_command} ${params.join(' ')}`; 67 | } 68 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema", 3 | "id": "NxPython", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | "name": { 8 | "type": "string", 9 | "description": "", 10 | "$default": { 11 | "$source": "argv", 12 | "index": 0 13 | }, 14 | "x-prompt": "What name would you like to use?" 15 | }, 16 | "tags": { 17 | "type": "string", 18 | "description": "Add tags to the project (used for linting)", 19 | "alias": "t" 20 | }, 21 | "description": { 22 | "type": "string", 23 | "description": "Project description", 24 | "alias": "d" 25 | }, 26 | "repoUrl": { 27 | "type": "string", 28 | "description": "Repository url", 29 | "alias": "r" 30 | }, 31 | "directory": { 32 | "type": "string", 33 | "description": "A directory where the project is placed", 34 | "alias": "d" 35 | }, 36 | "template": { 37 | "type": "string", 38 | "alias": "f", 39 | "default": "default", 40 | "x-prompt": { 41 | "message": "Which python framework would you like to use for the application?", 42 | "type": "list", 43 | "items": [ 44 | { 45 | "value": "default", 46 | "label": "(default) [ https://www.python.org/ ]" 47 | }, 48 | { 49 | "value": "django", 50 | "label": "django [ https://www.djangoproject.com/ ]" 51 | }, 52 | { 53 | "value": "flask", 54 | "label": "Flask [ https://pypi.org/project/Flask/ ]" 55 | } 56 | ] 57 | } 58 | } 59 | }, 60 | "required": [ 61 | "name" 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /packages/python-graph/src/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import { 3 | ProjectGraphBuilder, 4 | ProjectGraph, 5 | ProjectGraphProcessorContext, 6 | } from '@nrwl/devkit'; 7 | 8 | import * as path from 'path'; 9 | 10 | import { hasPythonFiles } from './has-python-files'; 11 | 12 | /** 13 | * Nx Project Graph plugin for go 14 | * 15 | * @param {import('@nrwl/devkit').ProjectGraph} graph 16 | * @param {import('@nrwl/devkit').ProjectGraphProcessorContext} context 17 | * @returns {import('@nrwl/devkit').ProjectGraph} 18 | */ 19 | export const processProjectGraph = ( 20 | graph: ProjectGraph, 21 | context: ProjectGraphProcessorContext 22 | ): ProjectGraph => { 23 | const builder = new ProjectGraphBuilder(graph); 24 | 25 | const projectNames = Object.keys(context.filesToProcess); 26 | 27 | const hasPythonCompiler = (project) => { 28 | const projectBuildOptions = project.targets['build'].options; 29 | return projectBuildOptions.compiler !== 'python'; 30 | }; 31 | 32 | const isPythonProject = (project) => 33 | hasPythonCompiler(project) || hasPythonFiles(project.root); 34 | 35 | const pythonFileExtensions = [ 36 | '.py', 37 | '.pyw', 38 | '.pyi', 39 | '.json', 40 | '.toml', 41 | '.xml', 42 | '.yaml', 43 | '.yml', 44 | ]; 45 | const isPythonFile = (file) => 46 | pythonFileExtensions.includes(path.extname(file)); 47 | 48 | const filterPythonFiles = (files: string[]) => files.filter(isPythonFile); 49 | 50 | projectNames.map((projName) => { 51 | const project = context.workspace.projects[projName]; 52 | if (!isPythonProject(project)) return; 53 | const projFiles = projectNames[projName]; 54 | const pythonFiles = filterPythonFiles(projFiles); 55 | builder.addNode({ 56 | name: projName, 57 | type: 'python', 58 | data: { 59 | files: pythonFiles, 60 | }, 61 | }); 62 | }); 63 | return builder.getUpdatedProjectGraph(); 64 | }; 65 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/flask/wadl/wadl.xsl.template: -------------------------------------------------------------------------------- 1 | 2 | 31 | 38 | 39 | -------------------------------------------------------------------------------- /e2e/nx-python-e2e/tests/nx-python.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | checkFilesExist, 3 | ensureNxProject, 4 | readJson, 5 | runNxCommandAsync, 6 | uniq, 7 | } from '@nrwl/nx-plugin/testing'; 8 | describe('nx-python e2e', () => { 9 | it('should create nx-python', async (done) => { 10 | const plugin = uniq('nx-python'); 11 | ensureNxProject('@nx-python/nx-python', 'dist/packages/nx-python'); 12 | await runNxCommandAsync(`generate @nx-python/nx-python:app ${plugin}`); 13 | 14 | const resultBuild = await runNxCommandAsync(`build ${plugin}`) 15 | expect(resultBuild.stdout).toContain(`Executing command: python3 -m py_compile`) 16 | 17 | const resultLint = await runNxCommandAsync(`lint ${plugin}`) 18 | expect(resultLint.stdout).toContain(`Executing command: python3 -m flake8 apps/${plugin}/src/*.py`) 19 | 20 | const resultServe = await runNxCommandAsync(`serve ${plugin}`) 21 | expect(resultServe.stdout).toContain(`Executing command: python3`) 22 | 23 | const resultTest = await runNxCommandAsync(`test ${plugin}`) 24 | expect(resultTest.stdout).toContain(`Executing command: python3 -m unittest discover -s ./ -p apps/${plugin}/src/*test*.py`) 25 | 26 | done(); 27 | }); 28 | 29 | describe('--directory', () => { 30 | it('should create src in the specified directory', async (done) => { 31 | const plugin = uniq('nx-python'); 32 | ensureNxProject('@nx-python/nx-python', 'dist/packages/nx-python'); 33 | await runNxCommandAsync( 34 | `generate @nx-python/nx-python:app ${plugin} --directory subdir` 35 | ); 36 | expect(() => 37 | checkFilesExist(`apps/subdir/${plugin}/src/hello.py`) 38 | ).not.toThrow(); 39 | done(); 40 | }); 41 | }); 42 | 43 | describe('--tags', () => { 44 | it('should add tags to nx.json', async (done) => { 45 | const plugin = uniq('nx-python'); 46 | ensureNxProject('@nx-python/nx-python', 'dist/packages/nx-python'); 47 | await runNxCommandAsync( 48 | `generate @nx-python/nx-python:app ${plugin} --tags e2etag,e2ePackage` 49 | ); 50 | const nxJson = readJson('nx.json'); 51 | expect(nxJson.projects[plugin].tags).toEqual(['e2etag', 'e2ePackage']); 52 | done(); 53 | }); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nx-python/nx-python", 3 | "version": "1.0.2", 4 | "license": "MIT", 5 | "scripts": { 6 | "nx": "nx", 7 | "start": "nx serve", 8 | "build": "nx build", 9 | "test": "nx test", 10 | "lint": "nx workspace-lint && nx lint", 11 | "e2e": "nx e2e", 12 | "affected:apps": "nx affected:apps", 13 | "affected:libs": "nx affected:libs", 14 | "affected:build": "nx affected:build", 15 | "affected:e2e": "nx affected:e2e", 16 | "affected:test": "nx affected:test", 17 | "affected:lint": "nx affected:lint", 18 | "affected:dep-graph": "nx affected:dep-graph", 19 | "affected": "nx affected", 20 | "format": "nx format:write", 21 | "format:write": "nx format:write", 22 | "format:check": "nx format:check", 23 | "update": "nx migrate latest", 24 | "workspace-schematic": "nx workspace-schematic", 25 | "dep-graph": "nx dep-graph", 26 | "help": "nx help" 27 | }, 28 | "private": false, 29 | "dependencies": { 30 | "@nrwl/devkit": "^12.9.0", 31 | "change-case": "^4.1.2", 32 | "cosmiconfig": "^7.0.1", 33 | "global": "^4.4.0", 34 | "recursive-readdir": "^2.2.2" 35 | }, 36 | "devDependencies": { 37 | "@nrwl/eslint-plugin-nx": "10.4.4", 38 | "@nrwl/jest": "10.4.4", 39 | "@nrwl/nx-plugin": "10.4.4", 40 | "@nrwl/workspace": "10.4.4", 41 | "@types/jest": "26.0.8", 42 | "@types/node": "~8.9.4", 43 | "@typescript-eslint/eslint-plugin": "4.3.0", 44 | "@typescript-eslint/parser": "4.3.0", 45 | "dotenv": "6.2.0", 46 | "eslint": "6.8.0", 47 | "eslint-config-prettier": "6.0.0", 48 | "jest": "26.2.2", 49 | "nxpm": "^1.15.0", 50 | "prettier": "2.1.2", 51 | "ts-jest": "26.4.0", 52 | "ts-node": "~7.0.0", 53 | "tslint": "~6.0.0", 54 | "typescript": "4.0.5" 55 | }, 56 | "description": "This project was generated using [Nx](https://nx.dev).", 57 | "main": "nx.json", 58 | "repository": { 59 | "type": "git", 60 | "url": "git+https://github.com/codeonrocks/nx-python.git" 61 | }, 62 | "keywords": [ 63 | "nx", 64 | "python" 65 | ], 66 | "author": "Code ON LLC", 67 | "bugs": { 68 | "url": "https://github.com/codeonrocks/nx-python/issues" 69 | }, 70 | "homepage": "https://github.com/codeonrocks/nx-python#readme" 71 | } 72 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/flask/src/name/__init__.py.template: -------------------------------------------------------------------------------- 1 | """Module for the `<%= snakeName %>` service.""" 2 | # -*- coding: utf-8 -*- 3 | 4 | import logging.config 5 | import syslog 6 | import traceback 7 | 8 | from flask import Flask 9 | from flask_restful import Api 10 | from werkzeug.exceptions import NotFound, Unauthorized 11 | from werkzeug.routing import RequestRedirect 12 | 13 | from <%= snakeName %> import settings 14 | 15 | 16 | ########################### 17 | # Setup and configuration # 18 | ########################### 19 | app = Flask(__name__) 20 | app.config['ERROR_404_HELP'] = False 21 | app.config['PROPAGATE_EXCEPTIONS'] = True 22 | api = Api(app) 23 | 24 | 25 | logging.config.dictConfig({ 26 | 'version': 1, 27 | 'formatters': { 28 | 'default': { 29 | 'format': ( 30 | '[%(levelname)s] %(asctime)s - %(name)s - lineno: %(lineno)d - %(message)s' # noqa: E501 31 | ), 32 | 'datefmt': '%d/%b/%Y:%H:%M:%S %z', 33 | } 34 | }, 35 | 'handlers': { 36 | 'syslog': { 37 | 'class': 'logging.handlers.SysLogHandler', 38 | 'formatter': 'default', 39 | 'address': 40 | '/var/run/syslog' if getattr(settings, 'DEV_MODE', False) 41 | else '/dev/log', 42 | 'facility': syslog.LOG_LOCAL1, 43 | } 44 | }, 45 | 'loggers': { 46 | '<%= snakeName %>': { 47 | 'handlers': ['syslog'], 48 | }, 49 | } 50 | }) 51 | 52 | 53 | @app.errorhandler(Exception) 54 | def unhandled_server_error(e): 55 | """Unhandled error handler.""" 56 | if isinstance(e, (NotFound, RequestRedirect, Unauthorized)): 57 | return e 58 | err_trace = traceback.format_tb(e.__traceback__) 59 | syslog.syslog( 60 | syslog.LOG_ERR, 61 | "## [<%= snakeName %>] UNHANDLED ERROR TRACEBACK: START ##") 62 | syslog.syslog( 63 | syslog.LOG_ERR, 64 | "Error type: {err_type}, cause: {err_msg}".format( 65 | err_type=str(type(e)), err_msg=str(e)) 66 | ) 67 | syslog.syslog(syslog.LOG_ERR, "-- Traceback:") 68 | for line in err_trace: 69 | syslog.syslog(syslog.LOG_ERR, line) 70 | syslog.syslog( 71 | syslog.LOG_ERR, 72 | "## [<%= snakeName %>] UNHANDLED ERROR TRACEBACK: END ##") 73 | return "<%= snakeName %> Internal Server Error", 500 74 | -------------------------------------------------------------------------------- /migrations.json: -------------------------------------------------------------------------------- 1 | { 2 | "migrations": [ 3 | { 4 | "version": "10.1.0-beta.0", 5 | "description": "Migrate .eslintrc files to use tsconfig with a wildcard", 6 | "factory": "./src/migrations/update-10-1-0/migrate-eslintrc-tsconfig-wildcard", 7 | "package": "@nrwl/workspace", 8 | "name": "migrate-eslintrc-tsconfig-wildcard" 9 | }, 10 | { 11 | "version": "10.3.0-beta.0", 12 | "description": "Add @nrwl/cli as dependency", 13 | "factory": "./src/migrations/update-10-3-0/add-cli-dependency", 14 | "package": "@nrwl/workspace", 15 | "name": "add-cli-dependency" 16 | }, 17 | { 18 | "version": "10.3.0-beta.0", 19 | "description": "Update typescript to v4", 20 | "factory": "./src/migrations/update-10-3-0/update-typescript", 21 | "package": "@nrwl/workspace", 22 | "name": "update-10-3-0" 23 | }, 24 | { 25 | "version": "10.3.0-beta.1", 26 | "description": "Adds .vscode/extensions.json to a workspace", 27 | "factory": "./src/migrations/update-10-3-0/add-vscode-extensions", 28 | "package": "@nrwl/workspace", 29 | "name": "add-vscode-extensions" 30 | }, 31 | { 32 | "version": "10.3.0-beta.0", 33 | "description": "Adds `buildableProjectDepsInPackageJsonType` for web and angular package builders", 34 | "factory": "./src/migrations/update-10-3-0/add-buildable-project-deps-in-package-json-type", 35 | "package": "@nrwl/workspace", 36 | "name": "add-buildable-project-deps-in-package-json-type" 37 | }, 38 | { 39 | "version": "10.4.0-beta.5", 40 | "description": "Add an explicit dependency on @nrwl/tao", 41 | "factory": "./src/migrations/update-10-4-0/add-explicit-dep-on-tao", 42 | "package": "@nrwl/workspace", 43 | "name": "add-explicit-dep-on-tao" 44 | }, 45 | { 46 | "version": "10.1.0-beta.4", 47 | "description": "Update jest to v26", 48 | "factory": "./src/migrations/update-10-1-0/update-10-1-0", 49 | "package": "@nrwl/jest", 50 | "name": "update-10.1.0" 51 | }, 52 | { 53 | "version": "10.2.0", 54 | "description": "Remove deprecated jest builder options", 55 | "factory": "./src/migrations/update-10-2-0/update-10-2-0", 56 | "package": "@nrwl/jest", 57 | "name": "update-10.2.0" 58 | }, 59 | { 60 | "version": "10.3.0-beta.1", 61 | "description": "Adds all jest projects into the root jest config", 62 | "factory": "./src/migrations/update-10-3-0/update-projects-property", 63 | "package": "@nrwl/jest", 64 | "name": "update-projects-property" 65 | }, 66 | { 67 | "version": "10.3.1-beta.1", 68 | "description": "Fix ts-jest migration", 69 | "factory": "./src/migrations/update-10-3-0/update-ts-jest", 70 | "package": "@nrwl/jest", 71 | "name": "update-ts-jest" 72 | }, 73 | { 74 | "version": "10.3.0-beta.1", 75 | "description": "Adds a jest extension to the recommended extensions for vscode", 76 | "factory": "./src/migrations/update-10-3-0/add-jest-extension", 77 | "package": "@nrwl/jest", 78 | "name": "add-jest-extension" 79 | } 80 | ] 81 | } -------------------------------------------------------------------------------- /packages/nx-python/READM.md: -------------------------------------------------------------------------------- 1 | # 🐍 NxPy: Nx Python plugin 2 | 3 | This project was generated using [Nx](https://nx.dev). 4 | 5 |

6 | 7 | 8 |

9 | 10 | The `nx-python` plugin allows users to create a basic python application using `nx` commands. To add the plugin to your project, just follow these steps: 11 | 12 | ## Getting started 13 | 14 | ### Create a Nx Workspace 15 | 16 | Before installing the `nx-python` plugin, it is required to have a pre-configured Nx Workspace . If you don't, then proceed to create a new one executing the following command: 17 | 18 | ``` 19 | npx create-nx-workspace python-workspace --preset=empty --cli=nx --nx-cloud true 20 | cd python-workspace 21 | ``` 22 | 23 | ### Install the `nx-python` plugin 24 | 25 | ``` 26 | yarn add -D @nx-python/nx-python 27 | ``` 28 | 29 | ### Adding an application to our workspace 30 | 31 | To create a new python application based on this plugin, please execute the following command: 32 | 33 | ``` 34 | nx g @nx-python/nx-python:app 35 | ``` 36 | 37 | **Note:** Replace `` with the name of your new application 38 | 39 | ## Usage 40 | 41 | After creating the `` application using the `nx-python` plugin. We can execute the build, lint, test and serve `nx commands` on this new application. Output will be stored on `dist//` directory. 42 | 43 | ### Building the app 44 | 45 | The `build` command is going to compile all the python files inside `` directory, using the `py_compile` native module. 46 | 47 | ``` 48 | nx build 49 | ``` 50 | 51 | More information here: [py_compile](https://docs.python.org/3/library/py_compile.html) 52 | 53 | ### Linting the application 54 | 55 | Unfortunately Python doesn't have a native linting module(yet!). `nx-python` uses the `Flake8` module to lint your application. It is required that you install this module beforehand. More info here: [Flake8](https://flake8.pycqa.org/en/latest/) 56 | 57 | ``` 58 | pip install Flake8 59 | ``` 60 | 61 | After that you can perform the lint process with: 62 | 63 | ``` 64 | nx lint 65 | ``` 66 | 67 | ### Serving the application 68 | 69 | This is going to execute the main file in your python application. 70 | 71 | ``` 72 | nx serve 73 | ``` 74 | 75 | ### Testing your application 76 | 77 | The `test` command is going to execute all the test units inside your python app. You can add new test unit files if you want, but there are two requirements that you must meet: 78 | 79 | - The filename must include the prefix `test` 80 | - Because we are using the native `unittest` python module to make our tests, you are going to create the tests based on this approach. More info here: [unittest](https://docs.python.org/3/library/unittest.html) 81 | 82 | To test your python app, execute the command: 83 | 84 | ``` 85 | nx test 86 | ``` 87 | ## Contributing 88 | 89 | 🐍 All contributions are welcome. Make sure you follow the [code of conduct](CODE_OF_CONDUCT.md) in this repository. 90 | 91 | ## MIT License 92 | 93 | Made with 💜 by [Code ON](https://codeon.rocks) | [Melvin Vega](https://github.com/melveg) & [Diana Rodriguez](https://github.com/sponsors/alphacentauri82) 94 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at support@nexmo.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/files/django/src/settings.py.template: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for <%= projectName %> project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.1.3. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.1/ref/settings/ 11 | """ 12 | 13 | from pathlib import Path 14 | 15 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 16 | BASE_DIR = Path(__file__).resolve().parent.parent 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = 'xqel9-rtlgqhv$4aj((s=ql)j5vkbibxd2h71ju9bnx2&q^fz5' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | ] 41 | 42 | MIDDLEWARE = [ 43 | 'django.middleware.security.SecurityMiddleware', 44 | 'django.contrib.sessions.middleware.SessionMiddleware', 45 | 'django.middleware.common.CommonMiddleware', 46 | 'django.middleware.csrf.CsrfViewMiddleware', 47 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 48 | 'django.contrib.messages.middleware.MessageMiddleware', 49 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 50 | ] 51 | 52 | ROOT_URLCONF = 'src.urls' 53 | 54 | TEMPLATES = [ 55 | { 56 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 57 | 'DIRS': [], 58 | 'APP_DIRS': True, 59 | 'OPTIONS': { 60 | 'context_processors': [ 61 | 'django.template.context_processors.debug', 62 | 'django.template.context_processors.request', 63 | 'django.contrib.auth.context_processors.auth', 64 | 'django.contrib.messages.context_processors.messages', 65 | ], 66 | }, 67 | }, 68 | ] 69 | 70 | WSGI_APPLICATION = 'src.wsgi.application' 71 | 72 | 73 | # Database 74 | # https://docs.djangoproject.com/en/3.1/ref/settings/#databases 75 | 76 | DATABASES = { 77 | 'default': { 78 | 'ENGINE': 'django.db.backends.sqlite3', 79 | 'NAME': BASE_DIR / 'db.sqlite3', 80 | } 81 | } 82 | 83 | 84 | # Password validation 85 | # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators 86 | 87 | AUTH_PASSWORD_VALIDATORS = [ 88 | { 89 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 90 | }, 91 | { 92 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 93 | }, 94 | { 95 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 96 | }, 97 | { 98 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 99 | }, 100 | ] 101 | 102 | 103 | # Internationalization 104 | # https://docs.djangoproject.com/en/3.1/topics/i18n/ 105 | 106 | LANGUAGE_CODE = 'en-us' 107 | 108 | TIME_ZONE = 'UTC' 109 | 110 | USE_I18N = True 111 | 112 | USE_L10N = True 113 | 114 | USE_TZ = True 115 | 116 | 117 | # Static files (CSS, JavaScript, Images) 118 | # https://docs.djangoproject.com/en/3.1/howto/static-files/ 119 | 120 | STATIC_URL = '/static/' 121 | -------------------------------------------------------------------------------- /workspace.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "projects": { 4 | "nx-python": { 5 | "root": "packages/nx-python", 6 | "sourceRoot": "packages/nx-python/src", 7 | "projectType": "library", 8 | "schematics": {}, 9 | "architect": { 10 | "lint": { 11 | "builder": "@nrwl/linter:lint", 12 | "options": { 13 | "linter": "eslint", 14 | "tsConfig": [ 15 | "packages/nx-python/tsconfig.lib.json", 16 | "packages/nx-python/tsconfig.spec.json" 17 | ], 18 | "exclude": ["**/node_modules/**", "!packages/nx-python/**/*"] 19 | } 20 | }, 21 | "test": { 22 | "builder": "@nrwl/jest:jest", 23 | "options": { 24 | "jestConfig": "packages/nx-python/jest.config.js", 25 | "tsConfig": "packages/nx-python/tsconfig.spec.json", 26 | "passWithNoTests": true 27 | } 28 | }, 29 | "build": { 30 | "builder": "@nrwl/node:package", 31 | "options": { 32 | "outputPath": "dist/packages/nx-python", 33 | "tsConfig": "packages/nx-python/tsconfig.lib.json", 34 | "packageJson": "packages/nx-python/package.json", 35 | "main": "packages/nx-python/src/index.ts", 36 | "assets": [ 37 | "packages/nx-python/*.md", 38 | { 39 | "input": "./packages/nx-python/src", 40 | "glob": "**/*.!(ts)", 41 | "output": "./src" 42 | }, 43 | { 44 | "input": "./packages/nx-python", 45 | "glob": "collection.json", 46 | "output": "." 47 | }, 48 | { 49 | "input": "./packages/nx-python", 50 | "glob": "builders.json", 51 | "output": "." 52 | } 53 | ] 54 | } 55 | } 56 | } 57 | }, 58 | "nx-python-e2e": { 59 | "projectType": "application", 60 | "root": "e2e/nx-python-e2e", 61 | "sourceRoot": "e2e/nx-python-e2e/src", 62 | "architect": { 63 | "e2e": { 64 | "builder": "@nrwl/nx-plugin:e2e", 65 | "options": { 66 | "target": "nx-python:build", 67 | "npmPackageName": "@nx-python/nx-python", 68 | "pluginOutputPath": "dist/packages/nx-python", 69 | "jestConfig": "e2e/nx-python-e2e/jest.config.js", 70 | "tsSpecConfig": "e2e/nx-python-e2e/tsconfig.spec.json" 71 | } 72 | } 73 | } 74 | } 75 | }, 76 | "cli": { 77 | "defaultCollection": "@nrwl/workspace" 78 | }, 79 | "schematics": { 80 | "@nrwl/workspace": { 81 | "library": { 82 | "linter": "eslint" 83 | } 84 | }, 85 | "@nrwl/cypress": { 86 | "cypress-project": { 87 | "linter": "eslint" 88 | } 89 | }, 90 | "@nrwl/react": { 91 | "application": { 92 | "linter": "eslint" 93 | }, 94 | "library": { 95 | "linter": "eslint" 96 | }, 97 | "storybook-configuration": { 98 | "linter": "eslint" 99 | } 100 | }, 101 | "@nrwl/next": { 102 | "application": { 103 | "linter": "eslint" 104 | } 105 | }, 106 | "@nrwl/web": { 107 | "application": { 108 | "linter": "eslint" 109 | } 110 | }, 111 | "@nrwl/node": { 112 | "application": { 113 | "linter": "eslint" 114 | }, 115 | "library": { 116 | "linter": "eslint" 117 | } 118 | }, 119 | "@nrwl/nx-plugin": { 120 | "plugin": { 121 | "linter": "eslint" 122 | } 123 | }, 124 | "@nrwl/nest": { 125 | "application": { 126 | "linter": "eslint" 127 | } 128 | }, 129 | "@nrwl/express": { 130 | "application": { 131 | "linter": "eslint" 132 | }, 133 | "library": { 134 | "linter": "eslint" 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /packages/nx-python/src/schematics/nx-python/schematic.ts: -------------------------------------------------------------------------------- 1 | import { 2 | apply, 3 | applyTemplates, 4 | chain, 5 | mergeWith, 6 | move, 7 | Rule, 8 | url, 9 | } from '@angular-devkit/schematics'; 10 | 11 | import { 12 | addProjectToNxJsonInTree, 13 | names, 14 | offsetFromRoot, 15 | projectRootDir, 16 | ProjectType, 17 | toFileName, 18 | updateWorkspace, 19 | } from '@nrwl/workspace'; 20 | 21 | import { snakeCase } from 'change-case'; 22 | 23 | import { NxPythonSchematicSchema, NxPythonTemplate } from './schema'; 24 | import { 25 | getBuildOptions, 26 | getLintOptions, 27 | getServeOptions, 28 | getTestOptions, 29 | } from './target-options'; 30 | 31 | /** 32 | * Depending on your needs, you can change this to either `Library` or `Application` 33 | */ 34 | //const projectType = ProjectType.Library; 35 | const projectType = ProjectType.Application; 36 | 37 | interface NormalizedSchema extends NxPythonSchematicSchema { 38 | projectName: string; 39 | snakeName: string; 40 | repoUrl: string; 41 | projectRoot: string; 42 | projectDirectory: string; 43 | projectDescription: string; 44 | parsedTags: string[]; 45 | } 46 | 47 | function normalizeOptions(options: NxPythonSchematicSchema): NormalizedSchema { 48 | const name = toFileName(options.name); 49 | const snakeName = snakeCase(name); 50 | const projectDirectory = options.directory 51 | ? `${toFileName(options.directory)}/${name}` 52 | : name; 53 | const projectDescription = options.description; 54 | const repoUrl = options.repoUrl; 55 | const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-'); 56 | const projectRoot = `${projectRootDir(projectType)}/${projectDirectory}`; 57 | const parsedTags = options.tags 58 | ? options.tags.split(',').map((s) => s.trim()) 59 | : []; 60 | 61 | return { 62 | ...options, 63 | projectName, 64 | snakeName, 65 | repoUrl, 66 | projectDescription, 67 | projectRoot, 68 | projectDirectory, 69 | parsedTags, 70 | }; 71 | } 72 | 73 | function addFiles(options: NormalizedSchema): Rule { 74 | return mergeWith( 75 | apply(url(getTemplateFilesPath(options.template)), [ 76 | applyTemplates({ 77 | ...options, 78 | ...names(options.name), 79 | offsetFromRoot: offsetFromRoot(options.projectRoot), 80 | }), 81 | move(options.projectRoot), 82 | ]) 83 | ); 84 | } 85 | 86 | function getTemplateFilesPath(template: NxPythonTemplate) { 87 | if (template === 'django') { 88 | return `./files/django`; 89 | } 90 | if (template === 'flask') { 91 | return `./files/flask`; 92 | } 93 | return `./files/default`; 94 | } 95 | 96 | export default function (options: NxPythonSchematicSchema): Rule { 97 | const normalizedOptions = normalizeOptions(options); 98 | return chain([ 99 | updateWorkspace((workspace) => { 100 | const appProjectRoot = normalizedOptions.projectRoot; 101 | const sourceRoot = `${appProjectRoot}/src`; 102 | const { projectName } = normalizedOptions; 103 | const name = names(projectName).propertyName; 104 | const project = workspace.projects.add({ 105 | name: projectName, 106 | root: appProjectRoot, 107 | sourceRoot, 108 | projectType, 109 | }); 110 | 111 | project.targets.add({ 112 | name: 'build', 113 | builder: '@nx-python/nx-python:build', 114 | options: getBuildOptions( 115 | normalizedOptions.template, 116 | project, 117 | normalizedOptions 118 | ), 119 | }); 120 | 121 | project.targets.add({ 122 | name: 'serve', 123 | builder: '@nx-python/nx-python:serve', 124 | options: getServeOptions(normalizedOptions.template, project), 125 | }); 126 | 127 | project.targets.add({ 128 | name: 'test', 129 | builder: '@nx-python/nx-python:test', 130 | options: getTestOptions(normalizedOptions.template, project), 131 | }); 132 | 133 | project.targets.add({ 134 | name: 'lint', 135 | builder: '@nx-python/nx-python:lint', 136 | options: getLintOptions(normalizedOptions.template, project), 137 | }); 138 | }), 139 | addProjectToNxJsonInTree(normalizedOptions.projectName, { 140 | tags: normalizedOptions.parsedTags, 141 | }), 142 | addFiles(normalizedOptions), 143 | ]); 144 | } 145 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🐍 NxPy: Nx Python plugin 2 | 3 | This project was generated using [Nx](https://nx.dev). 4 | 5 |

6 | 7 | 8 |

9 | 10 | The `nx-python` plugin allows users to create a basic python application using `nx` commands. To add the plugin to your project, just follow these steps: 11 | 12 | ## Getting started 13 | 14 | ### Create a Nx Workspace 15 | 16 | Before installing the `nx-python` plugin, it is required to have a pre-configured Nx Workspace . If you don't, then proceed to create a new one executing the following command: 17 | 18 | ```bash 19 | npx create-nx-workspace python-workspace --preset=empty --cli=nx --nx-cloud true 20 | cd python-workspace 21 | ``` 22 | 23 | ### Install the `nx-python` plugin 24 | 25 | ```bash 26 | yarn add -D @nx-python/nx-python 27 | ``` 28 | 29 | ### Adding an application to our workspace 30 | 31 | To create a new python application based on this plugin, please execute the following command: 32 | 33 | ```bash 34 | nx g @nx-python/nx-python:app 35 | ``` 36 | 37 | **Note:** Replace `` with the name of your new application 38 | 39 | ### Advanced options 40 | 41 | * `--tags` or `-t` list of tags for project (used for linting) 42 | * `--description` Description of project 43 | * `--repoUrl` Repository URL 44 | * `--directory` or `-d` A directory where the project is placed 45 | * `--template` or `-f` python framework to use (f.ex `django` or `flask`, where `python` is used by default) 46 | 47 | #### Create Flask app 48 | 49 | ```bash 50 | nx g @nx-python/nx-python:app --template flask 51 | ``` 52 | 53 | #### Create Django app 54 | 55 | ```bash 56 | nx g @nx-python/nx-python:app --template django 57 | ``` 58 | 59 | ### Advanced configuration 60 | 61 | The plugin supports [cosmiconfig](https://www.npmjs.com/package/cosmiconfig) for global configuration. 62 | 63 | Simply add a `.nx-pythonrc` file to the root of your monorepo. 64 | Currently this configuration support specifying command options to be used 65 | 66 | ```json 67 | { 68 | "python": "python3", 69 | "commands": { 70 | "serve": "flask run", 71 | "lint": "-m pylint", 72 | "test": "-m pytest", 73 | } 74 | } 75 | ``` 76 | 77 | See `src/utils/commands.ts` for command examples 78 | 79 | You can also specify project specific command overrides in `workspace.json` project entries or in `project.json` per project 80 | 81 | ```json 82 | "my-app": { 83 | "python": "python3", 84 | "commands": { 85 | "serve": "flask run", 86 | "lint": "-m pylint", 87 | "test": "-m unittest discover -s ./ -p", 88 | } 89 | } 90 | ``` 91 | 92 | ## Usage 93 | 94 | After creating the `` application using the `nx-python` plugin. We can execute the build, lint, test and serve `nx commands` on this new application. Output will be stored on `dist//` directory. 95 | 96 | ### Building the app 97 | 98 | The `build` command is going to compile all the python files inside `` directory, using the `py_compile` native module. 99 | 100 | ```bash 101 | nx build 102 | ``` 103 | 104 | More information here: [py_compile](https://docs.python.org/3/library/py_compile.html) 105 | 106 | ### Linting the application 107 | 108 | Unfortunately Python doesn't have a native linting module(yet!). 109 | It is required that you install the linting module beforehand. 110 | 111 | After you have installed the linting module you can perform the lint process with: 112 | 113 | ```bash 114 | nx lint 115 | ``` 116 | 117 | ### Flake8 118 | 119 | `nx-python` uses the `Flake8` module by default to lint your application. 120 | 121 | More info here: [Flake8](https://flake8.pycqa.org/en/latest/) 122 | 123 | ```bash 124 | pip install Flake8 125 | ``` 126 | 127 | ### Serving the application 128 | 129 | This is going to execute the main file in your python application. 130 | 131 | ```bash 132 | nx serve 133 | ``` 134 | 135 | For flask and django, the main file is `manage.py` 136 | 137 | ### Testing your application 138 | 139 | The `test` command is going to execute all the test units inside your python app. You can add new test unit files. 140 | 141 | To test your python app, execute the command: 142 | 143 | ```bash 144 | nx test 145 | ``` 146 | 147 | ### Unittest 148 | 149 | If you are using the default native `unittest` python module to for tests: 150 | 151 | * The filename must include the prefix `test` 152 | 153 | See more info here: [unittest](https://docs.python.org/3/library/unittest.html) 154 | 155 | ## Dependency Graph 156 | 157 | `packages/project-graph` includes some code which detects python projects and adds modified files in python projects to the dependency graph for the project. 158 | 159 | To detect a python project it must either: 160 | 161 | * have one or more python files (`.py` extension) 162 | * have `"compiler": "python"` set in project `build` options 163 | 164 | ## Contributing 165 | 166 | 🐍 All contributions are welcome. Make sure you follow the [code of conduct](CODE_OF_CONDUCT.md) in this repository. 167 | 168 | ## MIT License 169 | 170 | Made with 💜 by [Code ON](https://codeon.rocks) | [Melvin Vega](https://github.com/melveg) & [Diana Rodriguez](https://github.com/sponsors/alphacentauri82) 171 | --------------------------------------------------------------------------------