Index

A migration metadata, 266 running migrations, 268, 269 Abstract base classes, 223 setting up a new project, 264 @abc.abstractmethod decorator, 224 using constants in migrations, 267 __subclasshook__(...) method, 224 __anext__() method, 330 vs. typing module types, 477 apd.aggregation package, 397, 516, 524 virtual subclasses, 223 clean functions (see clean functions) Actions, 560 database, 254 analysis process, 571, 572 get_data_by_deployment(...) config file, 573, 575 function, 413, 416 DataProcessor class, 561 get_data(...) function, 415 extending, 581 plot_sensor(...) function, 458 IFTTT service, 566 plotting data, 429 ingesting data, 567, 571 plotting functions, 421 logs, 567 query functions, 417 trigger, 563, 564 apd.sensors package, 106 Adafruit, 42, 486 APDSensorsError, 500 Adapter pattern, 229 DataCollectionError, 500 __aenter__() method, 331, 365 directory structure, 108 __aexit__(...) method, 331, 365 extending, 149 Aggregation process, 533 IntermittentSensorFailureError, 500 aiohttp library, 336 making releases, 141 __aiter__() method, 330 sensors script, 32, 36, 130, 147, 148, Alembic, 264 153, 155, 156, 535 ambiguous changes, 268 UserFacingCLIError, 502 creating a new revision, 265 apd.sunnyboy_solar package, 148, current version, 269 155, 173 downgrading, 268, 270 API design, 190 irreversible, migrations, 270 authentication, 190 listing migrations, 269 versioning, 240, 241, 243 merging, migrations, 269

589 © Matthew Wilkes 2020 M. Wilkes, Advanced Python Development, https://doi.org/10.1007/978-1-4842-5793-7 Index

AssertionError, 71, 498 Event class, 333 Assert statement, 498 gather(...) function, 326, 330 Async code get_running_loop( ), 373 pytest plugin, 346 Lock class, 333 setup.cfg, 346 loop.add_signal_handler(...) method, Asynchronous databases 578 (see also Signal module) complex queries (see Complex loop.call_later(...) method, 578 queries, ORM) ython decorators.call_soon(...) SQLAlchemy ORM (see SQLAlchemy method, 578 ORM) loop.run_in_executor(...) Asynchronous test functions function, 334, 335, 373 aggregation code sensor endpoints, 347 run(...) function, 324, 345 HTTP response, 347 Semaphore class, 333 test server (see Test servers) sleep(...) function, 326, 332 AsyncIO code, 322 Audit log, 532 async def, 323 Automatic type inference, 159, 160 async for, 327, 329, 330 __await__( ) method, 325 async lock, 332 Awaitables, 325 async with, 331 cancel( ) method, 568 benchmarking, 340 implementation details, 325 comparison of tasks and tasks, 325 , 326 await keyword, 324 concurrent code safety, 333 concurrent execution, 326 event loop, 333 B force switch, 332 black, 94 has lost, 341 applying to existing codebase, 94 has won, 341 installing, 94 HTTP client, 336 purpose, 93 limitations, 339 Blocking, 285, 322 loop argument, 515 breakpoint( ) function, 48 synchronization, 332, 333 debugging threads, 11 synchronous libraries, 334, 335 builtins, 2 synchronous vs. asynchronous, 323, 334 breakpoint( ) function, 10 testing, 345 changing the debugger, 11 asyncio module, 324 using, 10 Condition class, 333 dir(...) function, 170 create_task(...) function, 325, 326 filter(...) function, 2

590 INDEX

