This study note is based on:
Concepts:
(Optional) Let [project_name]='pyUdemy'. At terminal, choose one of the environment managements:
% pip3 install virtualenv
% virtualenv [project_name]
% [project_name]/Scripts/activated.bat
% conda create -n [project_name] Python=3.8
% conda activate [project_name]
% pip install -r requirements.txt
% pip list
% exit
% isort mymodule.py
Element | Naming style | Example |
---|---|---|
pacakge | lowercase | pacakgename |
interface | CapitalizedWords | InterfaceName |
class | CapitalizedWords, CapWords, CamelCase | ClassName |
function | lower_case_with_underscore, snake_case, (sometimes mixedCase) |
function_name, (functionName) |
variable | lower_case_with_underscore, snake_case, (sometimes mixedCase) |
variable_name, (variableName) |
method | lower_case_with_underscore, snake_case, (sometimes mixedCase) |
method_name, methodName |
utility | mixedCase | utilityName |
constant | UPPER_CASE_WITH_UNDERSCORE | CONSTANT_1 |
%pip3 install pylint
% pylint mymodule.py
% pylint .
Pylint category | Description | VS Code category mapping |
---|---|---|
Convention (C) | Programming standard violation | Information (green underline) |
Refactor (R) | Bad code smell | Hint (light bulbs) |
Warning (W) | Python-specific | problems Warning |
Error (E) | Likely code bugs | Error (red underline) |
Fatal (F) | An error prevented further Pylint processing | Error |
% pip3 install flake8
% flake8 mymodule.py
% flake8 .
Flake8 category | Description | VS Code category mapping |
---|---|---|
F | An error prevented further Flake8 processing | Error |
E | Likely code bugs | Error |
W | Python-specific | Warning |
autopep8 (suggested): check and correct to conform to the PEP 8 style guide (based on Flake8)
% pip3 install autopep8
% autopep8 mymodule.py --diff
% autopep8 mymodule.py
% autopep8 .
black: not able to setup config file
% pip3 install black
% black mymodule.py --diff
% black mymodule.py
% black .
%pip3 install pydocstyle
% pydocstyle --convention=google mymodule.py
% pydocstyle --convention=google .
The function below takes and returns a string and is annotated as follows
def greeting(x: data_type) -> data_type:
return some_function(x)
def greeting(x: union[data_type, data_type]) -> union[data_type, data_type]:
return some_function(x)
Dict
(dict, MutableMapping[KT, VT]): A generic version of dict. Useful for annotating return types. To annotate arguments it is preferred to use an abstract collection type such as MappingList
(list, MutableSequence[T]): Generic version of list. Useful for annotating return types. To annotate arguments it is preferred to use an abstract collection type such as Sequence or Iterable.Set
(set, MutableSet[T]): A generic version of builtins.set. Useful for annotating return types. To annotate arguments it is preferred to use an abstract collection type such as AbstractSet.Any
: Special type indicating an unconstrained type.NoReturn
: Special type indicating that a function never returns.TypeAlias
: Special annotation for explicitly declaring a type alias.Tuple
: Tuple type; Tuple[X, Y] is the type of a tuple of two items with the first item of type X and the second of type Y. The type of the empty tuple can be written as Tuple[()].Union
: Union type; Union[X, Y] is equivalent to X | Y and means either X or Y.Optional
: Optional type. Optional[X] is equivalent to X | None (or Union[X, None]).Callable
: Callable type; Callable[[int], str] is a function of (int) -> str.%pip3 install mypy
% mypy mymodule.py
% mypy .
timeit: time a
import timeit
number
times exucutions: timeit.Timer(stmt='pass', setup='pass', number=1000000)
repeat
times setup and repeat
xnumber
times exucution: timeit.repeat(stmt='pass', setup='pass', repeat=5, number=1000000)
import cProfile
cProfile.run("print('a')")
import cProfile
import io
import pstats
import random
import sys
from functools import wraps
from vector import Vector2D
def profile(fn):
@wraps(fn)
def profiler(*args, **kwargs):
profiler = cProfile.Profile()
profiler.enable()
fn_result = fn(*args, **kwargs)
profiler.disable()
stream = io.StringIO()
ps = pstats.Stats(profiler, stream=stream).sort_stats('time')
ps.print_stats()
print(stream.getvalue())
return fn_result
return profiler
@profile
def test_addition_own_implementation():
for _ in range(100_000):
# your code being profiled
v1 = Vector2D(random.randint(-10, 10), random.randint(-10, 10))
v2 = Vector2D(random.randint(-10, 10), random.randint(-10, 10))
v3 = v1 + v2 # noqa
def main() -> int:
test_addition_own_implementation()
return sys.exit(0)
if __name__ == '__main__':
main()
unittest.TestCase
.import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
pip3 install pytest
test_*.py
files under current directory: % pytest
Python Package is a directory structure.
.
└── PACKAGING
├── my_package # this is the actual python package
│ │
│ │ #############
│ │ # Main body #
│ │ #############
│ ├── module1
│ │ ├── _module1_a.py
│ │ │ ├── print_hello_world()
│ │ │ └── print_name()
│ │ ├── _module2_b.py
│ │ │ ├── vector
│ │ │ └── string
│ │ ├── tests
│ │ │ ├── test_print.py
│ │ │ └── __init__.py
│ │ └── __init__.py
│ ├── module2
│ │ ├── _module2_a.py
│ │ ├── _module2_b.py
│ │ └── __init__.py
│ ├── module3.py
│ ├── __init__.py
│ │
│ │ #################
│ │ # Documentation #
│ │ #################
│ ├── doc
│ │ ├── api.md
│ │ └── index.md
│ ├── mkdocs.yml
│ └── README.md
└── setup.py or main.py
main.py
¶setup.py
: outside of the package, the import statemen in this .py
file is the entering point to load and execute the package, __all__
in __init__.py
and underscored _module.py
as the package modularization , it accesses the functions in ./PACKAGING/my_package/module1/_module1_a.py
via module1
from my_package.module1 import print_hello_world, print_name
def main() -> None:
print_hello_world()
print_name('Chen')
if __name__ == '__main__':
main()
my_package
¶my_package
: A regular package is typically implemented as a directory containing __init__.py
files that labels sub-directories as a part of the Python package. __init__.py
¶__init__.py
: a indicating file __all__
in __init__.py
, the main.py
is able to access the method under the module folder. e.g.: ./PACKAGING/my_package/module1/init.pyfrom ._module1_a import print_hello_world, print_name
__all__=[
"print_hello_world",
"print_name"
]
_module*.py
¶_module*.py
: as part of the package, this .py
files contain classes, functions, or methods. main.py
access to the function via the its parent directory. e.g.: ./PACKAGING/my_package/module1/_module1_a.pydef print_hello_world() -> None:
print("Hello world!")
def print_name(name: str) -> None:
print(f"Hello {name}")
setup.py
¶setup.py
% python setup.py develop
% python setup.py install
from setuptools import setup
CLASSIFIERS = '''\
License :: OSI Approved
Programming Language :: Python :: 3.7 :: 3.8
Topic :: Software Development
Operating System :: Microsoft :: Windows
Operating System :: POSIX
Operating System :: Unix
Operating System :: MacOS
'''
DISTNAME = 'my_package'
AUTHOR = 'Weiquan Luo'
AUTHOR_EMAIL = 'weiquan.luo1221@email.com'
DESCRIPTION = 'This is a my_package.'
LICENSE = 'MIT'
README = 'This is a simple my_package python package.'
VERSION = '0.1.0'
ISRELEASED = False
PYTHON_MIN_VERSION = '3.7'
PYTHON_MAX_VERSION = '3.8'
PYTHON_REQUIRES = f'>={PYTHON_MIN_VERSION}, <={PYTHON_MAX_VERSION}'
INSTALL_REQUIRES = [
'numpy',
'scipy'
]
PACKAGES = [
'fastvector',
'tests'
]
metadata = dict(
name=DISTNAME,
version=VERSION,
long_description=README,
packages=PACKAGES,
python_requires=PYTHON_REQUIRES,
install_requires=INSTALL_REQUIRES,
author=AUTHOR,
author_email=AUTHOR_EMAIL,
description=DESCRIPTION,
classifiers=[CLASSIFIERS],
license=LICENSE
)
def setup_package() -> None:
setup(**metadata)
if __name__ == '__main__':
setup_package()
mkdocs
: After preparing doc
and mkdocs.yml
,pip3 install mkdocs
% mkdocs --help
% mkdocs build
% mkdocs serve
% mkdocs gh-deploy
doc
¶doc
: folder use to create html file
api.md
: specify what api(class, function, method, etc) should be presented, then retrive the docstring of api to generate html documentation.
# References
## Mehod
::: module1.print_name
::: module1.print_name
## Class
::: module2.vector
::: module2.string
index.md
: homepage for the package website.
# my_package
This is a my_package.
mkdocs.yml
¶mkdocs.yml
: styling file.site_name: FastVector
site_description: "This is a simple vector python package."
theme:
name: "material"
palette:
primary: "blue"
accent: "grey"
plugins:
- search
- mkdocstrings
markdown_extensions:
- pymdownx.highlight
- pymdownx.superfences
nav:
- "Start": index.md
- "API": api.md