a9x-webstatistics 0.1.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ COPYRIGHT AND PERMISSION NOTICE
2
+
3
+ Copyright (c) 2024, Andre von Arx, andrevonarx@bluewin.ch, and many contributors, see the THANKS file.
4
+
5
+ All rights reserved.
6
+
7
+ Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10
+
11
+ Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder.
12
+
@@ -0,0 +1,5 @@
1
+ include pyproject.toml
2
+ include *.md
3
+ include LICENSE
4
+ include dist_del
5
+ recursive-include tests test*.py
@@ -0,0 +1,298 @@
1
+ Metadata-Version: 2.1
2
+ Name: a9x_webstatistics
3
+ Version: 0.1.5
4
+ Summary: Web Statistics and Analytics Package
5
+ Home-page: https://github.com/ava007/a9x-webstatistics
6
+ Author: André von Arx
7
+ Author-email: andrevonarx@bluewin.ch
8
+ Project-URL: Documentation, https://github.com/ava007/a9x-webstatistics
9
+ Project-URL: Bug Reports, https://github.com/ava007/a9x-webstatistics/issues
10
+ Project-URL: Source Code, https://github.com/ava007/a9x-webstatistics
11
+ Keywords: webstats,statistics,analytics
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Topic :: Software Development :: Build Tools
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Operating System :: OS Independent
20
+ Requires-Python: >=3.7
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Provides-Extra: dev
24
+ Requires-Dist: check-manifest; extra == "dev"
25
+
26
+ # Web Statistics and Analytics
27
+
28
+ This package produces web statics and analytical output based on nginx access log files.
29
+
30
+ [![PyPI package](https://img.shields.io/badge/pip%20install-example--pypi--package-brightgreen)](https://pypi.org/project/a9x-webstatistics/) [![version number](https://img.shields.io/pypi/v/example-pypi-package?color=green&label=version)](https://github.com/ava007/a9x-webstatistics/releases) [![Actions Status](https://github.com/ava007/a9x-webstatistics/workflows/Test/badge.svg)](https://github.com/ava007/a9x-webstatistics/actions) [![License](https://img.shields.io/github/license/ava007/a9x-webstatistics)](https://github.com/ava007/a9x-webstatistics/blob/main/LICENSE)
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install a9x-webstatistics
36
+ ```
37
+
38
+
39
+ <details>
40
+ ----------------
41
+ ## old content from template starts here
42
+
43
+ [![PyPI package](https://img.shields.io/badge/pip%20install-example--pypi--package-brightgreen)](https://pypi.org/project/example-pypi-package/) [![version number](https://img.shields.io/pypi/v/example-pypi-package?color=green&label=version)](https://github.com/tomchen/example_pypi_package/releases) [![Actions Status](https://github.com/tomchen/example_pypi_package/workflows/Test/badge.svg)](https://github.com/tomchen/example_pypi_package/actions) [![License](https://img.shields.io/github/license/tomchen/example_pypi_package)](https://github.com/tomchen/example_pypi_package/blob/main/LICENSE)
44
+
45
+ This is an example [PyPI](https://pypi.org/) (Python Package Index) package set up with automated tests and package publishing workflow using GitHub Actions CI/CD. It is made primarily for GitHub + VS Code (Windows / Mac / Linux) users who are about to write and publish their first PyPI package. The package could serve as a starter / boilerplate / demo and the tutorial could give you a quick and concise explaination to solve some small but annoying problems you might encounter, such as package / module name confusion, and VS Code test configuration issues.
46
+ <summary><strong>Differences from pypa/sampleproject (click to show/hide)</strong></summary>
47
+
48
+ This example package is inspired by / based on the [official sample project pypa/sampleproject](https://github.com/pypa/sampleproject), but this package:
49
+
50
+ - is a simplified version of pypa/sampleproject (and the [official Python Packaging User Guide](https://packaging.python.org/))
51
+ - uses GitHub Actions for both testing and publishing, instead of Travis CI
52
+ - is tested when pushing `master` or `main` branch, and is published when create a release
53
+ - includes test files in the source distribution
54
+ - uses **setup.cfg** for [version single-sourcing](https://packaging.python.org/guides/single-sourcing-package-version/) (setuptools 46.4.0+)
55
+ - has **.vscode\settings.json** and **vscode.env** which adds **src/** folder to `PYTHONPATH`, so that test files don't have linting errors and may run with pytest in VS Code
56
+ - does not use flake8 for automated linting - it is sometimes too strict and inflexible, you may use pylint locally instead
57
+ - has this tutorial that covers everything you need to know in one page. Everything that might not be very useful, is hidden in collapsible sections that you can click to show
58
+ - has **[.editorconfig](https://editorconfig.org/#download)** file
59
+
60
+
61
+
62
+ ## Make necessary changes
63
+
64
+ ### Use as a template
65
+
66
+ [![Use the template](https://img.shields.io/static/v1?label=&message=Click%20here%20to%20use%20this%20package%20as%20a%20template%20to%20start%20a%20new%20repo%20on%20GitHub&color=brightgreen&style=for-the-badge)](https://github.com/tomchen/example_pypi_package/generate)
67
+
68
+ (Click the above button to use this example package as a template for your new GitHub repo, this will initialize a new repository and my commits will not be in your git history)
69
+
70
+ (If you do not use GitHub, you can [download the archive of the example package](https://github.com/tomchen/example_pypi_package/archive/main.zip))
71
+
72
+ ### Package, module name
73
+
74
+ Many use a same package and module name, you could definitely do that. But this example package and its module's names are different: `example_pypi_package` and `examplepy`.
75
+
76
+ Open `example_pypi_package` folder with Visual Studio Code, <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>F</kbd> (Windows / Linux) or <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>F</kbd> (MacOS) to find all occurrences of both names and replace them with your package and module's names. Also remember to change the name of the folder **src/examplepy**.
77
+
78
+ Simply and very roughly speaking, package name is used in `pip install <PACKAGENAME>` and module name is used in `import <MODULENAME>`. Both names should consist of lowercase basic letters (a-z). They may have underscores (`_`) if you really need them. Hyphen-minus (`-`) should not be used.
79
+
80
+ You'll also need to make sure the URL "https://pypi.org/project/example-pypi-package/" (replace `example-pypi-package` by your package name, with all `_` becoming `-`) is not occupied.
81
+
82
+ <details><summary><strong>Details on naming convention (click to show/hide)</strong></summary>
83
+
84
+ Underscores (`_`) can be used but such use is discouraged. Numbers can be used if the name does not start with a number, but such use is also discouraged.
85
+
86
+ Name starting with a number and/or containing hyphen-minus (`-`) should not be used: although technically legal, such name causes a lot of trouble − users have to use `importlib` to import it.
87
+
88
+ Don't be fooled by the URL "[pypi.org/project/example-pypi-package/](https://pypi.org/project/example-pypi-package/)" and the name "example-pypi-package" on pypi.org. pypi.org and pip system convert all `_` to `-` and use the latter on the website / in `pip` command, but the real name is still with `_`, which users should use when importing the package.
89
+
90
+ There's also [namespace](https://packaging.python.org/guides/packaging-namespace-packages/) to use if you need sub-packages.
91
+
92
+ </details>
93
+
94
+ ### Other changes
95
+
96
+ Make necessary changes in **setup.py**.
97
+
98
+ The package's version number `__version__` is in **src/examplepy/\_\_init\_\_.py**. You may want to change that.
99
+
100
+ The example package is designed to be compatible with Python 3.6, 3.7, 3.8, 3.9, and will be tested against these versions. If you need to change the version range, you should change:
101
+
102
+ - `classifiers`, `python_requires` in **setup.py**
103
+ - `envlist` in **tox.ini**
104
+ - `matrix: python:` in **.github/workflows/test.yml**
105
+
106
+ If you plan to upload to [TestPyPI](https://test.pypi.org/) which is a playground of [PyPI](https://pypi.org/) for testing purpose, change `twine upload --repository pypi dist/*` to `twine upload --repository testpypi dist/*` in the file **.github/workflows/release.yml**.
107
+
108
+ ## Development
109
+
110
+ ### pip
111
+
112
+ pip is a Python package manager. You already have pip if you use Python 3.4 and later version which include it by default. Read [this](https://pip.pypa.io/en/stable/installing/#do-i-need-to-install-pip) to know how to check whether pip is installed. Read [this](https://pip.pypa.io/en/stable/installing/#installing-with-get-pip-py) if you need to install it.
113
+
114
+ ### Use VS Code
115
+
116
+ Visual Studio Code is the most popular code editor today, our example package is configured to work with VS Code.
117
+
118
+ Install VS Code extension "[Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python)".
119
+
120
+ "Python" VS Code extension will suggest you install pylint. Also, the example package is configured to use pytest with VS Code + Python extensions, so, install pylint and pytest:
121
+
122
+ ```bash
123
+ pip install pylint pytest
124
+ ```
125
+
126
+ (It's likely you will be prompted to install them, if that's the case, you don't need to type and execute the command)
127
+
128
+ **vscode.env**'s content is now `PYTHONPATH=/;src/;${PYTHONPATH}` which is good for Windows. If you use Linux or MacOS, you need to change it to `PYTHONPATH=/:src/:${PYTHONPATH}` (replacing `;` with `:`). If the PATH is not properly set, you'll see linting errors in test files and pytest won't be able to run **tests/test\_\*.py** files correctly.
129
+
130
+ Close and reopen VS Code. You can now click the lab flask icon in the left menu and run all tests there, with pytest. pytest seems better than the standard unittest framework, it supports `unittest` thus you can keep using `import unittest` in your test files.
131
+
132
+ The example package also has a **.editorconfig** file. You may install VS Code extension "[EditorConfig for VS Code](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig)" that uses the file. With current configuration, the EditorConfig tool can automatically use spaces (4 spaces for .py, 2 for others) for indentation, set `UTF-8` encoding, `LF` end of lines, trim trailing whitespaces in non Markdown files, etc.
133
+
134
+ In VS Code, you can go to File -> Preferences -> Settings, type "Python Formatting Provider" in the search box, and choose one of the three Python code formatting tools (autopep8, black and yapf), you'll be prompted to install it. The shortcuts for formatting of a code file are <kbd>Shift</kbd> + <kbd>Alt</kbd> + <kbd>F</kbd> (Windows); <kbd>Shift</kbd> + <kbd>Option (Alt)</kbd> + <kbd>F</kbd> (MacOS); <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> (Linux).
135
+
136
+ ### Write your package
137
+
138
+ In **src/examplepy/** (`examplepy` should have been replaced by your module name) folder, rename **module1.py** and write your code in it. Add more module .py files if you need to.
139
+
140
+ ### Write your tests
141
+
142
+ In **tests/** folder, rename **test_module1.py** (to **test\_\*.py**) and write your unit test code (with [unittest](https://docs.python.org/3/library/unittest.html)) in it. Add more **test\_\*.py** files if you need to.
143
+
144
+ <details><summary><strong>The testing tool `tox` will be used in the automation with GitHub Actions CI/CD. If you want to use `tox` locally, click to read the "Use tox locally" section</strong></summary>
145
+
146
+ ### Use tox locally
147
+
148
+ Install tox and run it:
149
+
150
+ ```bash
151
+ pip install tox
152
+ tox
153
+ ```
154
+
155
+ In our configuration, tox runs a check of source distribution using [check-manifest](https://pypi.org/project/check-manifest/) (which requires your repo to be git-initialized (`git init`) and added (`git add .`) at least), setuptools's check, and unit tests using pytest. You don't need to install check-manifest and pytest though, tox will install them in a separate environment.
156
+
157
+ The automated tests are run against several Python versions, but on your machine, you might be using only one version of Python, if that is Python 3.9, then run:
158
+
159
+ ```bash
160
+ tox -e py39
161
+ ```
162
+
163
+ </details>
164
+
165
+ If you add more files to the root directory (**example_pypi_package/**), you'll need to add your file to `check-manifest --ignore` list in **tox.ini**.
166
+
167
+ <details><summary><strong>Thanks to GitHub Actions' automated process, you don't need to generate distribution files locally. But if you insist, click to read the "Generate distribution files" section</strong></summary>
168
+
169
+ ## Generate distribution files
170
+
171
+ ### Install tools
172
+
173
+ Install or upgrade `setuptools` and `wheel`:
174
+
175
+ ```bash
176
+ python -m pip install --user --upgrade setuptools wheel
177
+ ```
178
+
179
+ (If `python3` is the command on your machine, change `python` to `python3` in the above command, or add a line `alias python=python3` to **~/.bashrc** or **~/.bash_aliases** file if you use bash on Linux)
180
+
181
+ ### Generate `dist`
182
+
183
+ From `example_pypi_package` directory, run the following command, in order to generate production version for source distribution (sdist) in `dist` folder:
184
+
185
+ ```bash
186
+ python setup.py sdist bdist_wheel
187
+ ```
188
+
189
+ ### Install locally
190
+
191
+ Optionally, you can install dist version of your package locally before uploading to [PyPI](https://pypi.org/) or [TestPyPI](https://test.pypi.org/):
192
+
193
+ ```bash
194
+ pip install dist/example_pypi_package-0.1.0.tar.gz
195
+ ```
196
+
197
+ (You may need to uninstall existing package first:
198
+
199
+ ```bash
200
+ pip uninstall example_pypi_package
201
+ ```
202
+
203
+ There may be several installed packages with the same name, so run `pip uninstall` multiple times until it says no more package to remove.)
204
+
205
+ </details>
206
+
207
+ ## Upload to PyPI
208
+
209
+ ### Register on PyPI and get token
210
+
211
+ Register an account on [PyPI](https://pypi.org/), go to [Account settings § API tokens](https://pypi.org/manage/account/#api-tokens), "Add API token". The PyPI token only appears once, copy it somewhere. If you missed it, delete the old and add a new token.
212
+
213
+ (Register a [TestPyPI](https://test.pypi.org/) account if you are uploading to TestPyPI)
214
+
215
+ ### Set secret in GitHub repo
216
+
217
+ On the page of your newly created or existing GitHub repo, click **Settings** -> **Secrets** -> **New repository secret**, the **Name** should be `PYPI_API_TOKEN` and the **Value** should be your PyPI token (which starts with `pypi-`).
218
+
219
+ ### Push or release
220
+
221
+ The example package has automated tests and upload (publishing) already set up with GitHub Actions:
222
+
223
+ - Every time you `git push` or a pull request is submitted on your `master` or `main` branch, the package is automatically tested against the desired Python versions with GitHub Actions.
224
+ - Every time a new release (either the initial version or an updated version) is created, the latest version of the package is automatically uploaded to PyPI with GitHub Actions.
225
+
226
+ ### View it on pypi.org
227
+
228
+ After your package is published on PyPI, go to [https://pypi.org/project/example-pypi-package/](https://pypi.org/project/example-pypi-package/) (`_` becomes `-`). Copy the command on the page, execute it to download and install your package from PyPI. (or test.pypi.org if you use that)
229
+
230
+ If you want to modify the description / README of your package on pypi.org, you have to publish a new version.
231
+
232
+ <details><summary><strong>If you publish your package to PyPI manually, click to read</strong></summary>
233
+
234
+ ### Install Twine
235
+
236
+ Install or upgrade Twine:
237
+
238
+ ```bash
239
+ python -m pip install --user --upgrade twine
240
+ ```
241
+
242
+ Create a **.pypirc** file in your **$HOME** (**~**) directory, its content should be:
243
+
244
+ ```ini
245
+ [pypi]
246
+ username = __token__
247
+ password = <PyPI token>
248
+ ```
249
+
250
+ (Use `[testpypi]` instead of `[pypi]` if you are uploading to [TestPyPI](https://test.pypi.org/))
251
+
252
+ Replace `<PyPI token>` with your real PyPI token (which starts with `pypi-`).
253
+
254
+ (if you don't manually create **$HOME/.pypirc**, you will be prompted for a username (which should be `__token__`) and password (which should be your PyPI token) when you run Twine)
255
+
256
+ ### Upload
257
+
258
+ Run Twine to upload all of the archives under **dist** folder:
259
+
260
+ ```bash
261
+ python -m twine upload --repository pypi dist/*
262
+ ```
263
+
264
+ (use `testpypi` instead of `pypi` if you are uploading to [TestPyPI](https://test.pypi.org/))
265
+
266
+ ### Update
267
+
268
+ When you finished developing a newer version of your package, do the following things.
269
+
270
+ Modify the version number `__version__` in **src\examplepy\_\_init\_\_.py**.
271
+
272
+ Delete all old versions in **dist**.
273
+
274
+ Run the following command again to regenerate **dist**:
275
+
276
+ ```bash
277
+ python setup.py sdist bdist_wheel
278
+ ```
279
+
280
+ Run the following command again to upload **dist**:
281
+
282
+ ```bash
283
+ python -m twine upload --repository pypi dist/*
284
+ ```
285
+
286
+ (use `testpypi` instead of `pypi` if needed)
287
+
288
+ </details>
289
+
290
+ ## References
291
+
292
+ - [Python Packaging Authority (PyPA)'s sample project](https://github.com/pypa/sampleproject)
293
+ - [PyPA's Python Packaging User Guide](https://packaging.python.org/tutorials/packaging-projects/)
294
+ - [Stackoverflow questions and answers](https://stackoverflow.com/questions/41093648/how-to-test-that-pypi-install-will-work-before-pushing-to-pypi-python)
295
+ - [GitHub Actions Guides: Building and testing Python](https://docs.github.com/en/free-pro-team@latest/actions/guides/building-and-testing-python)
296
+
297
+
298
+ </details>
@@ -0,0 +1,273 @@
1
+ # Web Statistics and Analytics
2
+
3
+ This package produces web statics and analytical output based on nginx access log files.
4
+
5
+ [![PyPI package](https://img.shields.io/badge/pip%20install-example--pypi--package-brightgreen)](https://pypi.org/project/a9x-webstatistics/) [![version number](https://img.shields.io/pypi/v/example-pypi-package?color=green&label=version)](https://github.com/ava007/a9x-webstatistics/releases) [![Actions Status](https://github.com/ava007/a9x-webstatistics/workflows/Test/badge.svg)](https://github.com/ava007/a9x-webstatistics/actions) [![License](https://img.shields.io/github/license/ava007/a9x-webstatistics)](https://github.com/ava007/a9x-webstatistics/blob/main/LICENSE)
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install a9x-webstatistics
11
+ ```
12
+
13
+
14
+ <details>
15
+ ----------------
16
+ ## old content from template starts here
17
+
18
+ [![PyPI package](https://img.shields.io/badge/pip%20install-example--pypi--package-brightgreen)](https://pypi.org/project/example-pypi-package/) [![version number](https://img.shields.io/pypi/v/example-pypi-package?color=green&label=version)](https://github.com/tomchen/example_pypi_package/releases) [![Actions Status](https://github.com/tomchen/example_pypi_package/workflows/Test/badge.svg)](https://github.com/tomchen/example_pypi_package/actions) [![License](https://img.shields.io/github/license/tomchen/example_pypi_package)](https://github.com/tomchen/example_pypi_package/blob/main/LICENSE)
19
+
20
+ This is an example [PyPI](https://pypi.org/) (Python Package Index) package set up with automated tests and package publishing workflow using GitHub Actions CI/CD. It is made primarily for GitHub + VS Code (Windows / Mac / Linux) users who are about to write and publish their first PyPI package. The package could serve as a starter / boilerplate / demo and the tutorial could give you a quick and concise explaination to solve some small but annoying problems you might encounter, such as package / module name confusion, and VS Code test configuration issues.
21
+ <summary><strong>Differences from pypa/sampleproject (click to show/hide)</strong></summary>
22
+
23
+ This example package is inspired by / based on the [official sample project pypa/sampleproject](https://github.com/pypa/sampleproject), but this package:
24
+
25
+ - is a simplified version of pypa/sampleproject (and the [official Python Packaging User Guide](https://packaging.python.org/))
26
+ - uses GitHub Actions for both testing and publishing, instead of Travis CI
27
+ - is tested when pushing `master` or `main` branch, and is published when create a release
28
+ - includes test files in the source distribution
29
+ - uses **setup.cfg** for [version single-sourcing](https://packaging.python.org/guides/single-sourcing-package-version/) (setuptools 46.4.0+)
30
+ - has **.vscode\settings.json** and **vscode.env** which adds **src/** folder to `PYTHONPATH`, so that test files don't have linting errors and may run with pytest in VS Code
31
+ - does not use flake8 for automated linting - it is sometimes too strict and inflexible, you may use pylint locally instead
32
+ - has this tutorial that covers everything you need to know in one page. Everything that might not be very useful, is hidden in collapsible sections that you can click to show
33
+ - has **[.editorconfig](https://editorconfig.org/#download)** file
34
+
35
+
36
+
37
+ ## Make necessary changes
38
+
39
+ ### Use as a template
40
+
41
+ [![Use the template](https://img.shields.io/static/v1?label=&message=Click%20here%20to%20use%20this%20package%20as%20a%20template%20to%20start%20a%20new%20repo%20on%20GitHub&color=brightgreen&style=for-the-badge)](https://github.com/tomchen/example_pypi_package/generate)
42
+
43
+ (Click the above button to use this example package as a template for your new GitHub repo, this will initialize a new repository and my commits will not be in your git history)
44
+
45
+ (If you do not use GitHub, you can [download the archive of the example package](https://github.com/tomchen/example_pypi_package/archive/main.zip))
46
+
47
+ ### Package, module name
48
+
49
+ Many use a same package and module name, you could definitely do that. But this example package and its module's names are different: `example_pypi_package` and `examplepy`.
50
+
51
+ Open `example_pypi_package` folder with Visual Studio Code, <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>F</kbd> (Windows / Linux) or <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>F</kbd> (MacOS) to find all occurrences of both names and replace them with your package and module's names. Also remember to change the name of the folder **src/examplepy**.
52
+
53
+ Simply and very roughly speaking, package name is used in `pip install <PACKAGENAME>` and module name is used in `import <MODULENAME>`. Both names should consist of lowercase basic letters (a-z). They may have underscores (`_`) if you really need them. Hyphen-minus (`-`) should not be used.
54
+
55
+ You'll also need to make sure the URL "https://pypi.org/project/example-pypi-package/" (replace `example-pypi-package` by your package name, with all `_` becoming `-`) is not occupied.
56
+
57
+ <details><summary><strong>Details on naming convention (click to show/hide)</strong></summary>
58
+
59
+ Underscores (`_`) can be used but such use is discouraged. Numbers can be used if the name does not start with a number, but such use is also discouraged.
60
+
61
+ Name starting with a number and/or containing hyphen-minus (`-`) should not be used: although technically legal, such name causes a lot of trouble − users have to use `importlib` to import it.
62
+
63
+ Don't be fooled by the URL "[pypi.org/project/example-pypi-package/](https://pypi.org/project/example-pypi-package/)" and the name "example-pypi-package" on pypi.org. pypi.org and pip system convert all `_` to `-` and use the latter on the website / in `pip` command, but the real name is still with `_`, which users should use when importing the package.
64
+
65
+ There's also [namespace](https://packaging.python.org/guides/packaging-namespace-packages/) to use if you need sub-packages.
66
+
67
+ </details>
68
+
69
+ ### Other changes
70
+
71
+ Make necessary changes in **setup.py**.
72
+
73
+ The package's version number `__version__` is in **src/examplepy/\_\_init\_\_.py**. You may want to change that.
74
+
75
+ The example package is designed to be compatible with Python 3.6, 3.7, 3.8, 3.9, and will be tested against these versions. If you need to change the version range, you should change:
76
+
77
+ - `classifiers`, `python_requires` in **setup.py**
78
+ - `envlist` in **tox.ini**
79
+ - `matrix: python:` in **.github/workflows/test.yml**
80
+
81
+ If you plan to upload to [TestPyPI](https://test.pypi.org/) which is a playground of [PyPI](https://pypi.org/) for testing purpose, change `twine upload --repository pypi dist/*` to `twine upload --repository testpypi dist/*` in the file **.github/workflows/release.yml**.
82
+
83
+ ## Development
84
+
85
+ ### pip
86
+
87
+ pip is a Python package manager. You already have pip if you use Python 3.4 and later version which include it by default. Read [this](https://pip.pypa.io/en/stable/installing/#do-i-need-to-install-pip) to know how to check whether pip is installed. Read [this](https://pip.pypa.io/en/stable/installing/#installing-with-get-pip-py) if you need to install it.
88
+
89
+ ### Use VS Code
90
+
91
+ Visual Studio Code is the most popular code editor today, our example package is configured to work with VS Code.
92
+
93
+ Install VS Code extension "[Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python)".
94
+
95
+ "Python" VS Code extension will suggest you install pylint. Also, the example package is configured to use pytest with VS Code + Python extensions, so, install pylint and pytest:
96
+
97
+ ```bash
98
+ pip install pylint pytest
99
+ ```
100
+
101
+ (It's likely you will be prompted to install them, if that's the case, you don't need to type and execute the command)
102
+
103
+ **vscode.env**'s content is now `PYTHONPATH=/;src/;${PYTHONPATH}` which is good for Windows. If you use Linux or MacOS, you need to change it to `PYTHONPATH=/:src/:${PYTHONPATH}` (replacing `;` with `:`). If the PATH is not properly set, you'll see linting errors in test files and pytest won't be able to run **tests/test\_\*.py** files correctly.
104
+
105
+ Close and reopen VS Code. You can now click the lab flask icon in the left menu and run all tests there, with pytest. pytest seems better than the standard unittest framework, it supports `unittest` thus you can keep using `import unittest` in your test files.
106
+
107
+ The example package also has a **.editorconfig** file. You may install VS Code extension "[EditorConfig for VS Code](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig)" that uses the file. With current configuration, the EditorConfig tool can automatically use spaces (4 spaces for .py, 2 for others) for indentation, set `UTF-8` encoding, `LF` end of lines, trim trailing whitespaces in non Markdown files, etc.
108
+
109
+ In VS Code, you can go to File -> Preferences -> Settings, type "Python Formatting Provider" in the search box, and choose one of the three Python code formatting tools (autopep8, black and yapf), you'll be prompted to install it. The shortcuts for formatting of a code file are <kbd>Shift</kbd> + <kbd>Alt</kbd> + <kbd>F</kbd> (Windows); <kbd>Shift</kbd> + <kbd>Option (Alt)</kbd> + <kbd>F</kbd> (MacOS); <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> (Linux).
110
+
111
+ ### Write your package
112
+
113
+ In **src/examplepy/** (`examplepy` should have been replaced by your module name) folder, rename **module1.py** and write your code in it. Add more module .py files if you need to.
114
+
115
+ ### Write your tests
116
+
117
+ In **tests/** folder, rename **test_module1.py** (to **test\_\*.py**) and write your unit test code (with [unittest](https://docs.python.org/3/library/unittest.html)) in it. Add more **test\_\*.py** files if you need to.
118
+
119
+ <details><summary><strong>The testing tool `tox` will be used in the automation with GitHub Actions CI/CD. If you want to use `tox` locally, click to read the "Use tox locally" section</strong></summary>
120
+
121
+ ### Use tox locally
122
+
123
+ Install tox and run it:
124
+
125
+ ```bash
126
+ pip install tox
127
+ tox
128
+ ```
129
+
130
+ In our configuration, tox runs a check of source distribution using [check-manifest](https://pypi.org/project/check-manifest/) (which requires your repo to be git-initialized (`git init`) and added (`git add .`) at least), setuptools's check, and unit tests using pytest. You don't need to install check-manifest and pytest though, tox will install them in a separate environment.
131
+
132
+ The automated tests are run against several Python versions, but on your machine, you might be using only one version of Python, if that is Python 3.9, then run:
133
+
134
+ ```bash
135
+ tox -e py39
136
+ ```
137
+
138
+ </details>
139
+
140
+ If you add more files to the root directory (**example_pypi_package/**), you'll need to add your file to `check-manifest --ignore` list in **tox.ini**.
141
+
142
+ <details><summary><strong>Thanks to GitHub Actions' automated process, you don't need to generate distribution files locally. But if you insist, click to read the "Generate distribution files" section</strong></summary>
143
+
144
+ ## Generate distribution files
145
+
146
+ ### Install tools
147
+
148
+ Install or upgrade `setuptools` and `wheel`:
149
+
150
+ ```bash
151
+ python -m pip install --user --upgrade setuptools wheel
152
+ ```
153
+
154
+ (If `python3` is the command on your machine, change `python` to `python3` in the above command, or add a line `alias python=python3` to **~/.bashrc** or **~/.bash_aliases** file if you use bash on Linux)
155
+
156
+ ### Generate `dist`
157
+
158
+ From `example_pypi_package` directory, run the following command, in order to generate production version for source distribution (sdist) in `dist` folder:
159
+
160
+ ```bash
161
+ python setup.py sdist bdist_wheel
162
+ ```
163
+
164
+ ### Install locally
165
+
166
+ Optionally, you can install dist version of your package locally before uploading to [PyPI](https://pypi.org/) or [TestPyPI](https://test.pypi.org/):
167
+
168
+ ```bash
169
+ pip install dist/example_pypi_package-0.1.0.tar.gz
170
+ ```
171
+
172
+ (You may need to uninstall existing package first:
173
+
174
+ ```bash
175
+ pip uninstall example_pypi_package
176
+ ```
177
+
178
+ There may be several installed packages with the same name, so run `pip uninstall` multiple times until it says no more package to remove.)
179
+
180
+ </details>
181
+
182
+ ## Upload to PyPI
183
+
184
+ ### Register on PyPI and get token
185
+
186
+ Register an account on [PyPI](https://pypi.org/), go to [Account settings § API tokens](https://pypi.org/manage/account/#api-tokens), "Add API token". The PyPI token only appears once, copy it somewhere. If you missed it, delete the old and add a new token.
187
+
188
+ (Register a [TestPyPI](https://test.pypi.org/) account if you are uploading to TestPyPI)
189
+
190
+ ### Set secret in GitHub repo
191
+
192
+ On the page of your newly created or existing GitHub repo, click **Settings** -> **Secrets** -> **New repository secret**, the **Name** should be `PYPI_API_TOKEN` and the **Value** should be your PyPI token (which starts with `pypi-`).
193
+
194
+ ### Push or release
195
+
196
+ The example package has automated tests and upload (publishing) already set up with GitHub Actions:
197
+
198
+ - Every time you `git push` or a pull request is submitted on your `master` or `main` branch, the package is automatically tested against the desired Python versions with GitHub Actions.
199
+ - Every time a new release (either the initial version or an updated version) is created, the latest version of the package is automatically uploaded to PyPI with GitHub Actions.
200
+
201
+ ### View it on pypi.org
202
+
203
+ After your package is published on PyPI, go to [https://pypi.org/project/example-pypi-package/](https://pypi.org/project/example-pypi-package/) (`_` becomes `-`). Copy the command on the page, execute it to download and install your package from PyPI. (or test.pypi.org if you use that)
204
+
205
+ If you want to modify the description / README of your package on pypi.org, you have to publish a new version.
206
+
207
+ <details><summary><strong>If you publish your package to PyPI manually, click to read</strong></summary>
208
+
209
+ ### Install Twine
210
+
211
+ Install or upgrade Twine:
212
+
213
+ ```bash
214
+ python -m pip install --user --upgrade twine
215
+ ```
216
+
217
+ Create a **.pypirc** file in your **$HOME** (**~**) directory, its content should be:
218
+
219
+ ```ini
220
+ [pypi]
221
+ username = __token__
222
+ password = <PyPI token>
223
+ ```
224
+
225
+ (Use `[testpypi]` instead of `[pypi]` if you are uploading to [TestPyPI](https://test.pypi.org/))
226
+
227
+ Replace `<PyPI token>` with your real PyPI token (which starts with `pypi-`).
228
+
229
+ (if you don't manually create **$HOME/.pypirc**, you will be prompted for a username (which should be `__token__`) and password (which should be your PyPI token) when you run Twine)
230
+
231
+ ### Upload
232
+
233
+ Run Twine to upload all of the archives under **dist** folder:
234
+
235
+ ```bash
236
+ python -m twine upload --repository pypi dist/*
237
+ ```
238
+
239
+ (use `testpypi` instead of `pypi` if you are uploading to [TestPyPI](https://test.pypi.org/))
240
+
241
+ ### Update
242
+
243
+ When you finished developing a newer version of your package, do the following things.
244
+
245
+ Modify the version number `__version__` in **src\examplepy\_\_init\_\_.py**.
246
+
247
+ Delete all old versions in **dist**.
248
+
249
+ Run the following command again to regenerate **dist**:
250
+
251
+ ```bash
252
+ python setup.py sdist bdist_wheel
253
+ ```
254
+
255
+ Run the following command again to upload **dist**:
256
+
257
+ ```bash
258
+ python -m twine upload --repository pypi dist/*
259
+ ```
260
+
261
+ (use `testpypi` instead of `pypi` if needed)
262
+
263
+ </details>
264
+
265
+ ## References
266
+
267
+ - [Python Packaging Authority (PyPA)'s sample project](https://github.com/pypa/sampleproject)
268
+ - [PyPA's Python Packaging User Guide](https://packaging.python.org/tutorials/packaging-projects/)
269
+ - [Stackoverflow questions and answers](https://stackoverflow.com/questions/41093648/how-to-test-that-pypi-install-will-work-before-pushing-to-pypi-python)
270
+ - [GitHub Actions Guides: Building and testing Python](https://docs.github.com/en/free-pro-team@latest/actions/guides/building-and-testing-python)
271
+
272
+
273
+ </details>
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,4 @@
1
+ [build-system]
2
+ requires = ["setuptools>=46.4.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+ # https://packaging.python.org/en/latest/guides/writing-pyproject-toml/
@@ -0,0 +1,8 @@
1
+ [metadata]
2
+ version = attr: a9x_webstatistics.__version__
3
+ license_files = LICENSE
4
+
5
+ [egg_info]
6
+ tag_build =
7
+ tag_date = 0
8
+
@@ -0,0 +1,50 @@
1
+ import setuptools
2
+
3
+ with open('README.md', 'r', encoding='utf-8') as fh:
4
+ long_description = fh.read()
5
+
6
+ setuptools.setup(
7
+ name='a9x_webstatistics',
8
+ author='André von Arx',
9
+ author_email='andrevonarx@bluewin.ch',
10
+ description='Web Statistics and Analytics Package',
11
+ keywords='webstats, statistics, analytics',
12
+ long_description=long_description,
13
+ long_description_content_type='text/markdown',
14
+ url='https://github.com/ava007/a9x-webstatistics',
15
+ project_urls={
16
+ 'Documentation': 'https://github.com/ava007/a9x-webstatistics',
17
+ 'Bug Reports':
18
+ 'https://github.com/ava007/a9x-webstatistics/issues',
19
+ 'Source Code': 'https://github.com/ava007/a9x-webstatistics',
20
+ # 'Funding': '',
21
+ # 'Say Thanks!': '',
22
+ },
23
+ package_dir={'': 'src'},
24
+ packages=setuptools.find_packages(where='src'),
25
+ classifiers=[
26
+ # see https://pypi.org/classifiers/
27
+ 'Development Status :: 5 - Production/Stable',
28
+
29
+ 'Intended Audience :: Developers',
30
+ 'Topic :: Software Development :: Build Tools',
31
+
32
+ 'Programming Language :: Python :: 3',
33
+ 'Programming Language :: Python :: 3.9',
34
+ 'Programming Language :: Python :: 3 :: Only',
35
+ 'License :: OSI Approved :: MIT License',
36
+ 'Operating System :: OS Independent',
37
+ ],
38
+ python_requires='>=3.7',
39
+ # install_requires=['Pillow'],
40
+ extras_require={
41
+ 'dev': ['check-manifest'],
42
+ # 'test': ['coverage'],
43
+ },
44
+ # entry_points={
45
+ # 'console_scripts': [ # This can provide executable scripts
46
+ # 'run=examplepy:main',
47
+ # You can execute `run` in bash to run `main()` in src/examplepy/__init__.py
48
+ # ],
49
+ # },
50
+ )
@@ -0,0 +1,5 @@
1
+ __version__ = "0.1.5"
2
+
3
+ from .module1 import *
4
+ from .main import *
5
+ from .updatestatistics import upd
@@ -0,0 +1,152 @@
1
+ import argparse
2
+ import io
3
+ import json
4
+ import re
5
+ import sys
6
+ from datetime import datetime
7
+ from .updatestatistics import upd
8
+
9
+ def parseRec(rec, log_pattern):
10
+ print(str(rec))
11
+
12
+ r = {}
13
+ # skip comments recs
14
+ if rec[0:1] == '#':
15
+ return r
16
+
17
+ match = log_pattern.match(rec)
18
+ if match:
19
+ ip_address = match.group(1)
20
+ timestamp = match.group(2)
21
+ request = match.group(3)
22
+ status = match.group(4)
23
+ bytes_sent = match.group(5)
24
+ referer = match.group(6)
25
+ user_agent = match.group(7)
26
+
27
+ dto = datetime.strptime(timestamp,'%d/%b/%Y:%H:%M:%S %z') # 07/Jan/2024:14:06:24 +0000
28
+
29
+ r = {
30
+ 'ip': ip_address,
31
+ 'ymd': dto.strftime("%Y%m%d"),
32
+ 'timestamp': dto.strftime("%Y%m%d%H%M%S") ,
33
+ 'request': request,
34
+ 'status': status,
35
+ 'bytes_sent': bytes_sent,
36
+ 'referer': referer,
37
+ 'user_agent': user_agent
38
+ }
39
+
40
+ return r
41
+
42
+
43
+ # get date and time: 19/Apr/2024:14:49:22 +0000
44
+ dtcomp = re.compile('\d{2}[/][A-Za-z]{3}[/]\d{4}[:]\d{2}[:]\d{2}[:]\d{2}')
45
+ dt = dtcomp.search(rec) # scan for first match in rec
46
+ r['timestamp'] = datetime.strptime(dt[0],'%d/%b/%Y:%H:%M:%S')
47
+
48
+ # get ip address:
49
+ ip6 = '''(?:(?x)(?:(?:[0-9a-f]{1,4}:){1,1}(?::[0-9a-f]{1,4}){1,6})|
50
+ (?:(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5})|
51
+ (?:(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4})|
52
+ (?:(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3})|
53
+ (?:(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2})|
54
+ (?:(?:[0-9a-f]{1,4}:){1,6}(?::[0-9a-f]{1,4}){1,1})|
55
+ (?:(?:(?:[0-9a-f]{1,4}:){1,7}|:):)|
56
+ (?::(?::[0-9a-f]{1,4}){1,7})|
57
+ (?:(?:(?:(?:[0-9a-f]{1,4}:){6})(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}))|
58
+ (?:(?:(?:[0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}))|
59
+ (?:(?:[0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})|
60
+ (?:(?:[0-9a-f]{1,4}:){1,1}(?::[0-9a-f]{1,4}){1,4}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})|
61
+ (?:(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,3}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})|
62
+ (?:(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,2}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})|
63
+ (?:(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,1}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})|
64
+ (?:(?:(?:[0-9a-f]{1,4}:){1,5}|:):(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})|
65
+ (?::(?::[0-9a-f]{1,4}){1,5}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}))
66
+ '''
67
+ #ip4 = '(?:[12]?\\d?\\d\\.){3}[12]?\\d?\\d'
68
+ ip4 = '^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$'
69
+
70
+ ip = re.findall(ip4 + '|' + ip6, rec)
71
+ if not ip:
72
+ r['ip'] = ''
73
+ print("IP not detected in: " + rec)
74
+ else:
75
+ r['ip'] = ip[0]
76
+ return r
77
+
78
+
79
+ def detectDeviceClass(ua):
80
+ if ua is None:
81
+ return 'desktop'
82
+ if (ua.lower().find('bot') > 0):
83
+ return 'bots'
84
+ if (ua.lower().find('python') > 0):
85
+ return 'bots'
86
+ if (ua.lower().find('mediapartner') > 0):
87
+ return 'others'
88
+ if (ua.lower().find('curl') > 0):
89
+ return 'others'
90
+ if (ua.lower().find('ipad') > 0):
91
+ return 'tablet'
92
+ if (ua.lower().find('mobile') > 0):
93
+ return 'mobile'
94
+ if (ua.lower().find('android') > 0):
95
+ return 'tablet'
96
+ return 'desktop'
97
+
98
+ def runws():
99
+ parser = argparse.ArgumentParser(allow_abbrev=False)
100
+ parser.add_argument("-s", "--statfile", help="json file that contains calculated statistics", default="webstat.json")
101
+ parser.add_argument("-i", "--infile", help="filename including path to web server access log that contains input data", default="nginx_access.log")
102
+ args, unknown = parser.parse_known_args()
103
+
104
+ # init statistic file if it does not exist:
105
+ d = {}
106
+ d['timelastrec'] = '19991231235959'
107
+ d['days'] = {}
108
+
109
+ lasttimerecobj = datetime.strptime(d['timelastrec'],"%Y%m%d%H%M%S")
110
+ print("lasttimerecobj: " + str(lasttimerecobj))
111
+
112
+ # init job results
113
+ j = {
114
+ 'records_read_total': 0,
115
+ 'records_skipped_comment': 0,
116
+ 'records_already_processed': 0,
117
+ 'records_processed_for_statistic': 0,
118
+ }
119
+
120
+ # load statistic file if it exists
121
+ try:
122
+ f = open(args.statfile)
123
+ d = json.load(f)
124
+ except FileNotFoundError: # first call: file does not exists
125
+ print("-s statistic file not found, it will be automatically created")
126
+ except json.JSONDecodeError:
127
+ print("-s json file is not valid")
128
+
129
+ visitIP = {}
130
+
131
+ ip_pattern = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|[0-9a-fA-F:]+'
132
+ log_pattern = re.compile(r'({}) - - \[([^\]]+)\] "([^"]+)" (\d+) (\d+) "([^"]+)" "([^"]+)"'.format(ip_pattern))
133
+
134
+ # process infile:
135
+ with open(args.infile,'r') as infile:
136
+ for rec in infile:
137
+ recparsed = parseRec(rec, log_pattern)
138
+ # skip unrecognized records:
139
+ if not recparsed or recparsed['timestamp'] is None or recparsed['ip'] is None:
140
+ continue
141
+ # skip already processed data:
142
+ if recparsed['timestamp'] <= d['timelastrec']:
143
+ continue
144
+ d = upd(d, recparsed, visitIP)
145
+
146
+ # write updated statistic file:
147
+ with open(args.statfile, "w") as sf:
148
+ json.dump(d,sf)
149
+ return 0
150
+
151
+ if __name__ == "__main__":
152
+ runws()
@@ -0,0 +1,22 @@
1
+ # Example PyPI (Python Package Index) Package
2
+
3
+ class Number(object):
4
+
5
+ def __init__(self, n):
6
+ self.value = n
7
+
8
+ def val(self):
9
+ return self.value
10
+
11
+ def add(self, n2):
12
+ self.value += n2.val()
13
+
14
+ def __add__(self, n2):
15
+ return self.__class__(self.value + n2.val())
16
+
17
+ def __str__(self):
18
+ return str(self.val())
19
+
20
+ @classmethod
21
+ def addall(cls, number_obj_iter):
22
+ cls(sum(n.val() for n in number_obj_iter))
@@ -0,0 +1,31 @@
1
+ def upd(
2
+ d,
3
+ i,
4
+ visitIP):
5
+
6
+ dt = i['ymd']
7
+
8
+ # init a new day with minimal attributes:
9
+ if dt not in d['days']:
10
+ d['days'][dt] = {}
11
+ d['days'][dt]['hits'] = 0;
12
+ d['days'][dt]['visits'] = 0;
13
+ d['days'][dt]['bytes_sent'] = 0;
14
+ d['days'][dt]['serverResponseCode'] = {}
15
+
16
+ # update statistics
17
+ d['days'][dt]['hits'] = d['days'][dt]['hits'] + 1
18
+ d['days'][dt]['bytes_sent'] = str(int(d['days'][dt]['bytes_sent']) + int(i['bytes_sent']))
19
+
20
+ if i['status'] in d['days'][dt]['serverResponseCode']:
21
+ d['days'][dt]['serverResponseCode'][i['status']] += 1
22
+ else:
23
+ d['days'][dt]['serverResponseCode'][i['status']] = 1
24
+
25
+ d['timelastrec'] = i['timestamp']
26
+
27
+ if i['ip'] not in visitIP:
28
+ d['days'][dt]['visits'] = d['days'][dt]['visits'] + 1;
29
+ visitIP[i['ip']] = 1
30
+
31
+ return d
@@ -0,0 +1,298 @@
1
+ Metadata-Version: 2.1
2
+ Name: a9x_webstatistics
3
+ Version: 0.1.5
4
+ Summary: Web Statistics and Analytics Package
5
+ Home-page: https://github.com/ava007/a9x-webstatistics
6
+ Author: André von Arx
7
+ Author-email: andrevonarx@bluewin.ch
8
+ Project-URL: Documentation, https://github.com/ava007/a9x-webstatistics
9
+ Project-URL: Bug Reports, https://github.com/ava007/a9x-webstatistics/issues
10
+ Project-URL: Source Code, https://github.com/ava007/a9x-webstatistics
11
+ Keywords: webstats,statistics,analytics
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Topic :: Software Development :: Build Tools
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Operating System :: OS Independent
20
+ Requires-Python: >=3.7
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Provides-Extra: dev
24
+ Requires-Dist: check-manifest; extra == "dev"
25
+
26
+ # Web Statistics and Analytics
27
+
28
+ This package produces web statics and analytical output based on nginx access log files.
29
+
30
+ [![PyPI package](https://img.shields.io/badge/pip%20install-example--pypi--package-brightgreen)](https://pypi.org/project/a9x-webstatistics/) [![version number](https://img.shields.io/pypi/v/example-pypi-package?color=green&label=version)](https://github.com/ava007/a9x-webstatistics/releases) [![Actions Status](https://github.com/ava007/a9x-webstatistics/workflows/Test/badge.svg)](https://github.com/ava007/a9x-webstatistics/actions) [![License](https://img.shields.io/github/license/ava007/a9x-webstatistics)](https://github.com/ava007/a9x-webstatistics/blob/main/LICENSE)
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install a9x-webstatistics
36
+ ```
37
+
38
+
39
+ <details>
40
+ ----------------
41
+ ## old content from template starts here
42
+
43
+ [![PyPI package](https://img.shields.io/badge/pip%20install-example--pypi--package-brightgreen)](https://pypi.org/project/example-pypi-package/) [![version number](https://img.shields.io/pypi/v/example-pypi-package?color=green&label=version)](https://github.com/tomchen/example_pypi_package/releases) [![Actions Status](https://github.com/tomchen/example_pypi_package/workflows/Test/badge.svg)](https://github.com/tomchen/example_pypi_package/actions) [![License](https://img.shields.io/github/license/tomchen/example_pypi_package)](https://github.com/tomchen/example_pypi_package/blob/main/LICENSE)
44
+
45
+ This is an example [PyPI](https://pypi.org/) (Python Package Index) package set up with automated tests and package publishing workflow using GitHub Actions CI/CD. It is made primarily for GitHub + VS Code (Windows / Mac / Linux) users who are about to write and publish their first PyPI package. The package could serve as a starter / boilerplate / demo and the tutorial could give you a quick and concise explaination to solve some small but annoying problems you might encounter, such as package / module name confusion, and VS Code test configuration issues.
46
+ <summary><strong>Differences from pypa/sampleproject (click to show/hide)</strong></summary>
47
+
48
+ This example package is inspired by / based on the [official sample project pypa/sampleproject](https://github.com/pypa/sampleproject), but this package:
49
+
50
+ - is a simplified version of pypa/sampleproject (and the [official Python Packaging User Guide](https://packaging.python.org/))
51
+ - uses GitHub Actions for both testing and publishing, instead of Travis CI
52
+ - is tested when pushing `master` or `main` branch, and is published when create a release
53
+ - includes test files in the source distribution
54
+ - uses **setup.cfg** for [version single-sourcing](https://packaging.python.org/guides/single-sourcing-package-version/) (setuptools 46.4.0+)
55
+ - has **.vscode\settings.json** and **vscode.env** which adds **src/** folder to `PYTHONPATH`, so that test files don't have linting errors and may run with pytest in VS Code
56
+ - does not use flake8 for automated linting - it is sometimes too strict and inflexible, you may use pylint locally instead
57
+ - has this tutorial that covers everything you need to know in one page. Everything that might not be very useful, is hidden in collapsible sections that you can click to show
58
+ - has **[.editorconfig](https://editorconfig.org/#download)** file
59
+
60
+
61
+
62
+ ## Make necessary changes
63
+
64
+ ### Use as a template
65
+
66
+ [![Use the template](https://img.shields.io/static/v1?label=&message=Click%20here%20to%20use%20this%20package%20as%20a%20template%20to%20start%20a%20new%20repo%20on%20GitHub&color=brightgreen&style=for-the-badge)](https://github.com/tomchen/example_pypi_package/generate)
67
+
68
+ (Click the above button to use this example package as a template for your new GitHub repo, this will initialize a new repository and my commits will not be in your git history)
69
+
70
+ (If you do not use GitHub, you can [download the archive of the example package](https://github.com/tomchen/example_pypi_package/archive/main.zip))
71
+
72
+ ### Package, module name
73
+
74
+ Many use a same package and module name, you could definitely do that. But this example package and its module's names are different: `example_pypi_package` and `examplepy`.
75
+
76
+ Open `example_pypi_package` folder with Visual Studio Code, <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>F</kbd> (Windows / Linux) or <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>F</kbd> (MacOS) to find all occurrences of both names and replace them with your package and module's names. Also remember to change the name of the folder **src/examplepy**.
77
+
78
+ Simply and very roughly speaking, package name is used in `pip install <PACKAGENAME>` and module name is used in `import <MODULENAME>`. Both names should consist of lowercase basic letters (a-z). They may have underscores (`_`) if you really need them. Hyphen-minus (`-`) should not be used.
79
+
80
+ You'll also need to make sure the URL "https://pypi.org/project/example-pypi-package/" (replace `example-pypi-package` by your package name, with all `_` becoming `-`) is not occupied.
81
+
82
+ <details><summary><strong>Details on naming convention (click to show/hide)</strong></summary>
83
+
84
+ Underscores (`_`) can be used but such use is discouraged. Numbers can be used if the name does not start with a number, but such use is also discouraged.
85
+
86
+ Name starting with a number and/or containing hyphen-minus (`-`) should not be used: although technically legal, such name causes a lot of trouble − users have to use `importlib` to import it.
87
+
88
+ Don't be fooled by the URL "[pypi.org/project/example-pypi-package/](https://pypi.org/project/example-pypi-package/)" and the name "example-pypi-package" on pypi.org. pypi.org and pip system convert all `_` to `-` and use the latter on the website / in `pip` command, but the real name is still with `_`, which users should use when importing the package.
89
+
90
+ There's also [namespace](https://packaging.python.org/guides/packaging-namespace-packages/) to use if you need sub-packages.
91
+
92
+ </details>
93
+
94
+ ### Other changes
95
+
96
+ Make necessary changes in **setup.py**.
97
+
98
+ The package's version number `__version__` is in **src/examplepy/\_\_init\_\_.py**. You may want to change that.
99
+
100
+ The example package is designed to be compatible with Python 3.6, 3.7, 3.8, 3.9, and will be tested against these versions. If you need to change the version range, you should change:
101
+
102
+ - `classifiers`, `python_requires` in **setup.py**
103
+ - `envlist` in **tox.ini**
104
+ - `matrix: python:` in **.github/workflows/test.yml**
105
+
106
+ If you plan to upload to [TestPyPI](https://test.pypi.org/) which is a playground of [PyPI](https://pypi.org/) for testing purpose, change `twine upload --repository pypi dist/*` to `twine upload --repository testpypi dist/*` in the file **.github/workflows/release.yml**.
107
+
108
+ ## Development
109
+
110
+ ### pip
111
+
112
+ pip is a Python package manager. You already have pip if you use Python 3.4 and later version which include it by default. Read [this](https://pip.pypa.io/en/stable/installing/#do-i-need-to-install-pip) to know how to check whether pip is installed. Read [this](https://pip.pypa.io/en/stable/installing/#installing-with-get-pip-py) if you need to install it.
113
+
114
+ ### Use VS Code
115
+
116
+ Visual Studio Code is the most popular code editor today, our example package is configured to work with VS Code.
117
+
118
+ Install VS Code extension "[Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python)".
119
+
120
+ "Python" VS Code extension will suggest you install pylint. Also, the example package is configured to use pytest with VS Code + Python extensions, so, install pylint and pytest:
121
+
122
+ ```bash
123
+ pip install pylint pytest
124
+ ```
125
+
126
+ (It's likely you will be prompted to install them, if that's the case, you don't need to type and execute the command)
127
+
128
+ **vscode.env**'s content is now `PYTHONPATH=/;src/;${PYTHONPATH}` which is good for Windows. If you use Linux or MacOS, you need to change it to `PYTHONPATH=/:src/:${PYTHONPATH}` (replacing `;` with `:`). If the PATH is not properly set, you'll see linting errors in test files and pytest won't be able to run **tests/test\_\*.py** files correctly.
129
+
130
+ Close and reopen VS Code. You can now click the lab flask icon in the left menu and run all tests there, with pytest. pytest seems better than the standard unittest framework, it supports `unittest` thus you can keep using `import unittest` in your test files.
131
+
132
+ The example package also has a **.editorconfig** file. You may install VS Code extension "[EditorConfig for VS Code](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig)" that uses the file. With current configuration, the EditorConfig tool can automatically use spaces (4 spaces for .py, 2 for others) for indentation, set `UTF-8` encoding, `LF` end of lines, trim trailing whitespaces in non Markdown files, etc.
133
+
134
+ In VS Code, you can go to File -> Preferences -> Settings, type "Python Formatting Provider" in the search box, and choose one of the three Python code formatting tools (autopep8, black and yapf), you'll be prompted to install it. The shortcuts for formatting of a code file are <kbd>Shift</kbd> + <kbd>Alt</kbd> + <kbd>F</kbd> (Windows); <kbd>Shift</kbd> + <kbd>Option (Alt)</kbd> + <kbd>F</kbd> (MacOS); <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> (Linux).
135
+
136
+ ### Write your package
137
+
138
+ In **src/examplepy/** (`examplepy` should have been replaced by your module name) folder, rename **module1.py** and write your code in it. Add more module .py files if you need to.
139
+
140
+ ### Write your tests
141
+
142
+ In **tests/** folder, rename **test_module1.py** (to **test\_\*.py**) and write your unit test code (with [unittest](https://docs.python.org/3/library/unittest.html)) in it. Add more **test\_\*.py** files if you need to.
143
+
144
+ <details><summary><strong>The testing tool `tox` will be used in the automation with GitHub Actions CI/CD. If you want to use `tox` locally, click to read the "Use tox locally" section</strong></summary>
145
+
146
+ ### Use tox locally
147
+
148
+ Install tox and run it:
149
+
150
+ ```bash
151
+ pip install tox
152
+ tox
153
+ ```
154
+
155
+ In our configuration, tox runs a check of source distribution using [check-manifest](https://pypi.org/project/check-manifest/) (which requires your repo to be git-initialized (`git init`) and added (`git add .`) at least), setuptools's check, and unit tests using pytest. You don't need to install check-manifest and pytest though, tox will install them in a separate environment.
156
+
157
+ The automated tests are run against several Python versions, but on your machine, you might be using only one version of Python, if that is Python 3.9, then run:
158
+
159
+ ```bash
160
+ tox -e py39
161
+ ```
162
+
163
+ </details>
164
+
165
+ If you add more files to the root directory (**example_pypi_package/**), you'll need to add your file to `check-manifest --ignore` list in **tox.ini**.
166
+
167
+ <details><summary><strong>Thanks to GitHub Actions' automated process, you don't need to generate distribution files locally. But if you insist, click to read the "Generate distribution files" section</strong></summary>
168
+
169
+ ## Generate distribution files
170
+
171
+ ### Install tools
172
+
173
+ Install or upgrade `setuptools` and `wheel`:
174
+
175
+ ```bash
176
+ python -m pip install --user --upgrade setuptools wheel
177
+ ```
178
+
179
+ (If `python3` is the command on your machine, change `python` to `python3` in the above command, or add a line `alias python=python3` to **~/.bashrc** or **~/.bash_aliases** file if you use bash on Linux)
180
+
181
+ ### Generate `dist`
182
+
183
+ From `example_pypi_package` directory, run the following command, in order to generate production version for source distribution (sdist) in `dist` folder:
184
+
185
+ ```bash
186
+ python setup.py sdist bdist_wheel
187
+ ```
188
+
189
+ ### Install locally
190
+
191
+ Optionally, you can install dist version of your package locally before uploading to [PyPI](https://pypi.org/) or [TestPyPI](https://test.pypi.org/):
192
+
193
+ ```bash
194
+ pip install dist/example_pypi_package-0.1.0.tar.gz
195
+ ```
196
+
197
+ (You may need to uninstall existing package first:
198
+
199
+ ```bash
200
+ pip uninstall example_pypi_package
201
+ ```
202
+
203
+ There may be several installed packages with the same name, so run `pip uninstall` multiple times until it says no more package to remove.)
204
+
205
+ </details>
206
+
207
+ ## Upload to PyPI
208
+
209
+ ### Register on PyPI and get token
210
+
211
+ Register an account on [PyPI](https://pypi.org/), go to [Account settings § API tokens](https://pypi.org/manage/account/#api-tokens), "Add API token". The PyPI token only appears once, copy it somewhere. If you missed it, delete the old and add a new token.
212
+
213
+ (Register a [TestPyPI](https://test.pypi.org/) account if you are uploading to TestPyPI)
214
+
215
+ ### Set secret in GitHub repo
216
+
217
+ On the page of your newly created or existing GitHub repo, click **Settings** -> **Secrets** -> **New repository secret**, the **Name** should be `PYPI_API_TOKEN` and the **Value** should be your PyPI token (which starts with `pypi-`).
218
+
219
+ ### Push or release
220
+
221
+ The example package has automated tests and upload (publishing) already set up with GitHub Actions:
222
+
223
+ - Every time you `git push` or a pull request is submitted on your `master` or `main` branch, the package is automatically tested against the desired Python versions with GitHub Actions.
224
+ - Every time a new release (either the initial version or an updated version) is created, the latest version of the package is automatically uploaded to PyPI with GitHub Actions.
225
+
226
+ ### View it on pypi.org
227
+
228
+ After your package is published on PyPI, go to [https://pypi.org/project/example-pypi-package/](https://pypi.org/project/example-pypi-package/) (`_` becomes `-`). Copy the command on the page, execute it to download and install your package from PyPI. (or test.pypi.org if you use that)
229
+
230
+ If you want to modify the description / README of your package on pypi.org, you have to publish a new version.
231
+
232
+ <details><summary><strong>If you publish your package to PyPI manually, click to read</strong></summary>
233
+
234
+ ### Install Twine
235
+
236
+ Install or upgrade Twine:
237
+
238
+ ```bash
239
+ python -m pip install --user --upgrade twine
240
+ ```
241
+
242
+ Create a **.pypirc** file in your **$HOME** (**~**) directory, its content should be:
243
+
244
+ ```ini
245
+ [pypi]
246
+ username = __token__
247
+ password = <PyPI token>
248
+ ```
249
+
250
+ (Use `[testpypi]` instead of `[pypi]` if you are uploading to [TestPyPI](https://test.pypi.org/))
251
+
252
+ Replace `<PyPI token>` with your real PyPI token (which starts with `pypi-`).
253
+
254
+ (if you don't manually create **$HOME/.pypirc**, you will be prompted for a username (which should be `__token__`) and password (which should be your PyPI token) when you run Twine)
255
+
256
+ ### Upload
257
+
258
+ Run Twine to upload all of the archives under **dist** folder:
259
+
260
+ ```bash
261
+ python -m twine upload --repository pypi dist/*
262
+ ```
263
+
264
+ (use `testpypi` instead of `pypi` if you are uploading to [TestPyPI](https://test.pypi.org/))
265
+
266
+ ### Update
267
+
268
+ When you finished developing a newer version of your package, do the following things.
269
+
270
+ Modify the version number `__version__` in **src\examplepy\_\_init\_\_.py**.
271
+
272
+ Delete all old versions in **dist**.
273
+
274
+ Run the following command again to regenerate **dist**:
275
+
276
+ ```bash
277
+ python setup.py sdist bdist_wheel
278
+ ```
279
+
280
+ Run the following command again to upload **dist**:
281
+
282
+ ```bash
283
+ python -m twine upload --repository pypi dist/*
284
+ ```
285
+
286
+ (use `testpypi` instead of `pypi` if needed)
287
+
288
+ </details>
289
+
290
+ ## References
291
+
292
+ - [Python Packaging Authority (PyPA)'s sample project](https://github.com/pypa/sampleproject)
293
+ - [PyPA's Python Packaging User Guide](https://packaging.python.org/tutorials/packaging-projects/)
294
+ - [Stackoverflow questions and answers](https://stackoverflow.com/questions/41093648/how-to-test-that-pypi-install-will-work-before-pushing-to-pypi-python)
295
+ - [GitHub Actions Guides: Building and testing Python](https://docs.github.com/en/free-pro-team@latest/actions/guides/building-and-testing-python)
296
+
297
+
298
+ </details>
@@ -0,0 +1,19 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ dist_del
5
+ pyproject.toml
6
+ setup.cfg
7
+ setup.py
8
+ src/a9x_webstatistics/__init__.py
9
+ src/a9x_webstatistics/main.py
10
+ src/a9x_webstatistics/module1.py
11
+ src/a9x_webstatistics/updatestatistics.py
12
+ src/a9x_webstatistics.egg-info/PKG-INFO
13
+ src/a9x_webstatistics.egg-info/SOURCES.txt
14
+ src/a9x_webstatistics.egg-info/dependency_links.txt
15
+ src/a9x_webstatistics.egg-info/requires.txt
16
+ src/a9x_webstatistics.egg-info/top_level.txt
17
+ tests/test_main001.py
18
+ tests/test_main010.py
19
+ tests/test_module1.py
@@ -0,0 +1,3 @@
1
+
2
+ [dev]
3
+ check-manifest
@@ -0,0 +1 @@
1
+ a9x_webstatistics
@@ -0,0 +1,21 @@
1
+ import unittest
2
+ from pathlib import Path
3
+
4
+ from a9x_webstatistics.main import *
5
+ from a9x_webstatistics.updatestatistics import upd
6
+
7
+ class TestMain(unittest.TestCase):
8
+
9
+ def test_main(self):
10
+ print("home: " + str(Path.home()) )
11
+ # calling runws expecting return 0
12
+ assert runws() == 0
13
+ file = Path("webstat.json")
14
+ with open(file) as f:
15
+ file_data = f.read()
16
+ print(str(file_data))
17
+ contents = json.loads(file_data)
18
+ assert '20240130144922' in contents['timelastrec']
19
+
20
+ if __name__ == '__main__':
21
+ unittest.main()
@@ -0,0 +1,20 @@
1
+ import unittest
2
+ from pathlib import Path
3
+
4
+ from a9x_webstatistics.main import *
5
+ from a9x_webstatistics.updatestatistics import *
6
+
7
+ class TestMain010(unittest.TestCase):
8
+
9
+ def test_main010(self):
10
+ # calling runws expecting return 0
11
+ assert runws() == 0
12
+ file = Path("webstat.json")
13
+ with open(file) as f:
14
+ file_data = f.read()
15
+ print(str(file_data))
16
+ contents = json.loads(file_data)
17
+ assert '20240130144922' in contents['timelastrec']
18
+
19
+ if __name__ == '__main__':
20
+ unittest.main()
@@ -0,0 +1,13 @@
1
+ import unittest
2
+
3
+ from a9x_webstatistics.module1 import Number
4
+
5
+
6
+ class TestSimple(unittest.TestCase):
7
+
8
+ def test_add(self):
9
+ self.assertEqual((Number(7) + Number(6)).value, 13)
10
+
11
+
12
+ if __name__ == '__main__':
13
+ unittest.main()