getattr(...) function, 158 customisation, 165 help(...) function, 2 enabling, 165 map(...) function, 278 @confirmation_option(...) open(...) function, 116 decorator, 167 print(...) function, 6, 35, 37 echo(...) function, 35 sorted(...) function, 202, 297 file handling, 162 vars(...) function, 170 flags, 278 bytecode, 296 group, 155 disassembling, 296 @help_option(...) decorator, 166 example, 297 metavar parameter, 154 .pyc files, 296 option, 156 simultaneous execution, 298 @password_option(...) decorator, 167 secho(...) function, 37, 161 @version_option(...) decorator, 166 Closures, 197, 198 __call__(...) method, 204 minimal example, 197 CHANGES.md file using classes instead, 204 apd.sensors package, 136 collections.abc module, 477 semantic versioning, 138 AsyncIterator class, 477 Classic SQLAlchemy style Collection class, 492 run_in_executor(...) function, 374 Container class, 492 stmt objects, 370 Iterable class, 492 @classmethod decorator, 62, 263 Mapping class, 492 clean functions, 422 Sequence class, 492 clean_magnitude(...) function, 425 Sized class, 492 clean_passthrough(...) function, 422, collections module, 361, 426 424, 542 deque class, 426 clean_temperature_fluctuations(...) namedtuple(...) function, 361 (see also function, 474, 477 Dynamic class generation) clean_watthours_to_watts(...) Command-line interface, 29 function, 458, 459, 488 argparse module, 34 purpose, 422 argv, 30, 33 specifying in config, 423 bold text, 37 Click, 153 click, 34–37 argument types, 153, 162, 163, 278 command(...) decorator, 35 creating custom, 163 secho(...), 36 latitude/longitude example, 162 exit codes, 161 autocomplete, 163, 165, 182 flags, 31, 33, 153

591 INDEX

Command-line interface (cont.) contextvars module ifmain, 29 context.run(...) function, 393 __name__ attribute, 30 ContextVar class, 393 signal handlers, 575 copy_context() function, 393 subcommands, 153 Control flows, 559 Command-line tool, 539, 571 Cookiecutter, 247 Complex queries, ORM aggregation process, 252–254 against views, 388–391 alembic documentation, 268 alembic revision, 381 apd.sensors, 250 ExprComparator type, 382, 385 install templates, 248 filter section, 381 preexisting templates, 248 @hybrid_property decorator, 381 pre/post-generation hooks, 251 hybrid property, 385 project creation, 248 indexes, 386 templates creation, 249, 250 transparent optimized comparator, 383 Coroutines, 324 update_expression, 382, 384 defining, 323 Config class, 448 CPython, 296 changes to support maps, 445 Custom classes, 361 (see also Maps) data classes, 361 (see also dataclasses created by end users, 481 module) draw(...) function, 448 custom initializers, 362 get_data(...) function, 448 defining fields, 362 SolarCumulativeOutput config, 155 dictionary conversion, 363 (see also apd.sunnyboy_solar equality, 363 package) field configuration, 363 typing, 447 immutability, 363 configparser, 174, 178 mutable defaults, 364 Configuration files, 174 ordering, 363 console_scripts, 129 uses, 361 Declarative approach, 130 (see also for mocking, 361 (see also mocking) setup.cfg) named tuple, 238, 361, 362 __contains__(...) method, 492 named tuple, adding methods to, 362 contextlib module, 364 __slots__, 461 @asynccontextmanager decorator, 365 Custom index server @contextmanager decorator, 364, 365 dependency metadata, 121 FakeAIOHttpClient, 365 integrity, 124, 125 Context managers, 295 warehouse, 120 Context variable, 582, 583 Custom map chart, 449, 450

592 INDEX D Descriptors, 260 alembic.ini file, 264 Data classes create_all(...) function, 263, 265 backwards compatibility of env.py, 265 constructors, 446 migration framework, 263 custom repr behavior, deserialize(...) functions, 235 comparison, 364 Design patterns, 229 dataclass decorator, 362 DHT base class, 506 hashable, 363 Discoverability, 354 dataclasses module, 361 dis module, 296 @dataclass decorator, 361, 362 Distribution, 105 field class, 363 C extensions, avoiding, 148 __post_init__(...) method, 362 converting to wheel, 126 DataPoint objects, 337, 397 cryptographic signing, 125 DataProcessor class, 561 hash, 123 datetime.date.today( ) function, 379 Immutability, 125 datetimes, 215 releasing, 141 db_session_var context variable, 399 source distribution, 110, 142 Debugging, 8, 400 src layout, 106 Decision tree, 218 Django, 105, 190, 258, 375, 386, 387 authorization, 191 Documentation, 130 databases, 255 draw(...) function, 479 generator control flow, 559 Duck typing, 51 metaclasses, 218 Dynamic class generation, 230 parallelization, 342 Dynamic dispatch, 51 Decorators, 196 single dispatch, 476 with arguments, 202, 204 URL-based dispatch for the web, 195 class-based, 204 generic decorators, 205 Minimal example, 200 E typed, 206 Elasticsearch, 256 Delayed teardown, 355 Enhanced generator, 548 Dependencies, 18 classes as an alternative, 551 conditional dependencies, 42, 111–113 converting to an iterator, 552 development dependencies, 19 iterable, 552 optional dependencies, 193 refactoring functions, 554, 555 pinning versions (see Version pin) return value of yield statement, 548 specifying, 110 sending data, 549

