agoras-common 2.0.0__py3-none-any.whl
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.
- agoras/__init__.py +3 -0
- agoras/common/__init__.py +45 -0
- agoras/common/logger.py +134 -0
- agoras/common/utils.py +96 -0
- agoras/common/version.py +36 -0
- agoras_common-2.0.0.dist-info/METADATA +79 -0
- agoras_common-2.0.0.dist-info/RECORD +9 -0
- agoras_common-2.0.0.dist-info/WHEEL +5 -0
- agoras_common-2.0.0.dist-info/top_level.txt +1 -0
agoras/__init__.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Please refer to AUTHORS.rst for a complete list of Copyright holders.
|
|
4
|
+
# Copyright (C) 2022-2026, Agoras Developers.
|
|
5
|
+
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU General Public License for more details.
|
|
15
|
+
|
|
16
|
+
# You should have received a copy of the GNU General Public License
|
|
17
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
"""
|
|
19
|
+
agoras.common
|
|
20
|
+
=============
|
|
21
|
+
|
|
22
|
+
Common utilities, logging, and shared constants for Agoras.
|
|
23
|
+
|
|
24
|
+
This package provides low-level utilities used throughout the Agoras ecosystem:
|
|
25
|
+
- Version and metadata information
|
|
26
|
+
- Logging infrastructure
|
|
27
|
+
- URL manipulation utilities
|
|
28
|
+
- Web scraping utilities
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from .logger import ControlableLogger, logger
|
|
32
|
+
from .utils import add_url_timestamp, parse_metatags
|
|
33
|
+
from .version import __author__, __description__, __email__, __url__, __version__
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
'__version__',
|
|
37
|
+
'__author__',
|
|
38
|
+
'__email__',
|
|
39
|
+
'__url__',
|
|
40
|
+
'__description__',
|
|
41
|
+
'logger',
|
|
42
|
+
'ControlableLogger',
|
|
43
|
+
'add_url_timestamp',
|
|
44
|
+
'parse_metatags',
|
|
45
|
+
]
|
agoras/common/logger.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Please refer to AUTHORS.rst for a complete list of Copyright holders.
|
|
4
|
+
# Copyright (C) 2022-2026, Agoras Developers.
|
|
5
|
+
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU General Public License for more details.
|
|
15
|
+
|
|
16
|
+
# You should have received a copy of the GNU General Public License
|
|
17
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
"""
|
|
19
|
+
``agoras.core.logger`` is the global application logging module.
|
|
20
|
+
|
|
21
|
+
All modules use the same global logging object. No messages will be emitted
|
|
22
|
+
until the logger is started.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import logging
|
|
26
|
+
import sys
|
|
27
|
+
from typing import cast
|
|
28
|
+
|
|
29
|
+
levelNames = {
|
|
30
|
+
'CRITICAL': 50,
|
|
31
|
+
'ERROR': 40,
|
|
32
|
+
'WARN': 30,
|
|
33
|
+
'WARNING': 30,
|
|
34
|
+
'INFO': 20,
|
|
35
|
+
'DEBUG': 10,
|
|
36
|
+
'NOTSET': 0,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ControlableLogger(logging.Logger):
|
|
41
|
+
"""
|
|
42
|
+
This class represents a logger object that can be started and stopped.
|
|
43
|
+
|
|
44
|
+
It has a start method which allows you to specify a logging level.
|
|
45
|
+
The stop method halts output.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(self, name=''):
|
|
49
|
+
"""
|
|
50
|
+
Initialize this ``ControlableLogger``.
|
|
51
|
+
|
|
52
|
+
The name defaults to the application name. Loggers with the same name
|
|
53
|
+
refer to the same underlying object. Names are hierarchical, e.g.
|
|
54
|
+
'parent.child' defines a logger that is a descendant of 'parent'.
|
|
55
|
+
|
|
56
|
+
:param name: a string containing the logger name.
|
|
57
|
+
:return: a ``ControlableLogger`` instance.
|
|
58
|
+
|
|
59
|
+
.. versionadded:: 0.1.0
|
|
60
|
+
"""
|
|
61
|
+
# Initializing parent class
|
|
62
|
+
super(ControlableLogger, self).__init__(name)
|
|
63
|
+
|
|
64
|
+
self.parent = logging.root
|
|
65
|
+
|
|
66
|
+
#: Attribute ``disabled`` (boolean): Stores the current status of the
|
|
67
|
+
#: logger.
|
|
68
|
+
self.disabled = True
|
|
69
|
+
self.propagate = False
|
|
70
|
+
|
|
71
|
+
#: Attribute ``formatstring`` (string): Stores the string that
|
|
72
|
+
#: will be used to format the logger output.
|
|
73
|
+
self.formatstring = '[%(levelname)s] %(message)s'
|
|
74
|
+
|
|
75
|
+
def start(self, filename=None):
|
|
76
|
+
"""
|
|
77
|
+
Start logging with this logger.
|
|
78
|
+
|
|
79
|
+
Until the logger is started, no messages will be emitted. This applies
|
|
80
|
+
to all loggers with the same name and any child loggers.
|
|
81
|
+
|
|
82
|
+
.. versionadded:: 0.1.0
|
|
83
|
+
"""
|
|
84
|
+
if self.disabled:
|
|
85
|
+
sh = logging.StreamHandler(sys.stdout)
|
|
86
|
+
sh.setFormatter(logging.Formatter(self.formatstring))
|
|
87
|
+
self.addHandler(sh)
|
|
88
|
+
if filename:
|
|
89
|
+
fh = logging.FileHandler(filename, mode='w')
|
|
90
|
+
fh.setFormatter(logging.Formatter(self.formatstring))
|
|
91
|
+
self.addHandler(fh)
|
|
92
|
+
self.disabled = False
|
|
93
|
+
|
|
94
|
+
def stop(self):
|
|
95
|
+
"""
|
|
96
|
+
Stop logging with this logger.
|
|
97
|
+
|
|
98
|
+
Remove available handlers and set disabled attribute to ``True``.
|
|
99
|
+
|
|
100
|
+
.. versionadded:: 0.1.0
|
|
101
|
+
"""
|
|
102
|
+
if not self.disabled:
|
|
103
|
+
for h in list(self.handlers):
|
|
104
|
+
self.removeHandler(h)
|
|
105
|
+
self.disabled = True
|
|
106
|
+
|
|
107
|
+
def loglevel(self, level='INFO'):
|
|
108
|
+
"""
|
|
109
|
+
Set the log level for this logger.
|
|
110
|
+
|
|
111
|
+
Messages less than the given priority level will be ignored. The
|
|
112
|
+
default level is 'INFO', which conforms to the *nix convention that
|
|
113
|
+
a successful run should produce no diagnostic output. Available levels
|
|
114
|
+
and their suggested meanings:
|
|
115
|
+
|
|
116
|
+
* ``NOTSET``: all messages are processed.
|
|
117
|
+
* ``DEBUG``: output useful for developers.
|
|
118
|
+
* ``INFO``: trace normal program flow, especially external
|
|
119
|
+
interactions.
|
|
120
|
+
* ``WARNING``: an abnormal condition was detected that might need
|
|
121
|
+
attention.
|
|
122
|
+
* ``ERROR``: an error was detected but execution continued.
|
|
123
|
+
* ``CRITICAL``: an error was detected and execution was halted.
|
|
124
|
+
|
|
125
|
+
:param level: a string containing the desired logging level.
|
|
126
|
+
|
|
127
|
+
.. versionadded:: 0.1.0
|
|
128
|
+
"""
|
|
129
|
+
if not self.disabled:
|
|
130
|
+
self.setLevel(levelNames[level])
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
logging.setLoggerClass(ControlableLogger)
|
|
134
|
+
logger = cast(ControlableLogger, logging.getLogger(__name__.split('.')[0]))
|
agoras/common/utils.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Please refer to AUTHORS.rst for a complete list of Copyright holders.
|
|
4
|
+
# Copyright (C) 2022-2026, Agoras Developers.
|
|
5
|
+
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU General Public License for more details.
|
|
15
|
+
|
|
16
|
+
# You should have received a copy of the GNU General Public License
|
|
17
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
agoras.common.utils
|
|
22
|
+
===================
|
|
23
|
+
|
|
24
|
+
This module contains common and low level functions to all modules in agoras.
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
from urllib.parse import parse_qs, urlencode, urlparse
|
|
30
|
+
|
|
31
|
+
import requests
|
|
32
|
+
from bs4 import BeautifulSoup
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def add_url_timestamp(url, timestamp):
|
|
36
|
+
parsed = urlparse(url)
|
|
37
|
+
query = dict(parse_qs(str(parsed.query)))
|
|
38
|
+
query['t'] = timestamp
|
|
39
|
+
parsed = parsed._replace(query=urlencode(query))
|
|
40
|
+
return parsed.geturl()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def metatag(tag):
|
|
44
|
+
return tag.name == "meta" \
|
|
45
|
+
and tag.has_attr("content") \
|
|
46
|
+
and (tag.has_attr("property") or tag.has_attr("name"))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def find_metatags(url, search):
|
|
50
|
+
found = {}
|
|
51
|
+
|
|
52
|
+
response = requests.get(url, timeout=20)
|
|
53
|
+
|
|
54
|
+
if response.status_code != 200:
|
|
55
|
+
return found
|
|
56
|
+
|
|
57
|
+
soup = BeautifulSoup(response.content, 'html.parser')
|
|
58
|
+
|
|
59
|
+
for target in search:
|
|
60
|
+
found_meta_tag = soup.find_all(metatag)
|
|
61
|
+
|
|
62
|
+
if not found_meta_tag:
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
for meta_tag in found_meta_tag:
|
|
66
|
+
|
|
67
|
+
prop = meta_tag.get("property", "")
|
|
68
|
+
name = meta_tag.get("name", "")
|
|
69
|
+
|
|
70
|
+
if prop == target or name == target:
|
|
71
|
+
found[target] = meta_tag.get("content", "")
|
|
72
|
+
|
|
73
|
+
return found
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def parse_metatags(url):
|
|
77
|
+
|
|
78
|
+
KNOWN_TAGS = [
|
|
79
|
+
"og:title",
|
|
80
|
+
"og:image",
|
|
81
|
+
"og:description",
|
|
82
|
+
"twitter:title",
|
|
83
|
+
"twitter:image",
|
|
84
|
+
"twitter:description",
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
data = find_metatags(url, KNOWN_TAGS)
|
|
89
|
+
except Exception:
|
|
90
|
+
data = {}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
"title": data.get("og:title", data.get("twitter:title", "")),
|
|
94
|
+
"image": data.get("og:image", data.get("twitter:image", "")),
|
|
95
|
+
"description": data.get("og:description", data.get("twitter:description", "")),
|
|
96
|
+
}
|
agoras/common/version.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Please refer to AUTHORS.rst for a complete list of Copyright holders.
|
|
4
|
+
# Copyright (C) 2022-2026, Agoras Developers.
|
|
5
|
+
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU General Public License for more details.
|
|
15
|
+
|
|
16
|
+
# You should have received a copy of the GNU General Public License
|
|
17
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
"""
|
|
19
|
+
agoras.common.version
|
|
20
|
+
=====================
|
|
21
|
+
|
|
22
|
+
Version and metadata information for Agoras.
|
|
23
|
+
|
|
24
|
+
This module serves as the single source of truth for version info
|
|
25
|
+
across all Agoras packages.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
__author__ = 'Luis Alejandro Martínez Faneyth'
|
|
29
|
+
__email__ = 'luis@luisalejandro.org'
|
|
30
|
+
__version__ = '2.0.0'
|
|
31
|
+
__url__ = 'https://github.com/LuisAlejandro/agoras'
|
|
32
|
+
__description__ = (
|
|
33
|
+
'A command line python utility to manage your social'
|
|
34
|
+
' networks (Twitter, Facebook, Instagram, LinkedIn, Discord, '
|
|
35
|
+
'YouTube, TikTok, Telegram, Threads, WhatsApp, and X)'
|
|
36
|
+
)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agoras-common
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Common utilities and logging for Agoras
|
|
5
|
+
Home-page: https://github.com/LuisAlejandro/agoras
|
|
6
|
+
Author: Luis Alejandro Martínez Faneyth
|
|
7
|
+
Author-email: luis@luisalejandro.org
|
|
8
|
+
Keywords: utilities,logging,social networks
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
12
|
+
Classifier: Natural Language :: English
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/x-rst
|
|
21
|
+
Requires-Dist: requests==2.33.1
|
|
22
|
+
Requires-Dist: beautifulsoup4==4.14.3
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: author-email
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: keywords
|
|
30
|
+
Dynamic: requires-dist
|
|
31
|
+
Dynamic: requires-python
|
|
32
|
+
Dynamic: summary
|
|
33
|
+
|
|
34
|
+
agoras-common
|
|
35
|
+
=============
|
|
36
|
+
|
|
37
|
+
Low-level utilities, logging, and shared constants for the Agoras ecosystem.
|
|
38
|
+
|
|
39
|
+
Installation
|
|
40
|
+
------------
|
|
41
|
+
|
|
42
|
+
.. code-block:: bash
|
|
43
|
+
|
|
44
|
+
pip install agoras-common
|
|
45
|
+
|
|
46
|
+
Contents
|
|
47
|
+
--------
|
|
48
|
+
|
|
49
|
+
- **Version Info**: ``__version__``, ``__author__``, ``__email__``, ``__url__``, ``__description__``
|
|
50
|
+
- **Utilities**: Helper functions for URL manipulation, metadata parsing
|
|
51
|
+
- **Logger**: Centralized logging configuration
|
|
52
|
+
|
|
53
|
+
Usage
|
|
54
|
+
-----
|
|
55
|
+
|
|
56
|
+
.. code-block:: python
|
|
57
|
+
|
|
58
|
+
from agoras.common import __version__, logger, add_url_timestamp, parse_metatags
|
|
59
|
+
|
|
60
|
+
# Version info
|
|
61
|
+
print(f"Agoras version: {__version__}")
|
|
62
|
+
|
|
63
|
+
# Logger
|
|
64
|
+
logger.start()
|
|
65
|
+
logger.loglevel('INFO')
|
|
66
|
+
logger.info("Hello from Agoras!")
|
|
67
|
+
|
|
68
|
+
# URL utilities
|
|
69
|
+
timestamped_url = add_url_timestamp('https://example.com', '20260110')
|
|
70
|
+
print(timestamped_url) # https://example.com?t=20260110
|
|
71
|
+
|
|
72
|
+
# Metatag parsing
|
|
73
|
+
metatags = parse_metatags('https://example.com')
|
|
74
|
+
print(metatags['title'], metatags['image'])
|
|
75
|
+
|
|
76
|
+
Dependencies
|
|
77
|
+
------------
|
|
78
|
+
|
|
79
|
+
None (pure Python utilities)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
agoras/__init__.py,sha256=BizfjbmRwkeL71J-UJWv3xvnQ0jUnmi2sSDBeere0JM,120
|
|
2
|
+
agoras/common/__init__.py,sha256=DwQEiKi8V0UWdQOQxEtIAke25pwvwsy8smoFeG_uSwg,1445
|
|
3
|
+
agoras/common/logger.py,sha256=OlHM1TPQ9-eN5P5DevhjHKiiIcEbrdsoUYqmjCrMtlA,4467
|
|
4
|
+
agoras/common/utils.py,sha256=Pk2Pb4mUh5PyOLw7szh89dU5FWch7-6fnaC7uCg5lBE,2532
|
|
5
|
+
agoras/common/version.py,sha256=SmMFDcfHAKf5Dz_vDKrKh3zcgv92x6_rPrnefRbBe08,1337
|
|
6
|
+
agoras_common-2.0.0.dist-info/METADATA,sha256=cTNh8SDaH3YlxUaHa-4Y_Xg_O154_G6TAffGUl7zxgs,2184
|
|
7
|
+
agoras_common-2.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
8
|
+
agoras_common-2.0.0.dist-info/top_level.txt,sha256=lpSbQnkePldQbtolks5qCcv_l_n22drGde6Jt-6ES_0,7
|
|
9
|
+
agoras_common-2.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
agoras
|