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 timeitnumber times exucutions: timeit.Timer(stmt='pass', setup='pass', number=1000000)repeat times setup and repeatxnumber times exucution: timeit.repeat(stmt='pass', setup='pass', repeat=5, number=1000000)import cProfilecProfile.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 pytesttest_*.py files under current directory: % pytestPython 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 module1from 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 installfrom 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-deploydoc¶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