593 INDEX

Enhanced generator (cont.) unittest package, 512 standard, 553 tracebacks, 502, 503 using classes, 551 block, 504–506 __enter__() method, 364 raise, 506, 507 entry_points, 129, 171 TypeError/ValueError, 497 find all groups, 171 Ethics, 382, 520 list group contents, 172 __exit__(...) method, 364 resolving references, 173 Extended tuple unpacking, 252 use, 170 enum module, 161 Flag class, 576 F implementing a bitmask, 576 File modes, 114 IntEnum class, 161 Filtering data .env files, 179 deployment_id, 406 Environment variables, 178 get_data(...) method, 404, 405 , 182 helper functions, 407, 408 PYTHONOPTIMIZE environment sensor deployments, 405 variable, 498 Fixture scoping PYTHONWARNINGS environment conftest.py module, 354 variable, 518 delayed, 355 reading, 178 effects, 355 setting with pipenv, 179 HTTP server, 354 __eq__(...) method, 362, 385 test_http_get.py test module, 355 Error handling, 491 FizzBuzz, 3 abstract base classes, 493 flake8, 93 custom exceptions, 498, 499, 501, 502 exclude checks, 95 exceptions, 496 , 192, 288 implementations, 495 accessing request data, 205 IndexError, 497 API server, minimal example, 194 items from container, 492 @app.route(...) decorator, 194, 195, 210 KeyboardInterrupt, 496 blueprints, 241, 243 KeyError, 497 blueprints, functional testing, 348 LookupError, 497 setting response status and headers, RuntimeError, 497 205 SystemExit, 497 flit, 119, 145 testing, 507 __format__(...) method, 219 behavior, 508–511 Fraction, 53 mock objects, 513, 514 f-strings, 6, 159, 164, 201, 261, 317

594 INDEX

Functional tests, 64, 243, 347 git config command, 179 functools module, 202, 484 .gitignore file, 24 @cached_property decorator, 486, 489 Global keyword, 305 cmp_to_key(...) function, 202 Global variables @lru_cache decorator, 484, 485, 489 argument, 393 @singledispatch decorator, 476 ClientSession object, 392 __future__ imports, 294 contextvars feature, 392 annotations, 294 get() method, 393 syntax rules, 294 parameter, 392 pattern, 394 pragmatic view, 392 G -local variable, 393 Generator function, 271–274 Greenlets, 343 advancing manually, 415, 548 gunicorn, 245 chaining, 544 complex example, 413 enhanced generators, 550 H execution flow, 408, 410 handle(...) method, 564 as loop bodies, 541, 542 hashlib, 232 processing own output, 546 h11 library, 288 send(...) method (see Enhanced HMAC, 209, 231, 245 generator) HTTP requests, 270, 283, 285, 336, 343, 348 get_data(...) function, 403, 471 get_data_by_deployment(...) function, 445, 472 I get_data_ongoing(...) functions, 581, 583 idle() method, 562 get_data_points(...) function, 356 ifmain, 57, 307 __getitem__(...) method, 92 Import-time side effects, 201 get_sensor_by_path(...) function, 507 Index server, 119 get_sensors(..) function, 176, 511 catastrophic hardware GIL, 298 failure, 123 atomic operations, 297 commercial environments, 120 avoiding with multiprocessing, 321 pypiserver (see pypiserver) implementation details, 344 static indexes, 121 purpose, 298 warehouse, 120 git, 98 Information security, 158 add--patch, 98 getattr(...) traversal, 158 bisect, 153 Untrusted pickles, 231

595 INDEX ini, 174 displaying widgets, 11 __init__(...) method, 62, 177, 204, 217, 361, installation, 12 362 IPython, 13 __init__.py, 106 kernels on remote computers, 38 Install-time code execution, 126 kernel specification, 38 Integration testing nbconvert, 27, 44 add_data_points(...) method, 366 notebook server, 12–15, 42 custom mock method, 366 keyboard shortcuts, 24 unittest.mock.Mock() object, 366 merging cells, 23 interactable_plot_multiple_charts(...)(...) Using pdb, 14 function, 455 Notebook server, 19 IronPython, 296 other programming languages, 11 isinstance(...) function, 223, 224 Jupyter widgets issubclass(...) function, 223 addition function, 431 iterable, async, 330 asyncio.run(...) function, 432 iterables, 330 calling synchronous functions, 433 iterator, async, 330 event loop, 435 Iterators, 271, 330 helper function, 435 consuming, 273, 278, 475, 476 HTTP request, 433 infinitely long, 274 interactive chart filtering, 436, 437 __iter__() method, 330 optional dependency, 430 itertools.cycle(...) function, 514 plot functions, 437–439 itertools module, 352, 408 plot_sensor(...) coroutine, 431, 432 chain(...) function, 352 task.done(), 434 groupby(...) function, 408, 412 wrapper functions, 434 JWT, 245 J, K , 296 join() method, 562 jq, 123, 187 L JSON, 215 lambda functions, 408 dumps(...) function, 228 Late binding, 51 loads(...) function, 228 Latin-1 encoding, 114 PostgreSQL fields, 257 __len__() method, 492 Type hints, 237 line_profiler, 463 JSONSerializedSensor, 228 Linting Jupyter, 11, 48 definition, 92 console, 12, 41 (see also REPL) Pull requests, 99

596 INDEX load_handler_config(...) function, 573 plot_date(...) function, 403, 421 Logging, 520 plotting maps (see Maps) adapter, 525, 526 pyplot, 407, 421 audit, 532 scatter plot, 403 configuration, 530 subplots, 421 custom actions, 523 Metaclasses, 217 filters, 528–530 Mocking, 347, 356, 358–360, 513 handlers, 532 mocking isinstance(...) checks, 512 individual, 523 module, 104 LogRecord attributes, 521 running as a script, 109 (see also Script) metadata, 524 Module scope, 354 nested hierarchy, 522 modwsgi, 245 record objects, 527, 528 Multilevel iterators logging.basicConfig(...) flow charts, 412 function, 521, 524 get_data_by_deployment, 414 Logging filters, 528–530 Multiprocessing, 291, 339 LogRecord factory, 527 benchmarking, 340 LRU cache, 483, 484 process pools (see ProcessPoolExecutor) Multithreading, 291 M avoid global state, 306 Multiple sensors, config objects/plot collating data, 307 function, 424 benchmarking, 340 main_loop() function, 584 bytecode, 296, 297 Maps, 440 deadlocks, 302–305 contours on maps, 443 GIL, 299 equirectangular projection, 441 HTTP spider example, 311 GIS libraries, 445 lowest-level, 292, 296 mercator projection, 442 low level threads, 292 OpenStreetMap project, 441 shared state, 304, 307, 308 plotting, 440, 444 stopping threads, 351 Markdown format, 131–133 synchronization, 312 matplotlib, 403 barriers, 316, 317 aspect ratio, setting, 441 conditions, 313, 314, 316 colorbars, 444 events, 318, 319 contour lines, 442 locks, 301 figures, 421 reentrant lock, 312 multiple series, 405 semaphores, 319, 320

597 INDEX

AsyncIO code (cont.) Optimizing control flow in tests, 350 caching, 477–479, 485, 486, 489 thread locks, 302 DataPoint records, 468 thread pools (see ThreadPoolExecutor) filtering database, 471–473 thread safety, 297, 299, 300 minimizing data to process, 425 mypy, 78 single sensor process, 469 debugging types, 87 os module, 178 ignore_missing_imports, 79 environ, 178, 211 reveal_type(...) pseudofunction, 87, 208 mkdir(...) function, 251 --strict, 92 path.join(...) function, 251 stubgen, 92 rename(...) function, 251 Unsupported operand types, 80 P N Package, 104 __name__ variable, 30 applying metadata __next__() method, 330 changes, 130 Nonblocking IO operations, 284, 285, dependencies, 347 287, 340 extras_require, 193 nonlocal keyword, 199 installing scripts, 103, 129 NoSQL databases, 256 metadata, 103, 131 namespace packages, 105 offline installation, 123 O private forks, 124 -O command-line flag, 498 version number, 116 operator module, 408 wheel, 104 attrgetter(...) function, 408 Parallelization, 284, 339, 341 itemgetter(...) function, 408 pdb, 7, 10 Optimizing a function break, 8 interpreting profile report, 459–461 breakpoints, conditional, 9 Jupyter notebook cell, 455 continue, 8 line_profiler, 463 debug, 8 New Relic, 468 import pdb; pdb.set_trace() profiling and threads, 455, 457, 458 (see breakpoint() function) SQL queries, 380 next, 8 timeit, 462 pdb++, 8 tracemalloc, 466, 467 post-mortem debugging, 9 yappi, 463–466 step, 8

598 INDEX

PEP8, 93 Pipfile.lock file, 24, 43 Avoiding PEP8 commits, 96 PiWheels, 39, 128 style guide, 93 pkg_resources module, 171 PEP342, 548 Plugin architectures, 147 PEP420, 144 alternative approaches, 181 PEP427, (see Wheels) autodetection, 167, 168 PEP440, 137 configuration, 167, 168, 175 PEP503, 120 error handling, 157 PEP508, 144 Poetry, 119, 144 PEP508, 42 PostgreSQL pubsub functionality, 570 PEP517, 118, 144 pre-commit, 96 PEP518, 118, 144 enabling, 97 PEP561, 101 skipping, 98 Persistent endpoints, 439 printf debugging, 6, 273 Pickle, 231 process(...) method, 580 advantages, 231 Processing data Cryptographic signing, 232 cleaner functions, 426, 428 Pint, 215 cleaner functions, 427 Custom string formatting, 219 Jupyter cell, 429 example usage, 215 temperature sensor, 426 Quantity class, 216 ProcessPoolExecutor, 321, 322 to(...) function, 216 process_time() function, 458 type checking, 216 Profiling, 453 UnitRegistry() class, 215 callgrind, 473 usage, 216 cProfile.run(...) function, 453 pip IDEs, 454 install, 12 profile.run(...) function, 453 sudo, 125 report, 454 Pipenv, 18, 48 visualizing speed, 474 criticism, 18 yappi, 474 editable installations, 106 @property decorator, 262, 486 environment variables, 179 (see also Descriptors) limitations, conditional Prototyping dependencies, 110 approaches, 1 Lock file, 24, 43, 123 comparison, 16 for production deployments, 180 development flow, 1 python_version, 43 , 1 reproducible builds, 110 post-mortem debugging, 10

599 INDEX

Prototyping (cont.) ScopeMismatch error, 354 Python script, 6, 7 @skipif(...) decorator, 150 REPL, 2–4, 6 tear down code, 350 using Jupyter notebooks, 149 Pytest fixtures, setup/teardown, 352 psutil, 24 Python decorators cpu_percent(...) function, 25 helper function, 197 cpu_stats() function, 24 utility function, 196 sensors_battery() function, 28 virtual_memory() function, 28 .pyc files, 296 Q PyCharm, 8 Query functions breakpoints, 8 async iterable, 403 .pyi files, 90, 188 database connection, 398 PyPI, 119 (see also Index server) DataPoint objects, 399 long_description, 131 db_session_var context variable, 399 long_description_content_type, 131 function signatures, 397 test server, 141 get_data() function, 400, 401 ~/.pypirc file, 143 get_data(...) filters, 416 pypiserver, 120 helper context manager, 402 authentication, 121 Jupyter notebook, 397 configuring, 121, 122 list/tuple, 397 hosting on Raspberry Pi, 121 premature optimization, 401 pyproject.toml, 118, 119 query.all(), 401 PyPy, 296, 344 RAM usage vs. instantiation time, 402 pytest, 55 sensor records, 399 approx(...), 57 sensor type, 397 filtering by mark, 72 utility functions, 399 fixtures, 68, 346, 350, 353 version number, 397 fixtures that return generators, 352 Queue object, 556 http server fixture, 348 coroutine, 557 layering fixtures, 353 execution flow, 558 mark decorator, 72, 346, 348 queue module, 292 marking classes and modules, 348 Empty exception, 308 pipenv run pytest, 63 LifoQueue class, 308 pytest-asyncio, 346 Queue class, 292, 308 pytestmark, 348 detecting the end of a queue, 308 raises(...), 57 get() method, 308

600 INDEX join() method, 308 S put() method, 308 Schemaless databases, 256 task_done() method, 308 Script, 104 underlying synchronisation dependencies, 109 implementation, 313 invoking, 129 select.select(...) function, 285 R Sensor base class, 236 example, 60 raise statement, 496, 506 format(...) method, 85, 219 Raspberry Pi, 39 JSONSensor variant, 236 ARM processors, 42 JSONSerializedSensor variant, 228 connection, Jupyter, 44 name attribute, 239 DHT22 sensor, 44 SerializableSensor variant, 224 Jupyter remote access, 38 , 221, 236 library, 42 typing, 83 precompiled wheels (see PiWheels) value() method, 85, 486 README file, 136 sensor_name parameter, 445 encoding, 113, 114 Sensor plugin garbled character, 115 allowing third party, 167 mode, 113 command option README.md file, 135 canned options, 166, 167 re.escape(...) function, 519 click.option line, 156 Relational databases, 257, 258, 371 Click’s parsing system, 163, 164 Remote kernels, 44 --develop, 157 specification, 40 error handling, 159, 161 remote-pdb, 11 off-loading parsing, argument REPL types, 162, 163 adding logic, 3 subcommands, 153–156 indent parsing rules, 4, 5 Pipfile, 180, 181 interpreter, 4 Sensors, 533, 535 multiline constructs, 3, 6 API implementation, 537 viewing help, 2 command-line tool, 539 __repr__() method, 362, 363 Sensors plugin, third party Requests, 270 apd.sensors vs. similar programs, 179 requirements.txt, 128 configuration-based system, 169 Return value, 271 configuration files, 174–176, 178 RuntimeError, 158

601 INDEX

Sensors plugin, third party (cont.) loading metadata from detects sensors, using fixed README files, 113 names, 169, 170 tests_require, 347 entrypoints, 170, 172, 173 side_effect method, 514 SerializableSensor, 228 Signal module, 576 Serialization problem, JSON values, 237 SIGINFO constant, 575 serialize(...) method, 221, 222 SIGINT constant, 576 Set literals, 211 signal(...) function, 576 Setting up, new project Signals enumeration, 576 complex function, 22 SIGUSR1 constant, 576 cpu_percent function, 26 site-packages, 129 installing dependencies, 24 __slots__, 461 IPv4/IPv6 addresses, 22 Software, third party Jupyter, 20 ad hoc signature, 221, 222 pipenv directory, 20 adapter pattern, 228, 229 psutils module, 24 SerializableSensor, 225, 226 setup.cfg, 95, 172 SolarCumulativeOutput sensor, 428 calender versioning, 138 SQLAlchemy, 258 check command, 142 best practices, 378 configuring, 143 BinaryExpression, 260 dist directory, 142 @cached_property decorator, 488 flake8 section, 95 classic style (see Classic format, 137 SQLAlchemy style) installing, 142 Column objects, 260 migrating from setup.py, 117 create_engine(...) function, 259 package metadata, 110 database functions, 379 PyPI, 119 declarative style, 259, 369 semantic versioning, 137 Enum field, 267 uploading, 141 @hybrid_property decorator, 378, 382 set_up_config(...) function, 214 insert statements, 370 setup.py, 103, 108, 118 migration framework, 263 excessive code, 110, 113 ORM, 369 install_requires, 109 session.commit() method, 372 setup(...) function, 108 session.execute(...) method, 371 Setuptools, 144 statement compilation phase, 370, 371 extras_require, 347 statement generation, 369 install_requires, 138 table definition, manual, 369

602 INDEX

type hints, 258 Terminology, 104 use in asynchronous code, 338 Testability, 59, 66, 67, 210, 242, 243, 347 using Alembic, 370 Test coverage, 73 SQLAlchemy functions, 379, 397 annotate report, 76 SQLAlchemy ORM branch coverage, 74, 75 alternative approaches, 391 .coveragerc file, 73 asyncio code, 368 HTML report, 74 query data, 376, 377 Test-driven development, 57 statement generator, 368 Testing Stackless Python, 343 assertions, 56 stand-alone data collection function, 275 Exception is raised, 57 @staticmethod decorator, 60–62 Floating point precision, 57 Statistics signal handler, 576 List containment, 56 Storing deployments, 439 Value is None, 56 String formatting, 219 Values are equal, 56 customising, 219 Values are unequal, 56 __str__() method, 62, 63, 66, 82 conversion function, 56 subprocess, 149 database applications, 417 check_output(...) function, 149 database setup fixtures, 417–419 Sunk cost fallacy, 58 optional arguments, 417 sys module, 158 overtesting, 77 argv variable, 31 parameterized tests, 420, 421 exit(...) function, 158, 161, 497 Pull requests, 99 path variable, 18 (see also Virtual Pytest, 55 environments) Subject Under Test, 68 setswitchinterval(...) function, 299 tautological tests, 65 version_info variable, 21 testing.TypeVar, 85 systemd, 122 Test servers, helper functions/fixture, 349 Threading module, 292 Barrier class, 316 T BrokenBarrierException, 316 Technologies wait() method, 316 attribute behavior, 279 Condition class, 313 database, 279 get(...) method, 313 generators, 280 notify_all() method, 314 Temperature conversion functions, 52, 55, notify() method, 314 219, 484 Event class, 318 Temperature sensor, 177 clear() method, 318

603 INDEX

Event class (cont.) generic types, 85–87 is_set() method, 318 isinstance(...) checks, 477 (see also set() method, 318 isinstance(...) function) wait() method, 318 Problems with .pyi files, 92 get_ident() function, 318 typing.Any, 86, 88 Lock() class, 301 ignoring modules, 216 acquire() method, 305 import typing as t, 82 context manager, 301 over-specifying types, 237 RLock class, 312 overtyping, 89 Semaphore class, 319 partial equivalence of int, float and Thread class, 292 bool, 86 join() method, 292 runtime checkability, 477 (see also name, 292 Abstract base classes) return values, 292 stub only packages, 101 start() method, 292 of test methods, 350 ThreadPoolExecutor, 294, 373 type hint files (see .pyi files) Futures, 295 typeshed, 100 hello world, 295 TypeError, 53 max_threads, 295 Typing module, 188 pool.submit(...) function, 295 Any type, 83 result() method, 295 AsyncIterator type, 477 using with asyncio, 334 Awaitable type, 328, 330 timeit, 462 Generator type, 549 time module, 318 Iterable type, 549 sleep(...) function, 318 List type, 81 time() function, 318 NamedTuple type, 238 T_key/T_value type variables, 479, 481 Optional type, 80 TLS certificates, 214 Sequence type, 81 TOML, 174 Tuple type, 81 Tracebacks, 158, 502 TYPE_CHECKING flag, 188 Tracemalloc, 466 TypeVar class, 480 twine, 142 Union type, 80 configure, 143 upload command, 142 Type checking, 77 U contravariant types, 480 Unittest, 56, 57 covariant types, 480 AsyncMock class, 357 debugging/overuse typing, 87, 88 MagicMock class, 357

604 INDEX

main(), 57 Warnings, 514 Mock class, 512 catch_warnings(...) context manager, 519 TestCase, 57 DeprecationWarning, 516 Unit testing filtering specific warnings, 518 aiohttp library, 356 suppressing, 518 branching logic, mocks, 360 treat as error, 518 ClientSession object, 356 warnings.warn(...) function, 514 generic mocking method, 359 -W command-line flag, 518 mocking, 357 Web frameworks, 183 responses, 356 Web microservices Uploading version authentication framework, 192 configuring twine, 144 decorators (see Python decorators) PyPI, 141 flask, 192–194 source distribution, 142 WebTest, 189 UTF-8 encoding, 114, 288 Wheels, 126 from existing distributions, 126 V generating, 142 invention of, 103 Variable scopes, 199 -manylinux, 126 vars(custom_sensors) function, 170 WSGI, 184 Version numbers, 137 application factory, 214 Alpha, Beta and Release Candidate, 137 definition, 184 when to increment, 156 functional tests, 189 Version pin, 18 Hello World, 184 approach, 141 iterable responses, 185 “compatible with” pins, 140 running servers in tests, 347 loose pinning, 139 start_response(...) function, 184 strict pinning, 140 using generators, 185 virtualenv, see Virtual environments wsgi.py file, 214 Virtual environments, 18, 106, wsgiref.simple_server, 184, 351 see also Pipenv Adding to Jupyter, 19 argparse, 32, 33 Y, Z including system packages, 18 YAML, 174 yappi, 463 W, X Yappi helper functions, 465 Waitress, 213, 214 yield from statement, 351 Warning filters, 518 yield statement, 273, 365, 548

605