├── .gitattributes
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.yaml
│ └── config.yml
└── workflows
│ ├── add-stars.yml
│ └── build.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── benchmark.py
├── docs
├── index.html
└── nimdoc.out.css
├── examples
├── .env
├── example_chmod.py
├── example_cwd.py
├── example_dotenv.py
├── example_expanduser.py
├── example_get_exe.py
├── example_get_file_info.py
├── example_get_file_times.py
├── example_get_size.py
├── example_home.py
├── example_is_file.py
├── example_is_valid_path.py
├── example_joinpath.py
├── example_lines.py
├── example_mkdir.py
├── example_path_splitted.py
├── example_replaced.py
├── example_resolve.py
├── example_rmdir.py
├── example_tokenized.py
├── example_walk.py
├── example_walk_glob.py
├── example_with_name.py
├── example_with_stem.py
└── example_with_suffix.py
├── package4pypi.sh
├── results_graph.png
├── run-benchmark.sh
├── setup.py
├── thatlib-logo.jpg
├── thatlib
├── thatlib.nim
├── thatlib.nim.cfg
├── thatlib.nimble
└── thatlib.py
└── upload2pypi.sh
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.* linguist-language=Python
2 | * linguist-language=Python
3 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom: ["https://gist.github.com/juancarlospaco/37da34ed13a609663f55f4466c4dbc3e"]
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yaml:
--------------------------------------------------------------------------------
1 | name: "BUG Report"
2 | description: "Create a new Bug report."
3 | title: "[bug] "
4 | labels: ["unconfirmed"]
5 | assignees: ["juancarlospaco"]
6 | body:
7 |
8 | - type: markdown
9 | attributes:
10 | value: |
11 | - **Remember to :star: Star the project on GitHub!.**
12 | - **Please provide a minimal code example that reproduces the :bug: Bug!.**
13 | Reports with full repro code and descriptive detailed information will be fixed faster.
14 | - [Please, keep in mind there is ZERO FUNDING for the project!, we have no sponsors, no company behind, no dev team,
15 | :heart: Send crypto today to speed up development!](https://gist.github.com/juancarlospaco/37da34ed13a609663f55f4466c4dbc3e)
16 |
17 | - type: dropdown
18 | id: architecture
19 | attributes:
20 | label: Architecture
21 | description: What is your Hardware Architecture?.
22 | options:
23 | - x86_64 (Default)
24 | - x86_32 (32Bit)
25 | - ARM_64 (64Bit)
26 | - ARM_32 (32Bit)
27 | - AVR (Arduino, ESP32)
28 | - RISC (RISC-V)
29 | - Others (Unkown)
30 | validations:
31 | required: true
32 |
33 | - type: dropdown
34 | id: os
35 | attributes:
36 | label: Operating System
37 | description: What is your Operating System?.
38 | options:
39 | - Linux
40 | - Windows
41 | - Mac OSX
42 | - Android
43 | - BSD
44 | - FreeDOS
45 | - ReactOS
46 | - Others (Unkown)
47 | validations:
48 | required: true
49 |
50 | - type: dropdown
51 | id: disk
52 | attributes:
53 | label: Disk
54 | description: What is your main Disk Storage?.
55 | options:
56 | - SSD (Solid)
57 | - HDD (SATA, IDE, Mechanical)
58 | - NVME (M2, MSATA)
59 | - Others (USB)
60 | validations:
61 | required: true
62 |
63 | - type: dropdown
64 | id: ram
65 | attributes:
66 | label: Memory
67 | description: What is your total RAM Memory capacity?.
68 | options:
69 | - 1 Gigabytes
70 | - 2 Gigabytes
71 | - 4 Gigabytes
72 | - 8 Gigabytes
73 | - 16 Gigabytes
74 | - 32 Gigabytes
75 | - 64 Gigabytes
76 | - 128 Gigabytes
77 | - 256 Gigabytes
78 | - 512 Gigabytes
79 | - Others (Unkown)
80 | validations:
81 | required: true
82 |
83 | - type: dropdown
84 | id: cores
85 | attributes:
86 | label: CPU Cores
87 | description: What is your total CPU Cores count?.
88 | options:
89 | - 1 CPU Cores
90 | - 2 CPU Cores
91 | - 4 CPU Cores
92 | - 8 CPU Cores
93 | - 16 CPU Cores
94 | - 32 CPU Cores
95 | - 64 CPU Cores
96 | - 128 CPU Cores
97 | - 256 CPU Cores
98 | - 512 CPU Cores
99 | - Others (Unkown)
100 | validations:
101 | required: true
102 |
103 | - type: dropdown
104 | id: internet
105 | attributes:
106 | label: Internet Connection
107 | description: What is your Internet connection?.
108 | options:
109 | - Optical Fiber (very fast)
110 | - DSL (aDSL, DSL, etc)
111 | - Wifi (WLAN, Wireless)
112 | - LAN (RJ45, Local, etc)
113 | - Satellite (StarLink, etc)
114 | - Mobile (4G, 3G, Edge, etc)
115 | - Offline (No Internet)
116 | - Others (Unkown)
117 | validations:
118 | required: true
119 |
120 | - type: dropdown
121 | id: browser
122 | attributes:
123 | label: What is your web browser?
124 | options:
125 | - Chrome/Chromium
126 | - Firefox/Firefox Fork
127 | - Apple Safari
128 | - Microsoft Edge
129 | - KDE (Konqueror, Falkon, etc)
130 | - Others (Unkown)
131 | validations:
132 | required: true
133 |
134 | - type: dropdown
135 | id: device
136 | attributes:
137 | label: Device
138 | description: What kind of computer is it?.
139 | options:
140 | - Desktop PC
141 | - Server PC
142 | - Docker/Qemu (Container)
143 | - VirtualBox/Vagrant (Virtual Machine)
144 | - Embedded/IOT
145 | - Arduino/ESP32 Kit
146 | - SmartTV/SmartDisplay
147 | - Drone/Robot
148 | - ASIC/FPGA/Crypto-mining hardware
149 | - PLC/Industrial/heavy machine
150 | - Point Of Sale/Kiosk/ATM
151 | - Car/Self-Driving/On-Board Computer
152 | - Electric scooter/Electric bike
153 | - Satellite/MicroSatellite
154 | - Military machine
155 | - Others (Unkown)
156 | validations:
157 | required: true
158 |
159 | - type: dropdown
160 | id: country
161 | attributes:
162 | label: Where are you from?
163 | options:
164 | - Afghanistan
165 | - Albania
166 | - Algeria
167 | - Andorra
168 | - Angola
169 | - Antigua
170 | - Argentina
171 | - Armenia
172 | - Australia
173 | - Austria
174 | - Azerbaijan
175 | - Bahamas
176 | - Bahrain
177 | - Bangladesh
178 | - Barbados
179 | - Belarus
180 | - Belgium
181 | - Belize
182 | - Benin
183 | - Bhutan
184 | - Bolivia
185 | - Bosnia Herzegovina
186 | - Botswana
187 | - Brazil
188 | - Brunei
189 | - Bulgaria
190 | - Burkina
191 | - Burundi
192 | - Cambodia
193 | - Cameroon
194 | - Canada
195 | - Cape Verde
196 | - Central African Republic
197 | - Chad
198 | - Chile
199 | - China
200 | - Colombia
201 | - Comoros
202 | - Congo
203 | - Congo Democratic Republic
204 | - Costa Rica
205 | - Croatia
206 | - Cuba
207 | - Curacao
208 | - Cyprus
209 | - Czech Republic
210 | - Denmark
211 | - Djibouti
212 | - Dominica
213 | - Dominican Republic
214 | - East Timor
215 | - Ecuador
216 | - Egypt
217 | - El Salvador
218 | - Equatorial Guinea
219 | - Eritrea
220 | - Estonia
221 | - Ethiopia
222 | - Fiji
223 | - Finland
224 | - France
225 | - Gabon
226 | - Gambia
227 | - Georgia
228 | - Germany
229 | - Ghana
230 | - Greece
231 | - Grenada
232 | - Guatemala
233 | - Guinea
234 | - Guinea-Bissau
235 | - Guyana
236 | - Haiti
237 | - Honduras
238 | - Hungary
239 | - Iceland
240 | - India
241 | - Indonesia
242 | - Iran
243 | - Iraq
244 | - Ireland
245 | - Israel
246 | - Italy
247 | - Ivory Coast
248 | - Jamaica
249 | - Japan
250 | - Jordan
251 | - Kazakhstan
252 | - Kenya
253 | - Kiribati
254 | - Korea North
255 | - Korea South
256 | - Kosovo
257 | - Kuwait
258 | - Kyrgyzstan
259 | - Laos
260 | - Latvia
261 | - Lebanon
262 | - Lesotho
263 | - Liberia
264 | - Libya
265 | - Liechtenstein
266 | - Lithuania
267 | - Luxembourg
268 | - Macedonia
269 | - Madagascar
270 | - Malawi
271 | - Malaysia
272 | - Maldives
273 | - Mali
274 | - Malvinas Argentinas Islands
275 | - Malta
276 | - Marshall Islands
277 | - Mauritania
278 | - Mauritius
279 | - Mexico
280 | - Micronesia
281 | - Moldova
282 | - Monaco
283 | - Mongolia
284 | - Montenegro
285 | - Morocco
286 | - Mozambique
287 | - Myanmar
288 | - Namibia
289 | - Nauru
290 | - Nepal
291 | - Netherlands
292 | - New Zealand
293 | - Nicaragua
294 | - Niger
295 | - Nigeria
296 | - Norway
297 | - Oman
298 | - Pakistan
299 | - Palau
300 | - Palestine
301 | - Panama
302 | - Papua New Guinea
303 | - Paraguay
304 | - Peru
305 | - Philippines
306 | - Poland
307 | - Portugal
308 | - Qatar
309 | - Romania
310 | - Russia
311 | - Rwanda
312 | - St Kitts
313 | - St Lucia
314 | - Saint Vincent
315 | - Samoa
316 | - San Marino
317 | - Sao Tome Principe
318 | - Saudi Arabia
319 | - Senegal
320 | - Scotland
321 | - Serbia
322 | - Seychelles
323 | - Sierra Leone
324 | - Singapore
325 | - Slovakia
326 | - Slovenia
327 | - Solomon Islands
328 | - Somalia
329 | - South Africa
330 | - South Sudan
331 | - Spain
332 | - Sri Lanka
333 | - Sudan
334 | - Suriname
335 | - Swaziland
336 | - Sweden
337 | - Switzerland
338 | - Syria
339 | - Taiwan
340 | - Tajikistan
341 | - Tanzania
342 | - Thailand
343 | - Togo
344 | - Tonga
345 | - Trinidad Tobago
346 | - Tunisia
347 | - Turkey
348 | - Turkmenistan
349 | - Tuvalu
350 | - Uganda
351 | - Ukraine
352 | - United Arab Emirates
353 | - United Kingdom
354 | - United States
355 | - Uruguay
356 | - Uzbekistan
357 | - Vanuatu
358 | - Vatican City
359 | - Venezuela
360 | - Vietnam
361 | - Yemen
362 | - Zambia
363 | - Zimbabwe
364 | validations:
365 | required: true
366 |
367 | - type: textarea
368 | id: what-happened
369 | attributes:
370 | label: What happened?
371 | description: Use DETAILED DESCRIPTIVE information about the problem
372 | placeholder: Bug reports with full repro code and detailed information will be fixed faster.
373 | validations:
374 | required: true
375 |
376 | - type: textarea
377 | id: logs
378 | attributes:
379 | label: Standard Output Logs
380 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
381 | placeholder: Bug reports with full repro code and detailed information will be fixed faster.
382 | render: shell
383 |
384 | - type: markdown
385 | attributes:
386 | value: |
387 | **Before you open a new bug...**
388 | - 32-Bit is NOT supported.
389 | - Windows older than Windows 10 is NOT supported.
390 | - Mac OSX support is Experimental.
391 | - ARM support is Experimental.
392 | - Alpine Linux support is Experimental.
393 | - Termux support is Experimental.
394 | - Check if Git main branch already have a fix for your problem.
395 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | contact_links:
2 | - name: Sponsor this Project
3 | url: https://gist.github.com/juancarlospaco/37da34ed13a609663f55f4466c4dbc3e
4 | about: Toss a coin to your witcher...
5 |
--------------------------------------------------------------------------------
/.github/workflows/add-stars.yml:
--------------------------------------------------------------------------------
1 | name: Add Stars
2 |
3 | on: [watch]
4 |
5 | jobs:
6 | addstars:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v1
10 | - name: Add Stars to Readme
11 | run: |
12 | echo -e ":star: [@${{github.actor}}](https://github.com/${{github.actor}} '`date --iso-8601`')\t" >> README.md
13 |
14 | - name: Commit changes
15 | uses: elstudio/actions-js-build/commit@v2
16 | env:
17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
18 | PUSH_BRANCH: 'nim'
19 |
20 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 | on:
3 | push:
4 | paths:
5 | - 'setup.py'
6 | - 'setup.cfg'
7 | - 'PKG-INFO'
8 | - 'thatlib/*.*'
9 | - '.github/workflows/*.yml'
10 | - '.github/workflows/*.yaml'
11 | - '.gitignore'
12 |
13 | jobs:
14 | build:
15 | if: "!contains(github.event.head_commit.message, '[skip ci]')"
16 | strategy:
17 | fail-fast: true
18 | matrix:
19 | platform: [ubuntu-latest, windows-latest] # Mac too slow in CI.
20 | name: ${{ matrix.platform }}
21 | runs-on: ${{ matrix.platform }}
22 | steps:
23 | - uses: actions/checkout@v2
24 | - uses: actions/setup-python@v2
25 | with:
26 | python-version: '3.9'
27 |
28 | - uses: jiro4989/setup-nim-action@v1
29 | with:
30 | nim-version: '1.4.8'
31 | no-color: true # --noColor
32 |
33 | - name: Set Environment Variables
34 | uses: allenevans/set-env@v2.0.0
35 | with:
36 | NIMPORTER_INSTRUMENT: true
37 | PACKAGE_NAME: "thatlib"
38 | MAIN_MODULE: "thatlib/thatlib.nim"
39 | ACTIONS_ALLOW_UNSECURE_COMMANDS: true
40 |
41 |
42 | - name: Nimble
43 | run: |
44 | nimble -y refresh
45 | nimble -y install nimpy
46 |
47 |
48 | - uses: juancarlospaco/nimpretty-action@main
49 | with:
50 | folders: "thatlib"
51 |
52 |
53 | - name: Generate Documentation (Linux)
54 | if: runner.os == 'Linux'
55 | run: nim doc --out:docs/index.html ${{ env.MAIN_MODULE }}
56 |
57 |
58 | - name: Compile (Unix)
59 | if: runner.os == 'Linux' || runner.os == 'macOS'
60 | run: nim c --app:lib --gc:arc --experimental:strictFuncs --out:$PACKAGE_NAME.so $MAIN_MODULE
61 |
62 |
63 | - name: Compile (Windows)
64 | if: runner.os == 'Windows'
65 | run: nim c --app:lib --gc:arc --experimental:strictFuncs --out:${{ env.PACKAGE_NAME }}.pyd ${{ env.MAIN_MODULE }}
66 |
67 |
68 | - name: Install Nimporter
69 | shell: bash
70 | run: |
71 | git clone https://github.com/Pebaz/nimporter.git
72 | cd nimporter/
73 | git checkout nimporter-v2.0.0rc
74 | python setup.py install
75 | cd ..
76 | rm --force --recursive nimporter/
77 |
78 |
79 | - name: Install Thatlib
80 | run: |
81 | python setup.py install
82 |
83 |
84 | - name: Import Thatlib
85 | run: |
86 | python -c "import thatlib ; print(thatlib.cwd())"
87 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | nimcache/
2 | nimblecache/
3 | htmldocs/
4 | *.dll
5 | *.so
6 | *.pyd
7 | __pycache__/
8 | *.pyc
9 | *.c.o
10 | dist/*.zip
11 | thatlib/*.so
12 | results.csv
13 | thatlib/benchmark.py
14 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team.
59 | All complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
2 | # Welcome Contributors
3 |
4 | When contributing, please first discuss the change you wish to make via issue, before making the actual change.
5 |
6 | We want to make contributing to this project as easy and transparent as possible.
7 |
8 | Please note we have a Code Of Conduct, please follow it in all your interactions with the project.
9 |
10 |
11 | # FAQ
12 |
13 | Whats Nim?
14 |
15 | - Its just like Cython, but faster and more elegant syntax, we can say Nim is more Pythonic than Cython,
16 | is a proper programming language instead of an experimental pseudo-lang alternative syntax, it also runs on the Browser Frontend.
17 |
18 |
19 | # Development Process
20 |
21 | [We use Github Flow](https://guides.github.com/introduction/flow/index.html), so all code changes happen via Pull Requests:
22 |
23 | 1. Fork the repo from latest working `master` and create a new branch.
24 | 2. Change the code on the new branch, update the documentation, test it locally.
25 | 3. Send a new Pull Request!, follow the Feedback from the Peer Reviews so it gets Merged faster.
26 |
27 |
28 | # How to Contribute if you cant code
29 |
30 | - [Make Nim Fan Art and Memes](https://t.me/addstickers/nimlang).
31 | - Give a Talk about Nim-based Python libs at your local meetup.
32 | - Talk about Nim-based Python libs on your social networks.
33 | - [Writing tutorials and blog posts](https://dev.to/juancarlospaco/self-firejailing-web-framework-h5l).
34 | - Improving documentations.
35 | - UX and Design improvements.
36 | - Make Benchmarks of Nim-based libs Vs other frameworks.
37 | - Mention Nim-based Python libs on discussions about Python.
38 | - Submitting bugs and feature requests.
39 |
40 | Are all examples of very helpful contributions!.
41 |
42 |
43 | # Style Guide
44 |
45 | - Follow [NEP1](https://nim-lang.org/docs/nep1.html).
46 | - Keep API human-friendly, but at the same time use performant algos, thats the Nim way.
47 | - Try to use naming that makes sense :)
48 |
49 |
50 | # Your Responsibilities
51 |
52 | - Write detailed bug reports with sample code.
53 | - Write meaningful human-friendly Commit Messages.
54 | - Ensure Linux platform and Latest Stable Nim compatibility.
55 | - Discuss things transparently and get community feedback.
56 | - Do not add any Types to the codebase unless absolutely needed.
57 | - Prefer standard library as much as possible instead of third party modules.
58 | - Document how to use the new features and pros/cons if any.
59 | - Be welcoming to newcomers and encourage diverse new contributors from all backgrounds.
60 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Juan Carlos
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ThatLib
2 |
3 | 
4 |
5 | [](https://youtu.be/QiKwnlyhKrk?t=5)
6 |
7 | 
8 | 
9 | 
10 | 
11 | 
12 | 
13 | 
14 |
15 |
16 | # Using Pathlib can make your project +50x Slower
17 |
18 | [](https://www.youtube.com/watch?v=tFrh9hKMS6Y)
19 |
20 |
21 | # Use
22 |
23 | - Same API as `pathlib`, nothing new to remember.
24 | - [See the examples folder (20+ simple tiny examples).](https://github.com/juancarlospaco/thatlib/tree/nim/examples)
25 | - https://juancarlospaco.github.io/thatlib
26 |
27 |
28 | # Type-safe DotEnv
29 |
30 | Thatlib has builtin support for Type-safe `.env`. Type-safe `.env` file is just a `.env` but Typed.
31 |
32 | Types are enforced via a comment, so it is still a "vanilla" `.env`.
33 |
34 | Type-safe `.env` file can be used with unsafe `.env` parsers, legacy parsers will ignore the comment.
35 |
36 | Keys must be a non-empty ASCII string `[a-zA-Z0-9_]`, keys are validated. Key-Value separator must be `=`.
37 |
38 | Parses the same `.env` file from the vanilla implementation tests.
39 |
40 | Several orders of magnitude faster than the vanilla implementation. Implementation is ~ 50 lines of code.
41 |
42 | Examples:
43 |
44 | ```ini
45 | # This is a comment
46 | DB_HOST=localhost # string
47 | DB_USER=root # string
48 | DB_PASS="123" # string
49 | DB_TIMEOUT=42 # int
50 | DELAY=3.14 # float
51 | ACTIVE=true # bool
52 | ```
53 |
54 | - `.env` file example https://github.com/juancarlospaco/thatlib/blob/nim/examples/.env
55 | - Python use example https://github.com/juancarlospaco/thatlib/blob/nim/examples/example_dotenv.py
56 |
57 |
58 | # Requisites
59 |
60 | - Python 1.x or 2.x or 3.x, 64Bit, CPython implementation.
61 |
62 |
63 | # PYPI
64 |
65 | - https://pypi.org/project/thatlib
66 |
67 |
68 | # Dependencies
69 |
70 | - None.
71 |
72 |
73 | # 💰➡️🍕
74 |
75 |
76 | Bitcoin BTC
77 |
78 | **BEP20 Binance Smart Chain Network BSC**
79 | ```
80 | 0xb78c4cf63274bb22f83481986157d234105ac17e
81 | ```
82 | **BTC Bitcoin Network**
83 | ```
84 | 1Pnf45MgGgY32X4KDNJbutnpx96E4FxqVi
85 | ```
86 | **Lightning Network**
87 | ```
88 | juancarlospaco@bitrefill.me
89 | ```
90 |
91 |
92 |
93 | Ethereum ETH Dai DAI Uniswap UNI Axie Infinity AXS Smooth Love Potion SLP Uniswap UNI USDC
94 |
95 | **BEP20 Binance Smart Chain Network BSC**
96 | ```
97 | 0xb78c4cf63274bb22f83481986157d234105ac17e
98 | ```
99 | **ERC20 Ethereum Network**
100 | ```
101 | 0xb78c4cf63274bb22f83481986157d234105ac17e
102 | ```
103 |
104 |
105 | Tether USDT
106 |
107 | **BEP20 Binance Smart Chain Network BSC**
108 | ```
109 | 0xb78c4cf63274bb22f83481986157d234105ac17e
110 | ```
111 | **ERC20 Ethereum Network**
112 | ```
113 | 0xb78c4cf63274bb22f83481986157d234105ac17e
114 | ```
115 | **TRC20 Tron Network**
116 | ```
117 | TWGft53WgWvH2mnqR8ZUXq1GD8M4gZ4Yfu
118 | ```
119 |
120 |
121 | Solana SOL
122 |
123 | **BEP20 Binance Smart Chain Network BSC**
124 | ```
125 | 0xb78c4cf63274bb22f83481986157d234105ac17e
126 | ```
127 | **SOL Solana Network**
128 | ```
129 | FKaPSd8kTUpH7Q76d77toy1jjPGpZSxR4xbhQHyCMSGq
130 | ```
131 |
132 |
133 | Cardano ADA
134 |
135 | **BEP20 Binance Smart Chain Network BSC**
136 | ```
137 | 0xb78c4cf63274bb22f83481986157d234105ac17e
138 | ```
139 | **ADA Cardano Network**
140 | ```
141 | DdzFFzCqrht9Y1r4Yx7ouqG9yJNWeXFt69xavLdaeXdu4cQi2yXgNWagzh52o9k9YRh3ussHnBnDrg7v7W2hSXWXfBhbo2ooUKRFMieM
142 | ```
143 |
144 |
145 | Sandbox SAND Decentraland MANA
146 |
147 | **ERC20 Ethereum Network**
148 | ```
149 | 0xb78c4cf63274bb22f83481986157d234105ac17e
150 | ```
151 |
152 |
153 | Algorand ALGO
154 |
155 | **ALGO Algorand Network**
156 | ```
157 | WM54DHVZQIQDVTHMPOH6FEZ4U2AU3OBPGAFTHSCYWMFE7ETKCUUOYAW24Q
158 | ```
159 |
160 |
161 | Polkadot DOT
162 |
163 | **DOT Network**
164 | ```
165 | 13GdxHQbQA1K6i7Ctf781nQkhQhoVhGgUnrjn9EvcJnYWCEd
166 | ```
167 | **BEP20 Binance Smart Chain Network BSC**
168 | ```
169 | 0xb78c4cf63274bb22f83481986157d234105ac17e
170 | ```
171 |
172 |
173 | Binance
174 |
175 | [https://pay.binance.com/en/checkout/e92e536210fd4f62b426ea7ee65b49c3](https://pay.binance.com/en/checkout/e92e536210fd4f62b426ea7ee65b49c3 "Send via Binance Pay")
176 |
177 |
178 |
179 | # Stars
180 |
181 | 
182 | :star: [@juancarlospaco](https://github.com/juancarlospaco '2022-02-16')
183 | :star: [@hamidb80](https://github.com/hamidb80 '2022-02-16')
184 | :star: [@nikitavoloboev](https://github.com/nikitavoloboev '2022-02-16')
185 | :star: [@mxschmitt](https://github.com/mxschmitt '2022-02-17')
186 | :star: [@harrtho](https://github.com/harrtho '2022-02-17')
187 | :star: [@kangkot](https://github.com/kangkot '2022-04-12')
188 | :star: [@crox-safe](https://github.com/crox-safe '2022-04-13')
189 | :star: [@carno](https://github.com/carno '2022-06-01')
190 | :star: [@xdroff](https://github.com/xdroff '2022-06-01')
191 | :star: [@tumregels](https://github.com/tumregels '2022-06-18')
192 | :star: [@Pebaz](https://github.com/Pebaz '2022-07-17')
193 | :star: [@Siss3l](https://github.com/Siss3l '2022-11-19')
194 | :star: [@daweedkob](https://github.com/daweedkob '2022-11-19')
195 | :star: [@xilicode](https://github.com/xilicode '2022-11-25')
196 | :star: [@pietroppeter](https://github.com/pietroppeter '2023-01-20')
197 | :star: [@linwaytin](https://github.com/linwaytin '2023-01-22')
198 | :star: [@thomas-mckay](https://github.com/thomas-mckay '2023-06-09')
199 | :star: [@hansalemaos](https://github.com/hansalemaos '2023-08-07')
200 | :star: [@benzolium](https://github.com/benzolium '2023-08-09')
201 | :star: [@T145](https://github.com/T145 '2023-08-13')
202 | :star: [@Xynonners](https://github.com/Xynonners '2023-08-13')
203 | :star: [@BlackNurse](https://github.com/BlackNurse '2023-08-19')
204 | :star: [@xjzh123](https://github.com/xjzh123 '2023-10-11')
205 | :star: [@JoeBarouneD](https://github.com/JoeBarouneD '2023-12-17')
206 | :star: [@wrath-codes](https://github.com/wrath-codes '2025-01-12')
207 | :star: [@wrath-codes](https://github.com/wrath-codes '2025-03-14')
208 |
--------------------------------------------------------------------------------
/benchmark.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import timeit
5 | import time
6 | import string
7 | import argparse
8 | import csv
9 | import pandas
10 |
11 |
12 | def run_test(library, repetitions, setup_test, run_test):
13 | mytime = timeit.timeit(stmt=run_test, setup=setup_test, number=repetitions)
14 | print(f"{library} =\t{round(mytime, 4)}")
15 | result = [library, repetitions, mytime]
16 | return result
17 |
18 |
19 | def run_all_benchmarks(repetitions=10_000, output_file="results.csv"):
20 | results = []
21 | tests = []
22 |
23 | tests.append(('pathlib cwd() ', 'import pathlib', "pathlib.Path().cwd()"))
24 | tests.append(('thatlib cwd() ', 'import thatlib', "thatlib.cwd()"))
25 |
26 | tests.append(('pathlib home()', 'import pathlib', "pathlib.Path().home()"))
27 | tests.append(('thatlib home()', 'import thatlib', "thatlib.home()"))
28 |
29 | tests.append(('pathlib is_file()', 'import pathlib', "pathlib.Path(__file__).is_file()"))
30 | tests.append(('thatlib is_file()', 'import thatlib', "thatlib.is_file(__file__)"))
31 |
32 | tests.append(('pathlib exists()', 'import pathlib', "pathlib.Path(__file__).exists()"))
33 | tests.append(('thatlib exists()', 'import thatlib', "thatlib.exists(__file__)"))
34 |
35 | tests.append(('pathlib is_absolute()', 'import pathlib', "pathlib.Path(__file__).is_absolute()"))
36 | tests.append(('thatlib is_absolute()', 'import thatlib', "thatlib.is_absolute(__file__)"))
37 |
38 | tests.append(('pathlib joinpath()', 'import pathlib', "pathlib.Path(__file__).joinpath('foo')"))
39 | tests.append(('thatlib joinpath()', 'import thatlib', "thatlib.joinpath([__file__, 'foo'])"))
40 |
41 | tests.append(('pathlib with_suffix()', 'import pathlib', "pathlib.Path(__file__).with_suffix('.foo')"))
42 | tests.append(('thatlib with_suffix()', 'import thatlib', "thatlib.with_suffix(__file__, '.foo')"))
43 |
44 | tests.append(('pathlib with_stem()', 'import pathlib', "pathlib.Path(__file__).with_stem('foo')"))
45 | tests.append(('thatlib with_stem()', 'import thatlib', "thatlib.with_stem(__file__, 'foo')"))
46 |
47 | tests.append(('pathlib with_name()', 'import pathlib', "pathlib.Path(__file__).with_name('foo')"))
48 | tests.append(('thatlib with_name()', 'import thatlib', "thatlib.with_name(__file__, 'foo')"))
49 |
50 | tests.append(('pathlib expanduser()', 'import pathlib', "pathlib.Path('~/foo').expanduser()"))
51 | tests.append(('thatlib expanduser()', 'import thatlib', "thatlib.expanduser('~/foo')"))
52 |
53 | tests.append(('pathlib joinpath()', 'import pathlib', "pathlib.Path('foo').joinpath('bar')"))
54 | tests.append(('thatlib joinpath()', 'import thatlib', "thatlib.joinpath(['foo', 'bar'])"))
55 |
56 | # tests.append(('pathlib write_bytes()', 'import pathlib', "pathlib.Path('/tmp/foo.txt').write_bytes(b'bar')"))
57 | # tests.append(('thatlib write_bytes()', 'import thatlib', "thatlib.write_bytes('/tmp/foo.txt', b'bar')"))
58 |
59 | # tests.append(('pathlib read_bytes()', 'import pathlib', "pathlib.Path('/tmp/foo.txt').read_bytes()"))
60 | # tests.append(('thatlib read_bytes()', 'import thatlib', "thatlib.read_bytes('/tmp/foo.txt')"))
61 |
62 | tests.append(('pathlib chmod()', 'import pathlib', "pathlib.Path('/tmp/foo.txt').chmod(0o666)"))
63 | tests.append(('thatlib chmod()', 'import thatlib', "thatlib.chmod('/tmp/foo.txt', 0o666)"))
64 |
65 | for test in tests:
66 | my_result = run_test(test[0], repetitions, test[1], test[2])
67 | results.append((test[0], my_result[-1]))
68 |
69 | if output_file:
70 | with open(output_file, 'w') as csvfile:
71 | outwriter = csv.writer(csvfile, dialect=csv.excel)
72 | outwriter.writerow(('library', 'time'))
73 | for result in results:
74 | outwriter.writerow(result)
75 |
76 |
77 | def plot_benchmark_results(in_path="results.csv", output_path="results_graph.png"):
78 | data = pandas.read_csv(in_path)
79 | chart = data.plot.bar(x='library', y='time', figsize=(10, 4), color=["red", "green"], title="Pathlib Versus Thatlib", rot=85)
80 | chart.figure.tight_layout()
81 | chart.figure.savefig(output_path)
82 | return
83 |
84 |
85 | if __name__ == '__main__':
86 | parser = argparse.ArgumentParser(description="Benchmarks for path libs")
87 | parser.add_argument('--repetitions', metavar='c', type=int, default=10_000, help="Repetitions")
88 | args = vars(parser.parse_args())
89 | assert args.get('repetitions') > 100, "Repetitions must be > 100."
90 | print(args)
91 | run_all_benchmarks(**args)
92 | plot_benchmark_results()
93 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | thatlib
21 |
22 |
23 |
24 |
25 |
67 |
68 |
69 |
70 |
71 |
72 |
thatlib
73 |
74 |
75 |
76 |
80 |
Dark Mode
81 |
82 |
83 |
84 | -
85 | Index
86 |
87 |
88 |
89 |
90 | Search:
92 |
93 |
94 | Group by:
95 |
99 |
100 |
101 | -
102 | Procs
103 |
104 |
109 |
114 |
119 |
124 |
129 |
134 |
139 |
144 |
149 |
154 |
159 |
164 |
169 |
174 |
179 |
184 |
191 |
198 |
205 |
210 |
215 |
220 |
225 |
230 |
235 |
240 |
245 |
250 |
255 |
260 |
265 |
270 |
275 |
280 |
285 |
290 |
295 |
300 |
305 |
310 |
315 |
320 |
325 |
330 |
335 |
340 |
345 |
350 |
355 |
360 |
365 |
370 |
375 |
380 |
385 |
390 |
395 |
400 |
405 |
410 |
415 |
420 |
425 |
434 |
439 |
444 |
449 |
456 |
461 |
466 |
471 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |

488 |
489 |
490 |
491 |
492 |
proc absolute(path: string): string {....raises: [ValueError, OSError], tags: [].}
493 |
-
494 |
495 |
496 |
497 |
498 |
499 |
500 |
proc as_uri(path: string): string {....raises: [ValueError, OSError], tags: [].}
501 |
-
502 |
503 |
504 |
505 |
506 |
507 |
508 |
proc chmod(path: string; permissions: uint) {....raises: [OSError],
509 | tags: [ReadDirEffect, WriteDirEffect].}
510 |
-
511 |
512 |
513 |
514 |
515 |
516 |
517 |
func compare_paths(pathA, pathB: string): int {....raises: [], tags: [].}
518 |
-
519 |
520 |
521 |
522 |
523 |
524 |
525 |
proc copy_dir_permissions(source, dest: string; ignore_errors: bool = true) {.
526 | ...raises: [OSError, IOError, Exception],
527 | tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect].}
528 |
-
529 |
530 |
531 |
532 |
533 |
534 |
535 |
proc copy_file_permissions(source, dest: string; ignore_errors: bool = true) {.
536 | ...raises: [OSError, IOError, Exception],
537 | tags: [ReadDirEffect, ReadIOEffect, WriteIOEffect, WriteDirEffect].}
538 |
-
539 |
540 |
541 |
542 |
543 |
544 |
545 |
proc counted_lines(path: string): int {....raises: [IOError], tags: [ReadIOEffect].}
546 |
-
547 |
548 |
549 |
550 |
551 |
552 |
553 |
proc cwd(): string {....raises: [OSError], tags: [].}
554 |
-
555 |
556 |
557 |
558 |
559 |
560 |
561 |
proc dotenv(path: string): string {....raises: [IOError, OSError, JsonParsingError,
562 | ValueError, Exception], tags: [ReadIOEffect, WriteIOEffect].}
563 |
-
564 |
565 |
566 |
567 |
568 |
569 |
570 |
proc env_vars_pairs(): seq[(string, string)] {....raises: [], tags: [ReadEnvEffect].}
571 |
-
572 |
573 |
574 |
575 |
576 |
577 |
578 |
proc exists(path: string): bool {....raises: [], tags: [ReadDirEffect].}
579 |
-
580 |
581 |
582 |
583 |
584 |
585 |
586 |
proc exists_create_dir(path: string): bool {....raises: [OSError, IOError],
587 | tags: [WriteDirEffect, ReadDirEffect].}
588 |
-
589 |
590 |
591 |
592 |
593 |
594 |
595 |
proc expanduser(path: string): string {....raises: [],
596 | tags: [ReadEnvEffect, ReadIOEffect].}
597 |
-
598 |
599 |
600 |
601 |
602 |
603 |
604 |
proc get_conf_dir(): string {....raises: [], tags: [ReadEnvEffect, ReadIOEffect].}
605 |
-
606 |
607 |
608 |
609 |
610 |
611 |
619 |
620 |
proc get_exe(path: string; followSymlinks: bool = true): string {.
621 | ...raises: [OSError], tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect].}
622 |
-
623 |
624 |
625 |
626 |
627 |
628 |
629 |
proc get_file_info(path: string; follow_symlinks: bool = true): tuple[
630 | size, link_count, block_size, permissions: int64] {....raises: [OSError],
631 | tags: [].}
632 |
-
633 |
634 |
635 |
636 |
637 |
638 |
639 |
proc get_file_times_iso(path: string; follow_symlinks: bool = true): tuple[
640 | last_access, last_write, creation: string] {....raises: [OSError], tags: [].}
641 |
-
642 |
643 |
644 |
645 |
646 |
647 |
648 |
proc get_file_times_unix(path: string; follow_symlinks: bool = true): tuple[
649 | last_access, last_write, creation: int64] {....raises: [OSError], tags: [].}
650 |
-
651 |
652 |
653 |
654 |
655 |
656 |
657 |
proc get_md5(path: string): string {....raises: [IOError], tags: [ReadIOEffect].}
658 |
-
659 |
660 |
661 |
662 |
663 |
664 |
665 |
proc get_sha1(path: string): string {....raises: [IOError], tags: [ReadIOEffect].}
666 |
-
667 |
668 |
669 |
670 |
671 |
672 |
673 |
proc get_size(path: string): BiggestInt {....raises: [IOError, OSError],
674 | tags: [ReadIOEffect].}
675 |
-
676 |
677 |
678 |
679 |
680 |
681 |
682 |
proc get_size_human(path: string): string {....raises: [IOError, OSError],
683 | tags: [ReadIOEffect].}
684 |
-
685 |
686 |
687 |
688 |
689 |
690 |
691 |
func get_suffix_index(path: string): int {....raises: [], tags: [].}
692 |
-
693 |
694 |
695 |
696 |
697 |
698 |
699 |
proc get_symlink(path: string): string {....raises: [OSError], tags: [].}
700 |
-
701 |
702 |
703 |
704 |
705 |
706 |
707 |
proc get_temporary_dir(): string {....raises: [],
708 | tags: [ReadEnvEffect, ReadIOEffect].}
709 |
-
710 |
711 |
712 |
713 |
714 |
715 |
716 |
proc hardlink(source, destination: string) {....raises: [OSError], tags: [].}
717 |
-
718 |
719 |
720 |
721 |
722 |
723 |
724 |
proc home(): string {....raises: [], tags: [ReadEnvEffect, ReadIOEffect].}
725 |
-
726 |
727 |
728 |
729 |
730 |
731 |
732 |
func is_absolute(path: string): bool {....raises: [], tags: [].}
733 |
-
734 |
735 |
736 |
737 |
738 |
739 |
740 |
proc is_dir(path: string): bool {....raises: [], tags: [ReadDirEffect].}
741 |
-
742 |
743 |
744 |
745 |
746 |
747 |
748 |
proc is_file(path: string): bool {....raises: [], tags: [ReadDirEffect].}
749 |
-
750 |
751 |
752 |
753 |
754 |
755 |
756 |
proc is_file_newer(pathA, pathB: string): bool {....raises: [OSError], tags: [].}
757 |
-
758 |
759 |
760 |
761 |
762 |
763 |
764 |
func is_fs_casesensitive(): bool {....raises: [], tags: [].}
765 |
-
766 |
767 |
768 |
769 |
770 |
771 |
772 |
proc is_hidden_path(path: string): bool {....raises: [], tags: [].}
773 |
-
774 |
775 |
776 |
777 |
778 |
779 |
780 |
proc is_relative_to(path, base: string): bool {....raises: [Exception],
781 | tags: [RootEffect].}
782 |
-
783 |
784 |
785 |
786 |
787 |
788 |
789 |
proc is_root(): bool {....raises: [], tags: [].}
790 |
-
791 |
792 |
793 |
794 |
795 |
796 |
797 |
func is_root_dir(path: string): bool {....raises: [], tags: [].}
798 |
-
799 |
800 |
801 |
802 |
803 |
804 |
805 |
func is_valid_path(path: string): bool {....raises: [], tags: [].}
806 |
-
807 |
808 |
809 |
810 |
811 |
812 |
813 |
func joinpath(paths: openArray[string]): string {....raises: [], tags: [].}
814 |
-
815 |
816 |
817 |
818 |
819 |
820 |
821 |
proc line(path: string; line_number: Natural): string {....raises: [IOError],
822 | tags: [ReadIOEffect].}
823 |
-
824 |
825 |
826 |
827 |
828 |
829 |
830 |
proc lines(path: string; start: int = 0; ends: int = 1): seq[string] {.
831 | ...raises: [IOError], tags: [ReadIOEffect].}
832 |
-
833 |
834 |
835 |
836 |
837 |
838 |
839 |
proc mkdir(path: string) {....raises: [OSError, IOError],
840 | tags: [WriteDirEffect, ReadDirEffect].}
841 |
-
842 |
843 |
844 |
845 |
846 |
847 |
848 |
proc mkhardlink(source, destination: string) {....raises: [OSError], tags: [].}
849 |
-
850 |
851 |
852 |
853 |
854 |
855 |
856 |
proc mksymlink(source, destination: string): uint {....raises: [OSError], tags: [].}
857 |
-
858 |
859 |
860 |
861 |
862 |
863 |
864 |
func normalized(path: string): string {....raises: [], tags: [].}
865 |
-
866 |
867 |
868 |
869 |
870 |
871 |
872 |
func parent(path: string): string {....raises: [], tags: [].}
873 |
-
874 |
875 |
876 |
877 |
878 |
879 |
880 |
func parents(path: string): string {....raises: [], tags: [].}
881 |
-
882 |
883 |
884 |
885 |
886 |
887 |
888 |
proc parts(path: string): seq[string] {....raises: [ValueError, OSError], tags: [].}
889 |
-
890 |
891 |
892 |
893 |
894 |
895 |
896 |
func path_splitted(path: string): tuple[dir, name, ext: string] {....raises: [],
897 | tags: [].}
898 |
-
899 |
900 |
901 |
902 |
903 |
904 |
905 |
func paths_quoted(paths: openArray[string]): string {....raises: [], tags: [].}
906 |
-
907 |
908 |
909 |
910 |
911 |
912 |
913 |
proc read_bytes(path: string): string {....raises: [IOError], tags: [ReadIOEffect].}
914 |
-
915 |
916 |
917 |
918 |
919 |
920 |
921 |
proc rename(source, destination: string) {.
922 | ...raises: [OSError, IOError, Exception],
923 | tags: [ReadDirEffect, ReadIOEffect, WriteIOEffect].}
924 |
-
925 |
926 |
927 |
928 |
929 |
930 |
931 |
proc replace(source, destination: string): string {.
932 | ...raises: [OSError, IOError, Exception],
933 | tags: [ReadDirEffect, ReadIOEffect, WriteIOEffect].}
934 |
-
935 |
936 |
937 |
938 |
939 |
940 |
941 |
func replaced(path: string; replacements: openArray[(string, string)]): string {.
942 | ...raises: [], tags: [].}
943 |
-
944 |
945 |
946 |
947 |
948 |
949 |
950 |
proc resolve(path: string): string {....raises: [ValueError, OSError], tags: [].}
951 |
-
952 |
953 |
954 |
955 |
956 |
957 |
958 |
proc rmdir(path: string; check: bool = false) {....raises: [OSError],
959 | tags: [WriteDirEffect, ReadDirEffect].}
960 |
-
961 |
962 |
963 |
964 |
965 |
966 |
967 |
func samefile(pathA, pathB: string): bool {....raises: [], tags: [].}
968 |
-
969 |
970 |
971 |
972 |
973 |
974 |
975 |
func stem(path: string): string {....raises: [], tags: [].}
976 |
-
977 |
978 |
979 |
980 |
981 |
982 |
983 |
func suffix(path: string): string {....raises: [], tags: [].}
984 |
-
985 |
986 |
987 |
988 |
989 |
990 |
991 |
proc symlink(source, destination: string) {....raises: [OSError], tags: [].}
992 |
-
993 |
994 |
995 |
996 |
997 |
998 |
999 |
func symlink_exists(path: string): bool {....raises: [], tags: [].}
1000 |
-
1001 |
1002 |
1003 |
1004 |
1005 |
1006 |
1007 |
proc tokenized(path: string): seq[tuple[token: string, isSep: bool]] {.
1008 | ...raises: [IOError], tags: [ReadIOEffect].}
1009 |
-
1010 |
1011 |
1012 |
1013 |
1014 |
1015 |
1016 |
proc try_rmfile(path: string): bool {....raises: [], tags: [WriteDirEffect].}
1017 |
-
1018 |
1019 |
1020 |
1021 |
1022 |
1023 |
1024 |
proc walk(folderpath: string; extensions: seq[string] = @[""];
1025 | followlinks: bool = false; yieldfiles: bool = true;
1026 | debugs: bool = false; check_folders: bool = false;
1027 | prealloc: Positive = 99): seq[string] {....raises: [OSError, ValueError],
1028 | tags: [ReadDirEffect, WriteIOEffect].}
1029 |
-
1030 |
1031 |
1032 |
1033 |
1034 |
1035 |
1036 |
proc walk_files(globpattern: string; prealloc: Positive = 99): seq[string] {.
1037 | ...raises: [ValueError, OSError], tags: [ReadDirEffect].}
1038 |
-
1039 |
1040 |
1041 |
1042 |
1043 |
1044 |
1045 |
proc walk_folders(globpattern: string; prealloc: Positive = 99): seq[string] {.
1046 | ...raises: [ValueError, OSError], tags: [ReadDirEffect].}
1047 |
-
1048 |
1049 |
1050 |
1051 |
1052 |
1053 |
1054 |
proc walk_glob(globpattern: string; prealloc: Positive = 99): seq[string] {.
1055 | ...raises: [ValueError, OSError], tags: [ReadDirEffect].}
1056 |
-
1057 |
1058 |
1059 |
1060 |
1061 |
1062 |
1063 |
proc walk_simple(folderpath: string; relative: bool = false;
1064 | check_folders: bool = false; prealloc: Positive = 99): seq[
1065 | string] {....raises: [OSError, ValueError], tags: [ReadDirEffect].}
1066 |
-
1067 |
1068 |
1069 |
1070 |
1071 |
1072 |
1073 |
func with_name(path, name: string): string {....raises: [], tags: [].}
1074 |
-
1075 |
1076 |
1077 |
1078 |
1079 |
1080 |
1081 |
func with_stem(path, stem: string): string {....raises: [], tags: [].}
1082 |
-
1083 |
1084 |
1085 |
1086 |
1087 |
1088 |
1089 |
func with_suffix(path, ext: string): string {....raises: [], tags: [].}
1090 |
-
1091 |
1092 |
1093 |
1094 |
1095 |
1096 |
1097 |
proc write_bytes(path, data: string): string {....raises: [IOError],
1098 | tags: [WriteIOEffect].}
1099 |
-
1100 |
1101 |
1102 |
1103 |
1104 |
1105 |
1106 |
1107 |
1108 |
1109 |
1110 |
1111 |
1112 |
1113 |
1114 |
1115 | Made with Nim. Generated: 2021-09-04 20:00:05 UTC
1116 |
1117 |
1118 |
1119 |
1120 |
1121 |
1122 |
1123 |
--------------------------------------------------------------------------------
/docs/nimdoc.out.css:
--------------------------------------------------------------------------------
1 | /*
2 | Stylesheet for use with Docutils/rst2html.
3 |
4 | See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
5 | customize this style sheet.
6 |
7 | Modified from Chad Skeeters' rst2html-style
8 | https://bitbucket.org/cskeeters/rst2html-style/
9 |
10 | Modified by Boyd Greenfield and narimiran
11 | */
12 |
13 | :root {
14 | --primary-background: #fff;
15 | --secondary-background: ghostwhite;
16 | --third-background: #e8e8e8;
17 | --info-background: #50c050;
18 | --warning-background: #c0a000;
19 | --error-background: #e04040;
20 | --border: #dde;
21 | --text: #222;
22 | --anchor: #07b;
23 | --anchor-focus: #607c9f;
24 | --input-focus: #1fa0eb;
25 | --strong: #3c3c3c;
26 | --hint: #9A9A9A;
27 | --nim-sprite-base64: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAN4AAAA9CAYAAADCt9ebAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFFmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDggNzkuMTY0MDM2LCAyMDE5LzA4LzEzLTAxOjA2OjU3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDE5LTEyLTAzVDAxOjAzOjQ4KzAxOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOS0xMi0wM1QwMjoyODo0MSswMTowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxOS0xMi0wM1QwMjoyODo0MSswMTowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozMzM0ZjAxYS0yMDExLWE1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");
28 |
29 | --keyword: #5e8f60;
30 | --identifier: #222;
31 | --comment: #484a86;
32 | --operator: #155da4;
33 | --punctuation: black;
34 | --other: black;
35 | --escapeSequence: #c4891b;
36 | --number: #252dbe;
37 | --literal: #a4255b;
38 | --program: #6060c0;
39 | --option: #508000;
40 | --raw-data: #a4255b;
41 | }
42 |
43 | [data-theme="dark"] {
44 | --primary-background: #171921;
45 | --secondary-background: #1e202a;
46 | --third-background: #2b2e3b;
47 | --info-background: #008000;
48 | --warning-background: #807000;
49 | --error-background: #c03000;
50 | --border: #0e1014;
51 | --text: #fff;
52 | --anchor: #8be9fd;
53 | --anchor-focus: #8be9fd;
54 | --input-focus: #8be9fd;
55 | --strong: #bd93f9;
56 | --hint: #7A7C85;
57 | --nim-sprite-base64: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARMAAABMCAYAAABOBlMuAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFFmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDggNzkuMTY0MDM2LCAyMDE5LzA4LzEzLTAxOjA2OjU3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDE5LTEyLTAzVDAxOjE4OjIyKzAxOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOS0xMi0wM1QwMToyMDoxMCswMTowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxOS0xMi0wM1QwMToyMDoxMCswMTowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDplZGViMzU3MC1iNmZjLWQy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");
58 |
59 | --keyword: #ff79c6;
60 | --identifier: #f8f8f2;
61 | --comment: #6272a4;
62 | --operator: #ff79c6;
63 | --punctuation: #f8f8f2;
64 | --other: #f8f8f2;
65 | --escapeSequence: #bd93f9;
66 | --number: #bd93f9;
67 | --literal: #f1fa8c;
68 | --program: #9090c0;
69 | --option: #90b010;
70 | --raw-data: #8be9fd;
71 | }
72 |
73 | .theme-switch-wrapper {
74 | display: flex;
75 | align-items: center;
76 | }
77 |
78 | .theme-switch-wrapper em {
79 | margin-left: 10px;
80 | font-size: 1rem;
81 | }
82 |
83 | .theme-switch {
84 | display: inline-block;
85 | height: 22px;
86 | position: relative;
87 | width: 50px;
88 | }
89 |
90 | .theme-switch input {
91 | display: none;
92 | }
93 |
94 | .slider {
95 | background-color: #ccc;
96 | bottom: 0;
97 | cursor: pointer;
98 | left: 0;
99 | position: absolute;
100 | right: 0;
101 | top: 0;
102 | transition: .4s;
103 | }
104 |
105 | .slider:before {
106 | background-color: #fff;
107 | bottom: 4px;
108 | content: "";
109 | height: 13px;
110 | left: 4px;
111 | position: absolute;
112 | transition: .4s;
113 | width: 13px;
114 | }
115 |
116 | input:checked + .slider {
117 | background-color: #66bb6a;
118 | }
119 |
120 | input:checked + .slider:before {
121 | transform: translateX(26px);
122 | }
123 |
124 | .slider.round {
125 | border-radius: 17px;
126 | }
127 |
128 | .slider.round:before {
129 | border-radius: 50%;
130 | }
131 |
132 | html {
133 | font-size: 100%;
134 | -webkit-text-size-adjust: 100%;
135 | -ms-text-size-adjust: 100%; }
136 |
137 | body {
138 | font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
139 | font-weight: 400;
140 | font-size: 1.125em;
141 | line-height: 1.5;
142 | color: var(--text);
143 | background-color: var(--primary-background); }
144 |
145 | /* Skeleton grid */
146 | .container {
147 | position: relative;
148 | width: 100%;
149 | max-width: 1050px;
150 | margin: 0 auto;
151 | padding: 0;
152 | box-sizing: border-box; }
153 |
154 | .column,
155 | .columns {
156 | width: 100%;
157 | float: left;
158 | box-sizing: border-box;
159 | margin-left: 1%;
160 | }
161 |
162 | .column:first-child,
163 | .columns:first-child {
164 | margin-left: 0; }
165 |
166 | .three.columns {
167 | width: 22%;
168 | }
169 |
170 | .nine.columns {
171 | width: 77.0%; }
172 |
173 | .twelve.columns {
174 | width: 100%;
175 | margin-left: 0; }
176 |
177 | @media screen and (max-width: 860px) {
178 | .three.columns {
179 | display: none;
180 | }
181 | .nine.columns {
182 | width: 98.0%;
183 | }
184 | body {
185 | font-size: 1em;
186 | line-height: 1.35;
187 | }
188 | }
189 |
190 | cite {
191 | font-style: italic !important; }
192 |
193 |
194 | /* Nim search input */
195 | div#searchInputDiv {
196 | margin-bottom: 1em;
197 | }
198 | input#searchInput {
199 | width: 80%;
200 | }
201 |
202 | /*
203 | * Some custom formatting for input forms.
204 | * This also fixes input form colors on Firefox with a dark system theme on Linux.
205 | */
206 | input {
207 | -moz-appearance: none;
208 | background-color: var(--secondary-background);
209 | color: var(--text);
210 | border: 1px solid var(--border);
211 | font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
212 | font-size: 0.9em;
213 | padding: 6px;
214 | }
215 |
216 | input:focus {
217 | border: 1px solid var(--input-focus);
218 | box-shadow: 0 0 3px var(--input-focus);
219 | }
220 |
221 | select {
222 | -moz-appearance: none;
223 | background-color: var(--secondary-background);
224 | color: var(--text);
225 | border: 1px solid var(--border);
226 | font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
227 | font-size: 0.9em;
228 | padding: 6px;
229 | }
230 |
231 | select:focus {
232 | border: 1px solid var(--input-focus);
233 | box-shadow: 0 0 3px var(--input-focus);
234 | }
235 |
236 | /* Docgen styles */
237 |
238 | :target {
239 | border: 2px solid #B5651D;
240 | border-style: dotted;
241 | }
242 |
243 | /* Links */
244 | a {
245 | color: var(--anchor);
246 | text-decoration: none;
247 | }
248 |
249 | a span.Identifier {
250 | text-decoration: underline;
251 | text-decoration-color: #aab;
252 | }
253 |
254 | a.reference-toplevel {
255 | font-weight: bold;
256 | }
257 |
258 | a.toc-backref {
259 | text-decoration: none;
260 | color: var(--text); }
261 |
262 | a.link-seesrc {
263 | color: #607c9f;
264 | font-size: 0.9em;
265 | font-style: italic; }
266 |
267 | a:hover,
268 | a:focus {
269 | color: var(--anchor-focus);
270 | text-decoration: underline; }
271 |
272 | a:hover span.Identifier {
273 | color: var(--anchor);
274 | }
275 |
276 |
277 | sub,
278 | sup {
279 | position: relative;
280 | font-size: 75%;
281 | line-height: 0;
282 | vertical-align: baseline; }
283 |
284 | sup {
285 | top: -0.5em; }
286 |
287 | sub {
288 | bottom: -0.25em; }
289 |
290 | img {
291 | width: auto;
292 | height: auto;
293 | max-width: 100%;
294 | vertical-align: middle;
295 | border: 0;
296 | -ms-interpolation-mode: bicubic; }
297 |
298 | @media print {
299 | * {
300 | color: black !important;
301 | text-shadow: none !important;
302 | background: transparent !important;
303 | box-shadow: none !important; }
304 |
305 | a,
306 | a:visited {
307 | text-decoration: underline; }
308 |
309 | a[href]:after {
310 | content: " (" attr(href) ")"; }
311 |
312 | abbr[title]:after {
313 | content: " (" attr(title) ")"; }
314 |
315 | .ir a:after,
316 | a[href^="javascript:"]:after,
317 | a[href^="#"]:after {
318 | content: ""; }
319 |
320 | pre,
321 | blockquote {
322 | border: 1px solid #999;
323 | page-break-inside: avoid; }
324 |
325 | thead {
326 | display: table-header-group; }
327 |
328 | tr,
329 | img {
330 | page-break-inside: avoid; }
331 |
332 | img {
333 | max-width: 100% !important; }
334 |
335 | @page {
336 | margin: 0.5cm; }
337 |
338 | h1 {
339 | page-break-before: always; }
340 |
341 | h1.title {
342 | page-break-before: avoid; }
343 |
344 | p,
345 | h2,
346 | h3 {
347 | orphans: 3;
348 | widows: 3; }
349 |
350 | h2,
351 | h3 {
352 | page-break-after: avoid; }
353 | }
354 |
355 |
356 | p {
357 | margin-top: 0.5em;
358 | margin-bottom: 0.5em;
359 | }
360 |
361 | small {
362 | font-size: 85%; }
363 |
364 | strong {
365 | font-weight: 600;
366 | font-size: 0.95em;
367 | color: var(--strong);
368 | }
369 |
370 | em {
371 | font-style: italic; }
372 |
373 | h1 {
374 | font-size: 1.8em;
375 | font-weight: 400;
376 | padding-bottom: .25em;
377 | border-bottom: 6px solid var(--third-background);
378 | margin-top: 2.5em;
379 | margin-bottom: 1em;
380 | line-height: 1.2em; }
381 |
382 | h1.title {
383 | padding-bottom: 1em;
384 | border-bottom: 0px;
385 | font-size: 2.5em;
386 | text-align: center;
387 | font-weight: 900;
388 | margin-top: 0.75em;
389 | margin-bottom: 0em;
390 | }
391 |
392 | h2 {
393 | font-size: 1.3em;
394 | margin-top: 2em; }
395 |
396 | h2.subtitle {
397 | margin-top: 0em;
398 | text-align: center; }
399 |
400 | h3 {
401 | font-size: 1.125em;
402 | font-style: italic;
403 | margin-top: 1.5em; }
404 |
405 | h4 {
406 | font-size: 1.125em;
407 | margin-top: 1em; }
408 |
409 | h5 {
410 | font-size: 1.125em;
411 | margin-top: 0.75em; }
412 |
413 | h6 {
414 | font-size: 1.1em; }
415 |
416 |
417 | ul,
418 | ol {
419 | padding: 0;
420 | margin-top: 0.5em;
421 | margin-left: 0.75em; }
422 |
423 | ul ul,
424 | ul ol,
425 | ol ol,
426 | ol ul {
427 | margin-bottom: 0;
428 | margin-left: 1.25em; }
429 |
430 | ul.simple > li {
431 | list-style-type: circle;
432 | }
433 |
434 | ul.simple-boot li {
435 | list-style-type: none;
436 | margin-left: 0em;
437 | margin-bottom: 0.5em;
438 | }
439 |
440 | ol.simple > li, ul.simple > li {
441 | margin-bottom: 0.2em;
442 | margin-left: 0.4em }
443 |
444 | ul.simple.simple-toc > li {
445 | margin-top: 1em;
446 | }
447 |
448 | ul.simple-toc {
449 | list-style: none;
450 | font-size: 0.9em;
451 | margin-left: -0.3em;
452 | margin-top: 1em; }
453 |
454 | ul.simple-toc > li {
455 | list-style-type: none;
456 | }
457 |
458 | ul.simple-toc-section {
459 | list-style-type: circle;
460 | margin-left: 0.8em;
461 | color: #6c9aae; }
462 |
463 | ul.nested-toc-section {
464 | list-style-type: circle;
465 | margin-left: -0.75em;
466 | color: var(--text);
467 | }
468 |
469 | ul.nested-toc-section > li {
470 | margin-left: 1.25em;
471 | }
472 |
473 |
474 | ol.arabic {
475 | list-style: decimal; }
476 |
477 | ol.loweralpha {
478 | list-style: lower-alpha; }
479 |
480 | ol.upperalpha {
481 | list-style: upper-alpha; }
482 |
483 | ol.lowerroman {
484 | list-style: lower-roman; }
485 |
486 | ol.upperroman {
487 | list-style: upper-roman; }
488 |
489 | ul.auto-toc {
490 | list-style-type: none; }
491 |
492 |
493 | dl {
494 | margin-bottom: 1.5em; }
495 |
496 | dt {
497 | margin-bottom: -0.5em;
498 | margin-left: 0.0em; }
499 |
500 | dd {
501 | margin-left: 2.0em;
502 | margin-bottom: 3.0em;
503 | margin-top: 0.5em; }
504 |
505 |
506 | hr {
507 | margin: 2em 0;
508 | border: 0;
509 | border-top: 1px solid #aaa; }
510 |
511 | hr.footnote {
512 | width: 25%;
513 | border-top: 0.15em solid #999;
514 | margin-bottom: 0.15em;
515 | margin-top: 0.15em;
516 | }
517 | div.footnote-group {
518 | margin-left: 1em; }
519 | div.footnote-label {
520 | display: inline-block;
521 | min-width: 1.7em;
522 | }
523 |
524 | div.option-list {
525 | border: 0.1em solid var(--border);
526 | }
527 | div.option-list-item {
528 | padding-left: 12em;
529 | padding-right: 0;
530 | padding-bottom: 0.3em;
531 | padding-top: 0.3em;
532 | }
533 | div.odd {
534 | background-color: var(--secondary-background);
535 | }
536 | div.option-list-label {
537 | margin-left: -11.5em;
538 | margin-right: 0em;
539 | min-width: 11.5em;
540 | display: inline-block;
541 | vertical-align: top;
542 | }
543 | div.option-list-description {
544 | width: calc(100% - 1em);
545 | padding-left: 1em;
546 | padding-right: 0;
547 | display: inline-block;
548 | }
549 |
550 | blockquote {
551 | font-size: 0.9em;
552 | font-style: italic;
553 | padding-left: 0.5em;
554 | margin-left: 0;
555 | border-left: 5px solid #bbc;
556 | }
557 |
558 | .pre, span.tok {
559 | font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace;
560 | font-weight: 500;
561 | font-size: 0.85em;
562 | color: var(--text);
563 | background-color: var(--third-background);
564 | padding-left: 3px;
565 | padding-right: 3px;
566 | border-radius: 4px;
567 | }
568 |
569 | span.tok {
570 | border: 1px solid #808080;
571 | padding-bottom: 0.1em;
572 | margin-right: 0.2em;
573 | }
574 |
575 | pre {
576 | font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace;
577 | color: var(--text);
578 | font-weight: 500;
579 | display: inline-block;
580 | box-sizing: border-box;
581 | min-width: 100%;
582 | padding: 0.5em;
583 | margin-top: 0.5em;
584 | margin-bottom: 0.5em;
585 | font-size: 0.85em;
586 | white-space: pre !important;
587 | overflow-y: hidden;
588 | overflow-x: visible;
589 | background-color: var(--secondary-background);
590 | border: 1px solid var(--border);
591 | -webkit-border-radius: 6px;
592 | -moz-border-radius: 6px;
593 | border-radius: 6px; }
594 |
595 | .pre-scrollable {
596 | max-height: 340px;
597 | overflow-y: scroll; }
598 |
599 |
600 | /* Nim line-numbered tables */
601 | .line-nums-table {
602 | width: 100%;
603 | table-layout: fixed; }
604 |
605 | table.line-nums-table {
606 | border-radius: 4px;
607 | border: 1px solid #cccccc;
608 | background-color: ghostwhite;
609 | border-collapse: separate;
610 | margin-top: 15px;
611 | margin-bottom: 25px; }
612 |
613 | .line-nums-table tbody {
614 | border: none; }
615 |
616 | .line-nums-table td pre {
617 | border: none;
618 | background-color: transparent; }
619 |
620 | .line-nums-table td.blob-line-nums {
621 | width: 28px; }
622 |
623 | .line-nums-table td.blob-line-nums pre {
624 | color: #b0b0b0;
625 | -webkit-filter: opacity(75%);
626 | filter: opacity(75%);
627 | text-align: right;
628 | border-color: transparent;
629 | background-color: transparent;
630 | padding-left: 0px;
631 | margin-left: 0px;
632 | padding-right: 0px;
633 | margin-right: 0px; }
634 |
635 |
636 | table {
637 | max-width: 100%;
638 | background-color: transparent;
639 | margin-top: 0.5em;
640 | margin-bottom: 1.5em;
641 | border-collapse: collapse;
642 | border-color: var(--third-background);
643 | border-spacing: 0;
644 | font-size: 0.9em;
645 | }
646 |
647 | table th, table td {
648 | padding: 0px 0.5em 0px;
649 | border-color: var(--third-background);
650 | }
651 |
652 | table th {
653 | background-color: var(--third-background);
654 | border-color: var(--third-background);
655 | font-weight: bold; }
656 |
657 | table th.docinfo-name {
658 | background-color: transparent;
659 | text-align: right;
660 | }
661 |
662 | table tr:hover {
663 | background-color: var(--third-background); }
664 |
665 |
666 | /* rst2html default used to remove borders from tables and images */
667 | .borderless, table.borderless td, table.borderless th {
668 | border: 0; }
669 |
670 | table.borderless td, table.borderless th {
671 | /* Override padding for "table.docutils td" with "! important".
672 | The right padding separates the table cells. */
673 | padding: 0 0.5em 0 0 !important; }
674 |
675 | .admonition {
676 | padding: 0.3em;
677 | background-color: var(--secondary-background);
678 | border-left: 0.4em solid #7f7f84;
679 | margin-bottom: 0.5em;
680 | -webkit-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2);
681 | -moz-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2);
682 | box-shadow: 0 5px 8px -6px rgba(0,0,0,.2);
683 | }
684 | .admonition-info {
685 | border-color: var(--info-background);
686 | }
687 | .admonition-info-text {
688 | color: var(--info-background);
689 | }
690 | .admonition-warning {
691 | border-color: var(--warning-background);
692 | }
693 | .admonition-warning-text {
694 | color: var(--warning-background);
695 | }
696 | .admonition-error {
697 | border-color: var(--error-background);
698 | }
699 | .admonition-error-text {
700 | color: var(--error-background);
701 | }
702 |
703 | .first {
704 | /* Override more specific margin styles with "! important". */
705 | margin-top: 0 !important; }
706 |
707 | .last, .with-subtitle {
708 | margin-bottom: 0 !important; }
709 |
710 | .hidden {
711 | display: none; }
712 |
713 | blockquote.epigraph {
714 | margin: 2em 5em; }
715 |
716 | dl.docutils dd {
717 | margin-bottom: 0.5em; }
718 |
719 | object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
720 | overflow: hidden; }
721 |
722 |
723 | div.figure {
724 | margin-left: 2em;
725 | margin-right: 2em; }
726 |
727 | div.footer, div.header {
728 | clear: both;
729 | text-align: center;
730 | color: #666;
731 | font-size: smaller; }
732 |
733 | div.footer {
734 | padding-top: 5em;
735 | }
736 |
737 | div.line-block {
738 | display: block;
739 | margin-top: 1em;
740 | margin-bottom: 1em; }
741 |
742 | div.line-block div.line-block {
743 | margin-top: 0;
744 | margin-bottom: 0;
745 | margin-left: 1.5em; }
746 |
747 | div.topic {
748 | margin: 2em; }
749 |
750 | div.search_results {
751 | background-color: var(--third-background);
752 | margin: 3em;
753 | padding: 1em;
754 | border: 1px solid #4d4d4d;
755 | }
756 |
757 | div#global-links ul {
758 | margin-left: 0;
759 | list-style-type: none;
760 | }
761 |
762 | div#global-links > simple-boot {
763 | margin-left: 3em;
764 | }
765 |
766 | hr.docutils {
767 | width: 75%; }
768 |
769 | img.align-left, .figure.align-left, object.align-left {
770 | clear: left;
771 | float: left;
772 | margin-right: 1em; }
773 |
774 | img.align-right, .figure.align-right, object.align-right {
775 | clear: right;
776 | float: right;
777 | margin-left: 1em; }
778 |
779 | img.align-center, .figure.align-center, object.align-center {
780 | display: block;
781 | margin-left: auto;
782 | margin-right: auto; }
783 |
784 | .align-left {
785 | text-align: left; }
786 |
787 | .align-center {
788 | clear: both;
789 | text-align: center; }
790 |
791 | .align-right {
792 | text-align: right; }
793 |
794 | /* reset inner alignment in figures */
795 | div.align-right {
796 | text-align: inherit; }
797 |
798 | p.attribution {
799 | text-align: right;
800 | margin-left: 50%; }
801 |
802 | p.caption {
803 | font-style: italic; }
804 |
805 | p.credits {
806 | font-style: italic;
807 | font-size: smaller; }
808 |
809 | p.label {
810 | white-space: nowrap; }
811 |
812 | p.rubric {
813 | font-weight: bold;
814 | font-size: larger;
815 | color: maroon;
816 | text-align: center; }
817 |
818 | p.topic-title {
819 | font-weight: bold; }
820 |
821 | pre.address {
822 | margin-bottom: 0;
823 | margin-top: 0;
824 | font: inherit; }
825 |
826 | pre.literal-block, pre.doctest-block, pre.math, pre.code {
827 | margin-left: 2em;
828 | margin-right: 2em; }
829 |
830 | pre.code .ln {
831 | color: grey; }
832 |
833 | /* line numbers */
834 | pre.code, code {
835 | background-color: #eeeeee; }
836 |
837 | pre.code .comment, code .comment {
838 | color: #5c6576; }
839 |
840 | pre.code .keyword, code .keyword {
841 | color: #3B0D06;
842 | font-weight: bold; }
843 |
844 | pre.code .literal.string, code .literal.string {
845 | color: #0c5404; }
846 |
847 | pre.code .name.builtin, code .name.builtin {
848 | color: #352b84; }
849 |
850 | pre.code .deleted, code .deleted {
851 | background-color: #DEB0A1; }
852 |
853 | pre.code .inserted, code .inserted {
854 | background-color: #A3D289; }
855 |
856 | span.classifier {
857 | font-style: oblique; }
858 |
859 | span.classifier-delimiter {
860 | font-weight: bold; }
861 |
862 | span.problematic {
863 | color: #b30000; }
864 |
865 | span.section-subtitle {
866 | /* font-size relative to parent (h1..h6 element) */
867 | font-size: 80%; }
868 |
869 | span.DecNumber {
870 | color: var(--number); }
871 |
872 | span.BinNumber {
873 | color: var(--number); }
874 |
875 | span.HexNumber {
876 | color: var(--number); }
877 |
878 | span.OctNumber {
879 | color: var(--number); }
880 |
881 | span.FloatNumber {
882 | color: var(--number); }
883 |
884 | span.Identifier {
885 | color: var(--identifier); }
886 |
887 | span.Keyword {
888 | font-weight: 600;
889 | color: var(--keyword); }
890 |
891 | span.StringLit {
892 | color: var(--literal); }
893 |
894 | span.LongStringLit {
895 | color: var(--literal); }
896 |
897 | span.CharLit {
898 | color: var(--literal); }
899 |
900 | span.EscapeSequence {
901 | color: var(--escapeSequence); }
902 |
903 | span.Operator {
904 | color: var(--operator); }
905 |
906 | span.Punctuation {
907 | color: var(--punctuation); }
908 |
909 | span.Comment, span.LongComment {
910 | font-style: italic;
911 | font-weight: 400;
912 | color: var(--comment); }
913 |
914 | span.RegularExpression {
915 | color: darkviolet; }
916 |
917 | span.TagStart {
918 | color: darkviolet; }
919 |
920 | span.TagEnd {
921 | color: darkviolet; }
922 |
923 | span.Key {
924 | color: #252dbe; }
925 |
926 | span.Value {
927 | color: #252dbe; }
928 |
929 | span.RawData {
930 | color: var(--raw-data); }
931 |
932 | span.Assembler {
933 | color: #252dbe; }
934 |
935 | span.Preprocessor {
936 | color: #252dbe; }
937 |
938 | span.Directive {
939 | color: #252dbe; }
940 |
941 | span.option {
942 | font-weight: bold;
943 | font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace;
944 | color: var(--option);
945 | }
946 |
947 | span.Prompt {
948 | font-weight: bold;
949 | color: red; }
950 |
951 | span.ProgramOutput {
952 | font-weight: bold;
953 | color: #808080; }
954 |
955 | span.program {
956 | font-weight: bold;
957 | color: var(--program);
958 | text-decoration: underline;
959 | text-decoration-color: var(--hint);
960 | text-decoration-thickness: 0.05em;
961 | text-underline-offset: 0.15em;
962 | }
963 |
964 | span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference,
965 | span.Other {
966 | color: var(--other); }
967 |
968 | /* Pop type, const, proc, and iterator defs in nim def blocks */
969 | dt pre > span.Identifier, dt pre > span.Operator {
970 | color: var(--identifier);
971 | font-weight: 700; }
972 |
973 | dt pre > span.Keyword ~ span.Identifier, dt pre > span.Identifier ~ span.Identifier,
974 | dt pre > span.Operator ~ span.Identifier, dt pre > span.Other ~ span.Identifier {
975 | color: var(--identifier);
976 | font-weight: inherit; }
977 |
978 | /* Nim sprite for the footer (taken from main page favicon) */
979 | .nim-sprite {
980 | display: inline-block;
981 | width: 51px;
982 | height: 14px;
983 | background-position: 0 0;
984 | background-size: 51px 14px;
985 | -webkit-filter: opacity(50%);
986 | filter: opacity(50%);
987 | background-repeat: no-repeat;
988 | background-image: var(--nim-sprite-base64);
989 | margin-bottom: 5px; }
990 |
991 | span.pragmadots {
992 | /* Position: relative frees us up to make the dots
993 | look really nice without fucking up the layout and
994 | causing bulging in the parent container */
995 | position: relative;
996 | /* 1px down looks slightly nicer */
997 | top: 1px;
998 | padding: 2px;
999 | background-color: var(--third-background);
1000 | border-radius: 4px;
1001 | margin: 0 2px;
1002 | cursor: pointer;
1003 | font-size: 0.8em;
1004 | }
1005 |
1006 | span.pragmadots:hover {
1007 | background-color: var(--hint);
1008 | }
1009 | span.pragmawrap {
1010 | display: none;
1011 | }
1012 |
1013 | span.attachedType {
1014 | display: none;
1015 | visibility: hidden;
1016 | }
1017 |
--------------------------------------------------------------------------------
/examples/.env:
--------------------------------------------------------------------------------
1 | # This is a comment = 42
2 | json0 = {"key":"value"} # json
3 | k="v" # string
4 | x = 42 # int
5 | v = 2.0 # float
6 | o = true # bool
7 | b = false # bool
8 | t = +inf # float
9 | w = -inf # float
10 | g = NaN # float
11 | cc="" # string
12 | x="" # int
13 | t = 9999999999999999999 # int
14 | isConsoleApplication=False # bool
15 | COMPILE=True # bool
16 | BASIC=basic # string
17 |
18 | # previous line intentionally left blank
19 | AFTER_LINE=after_line # string
20 | EMPTY= # string
21 | SINGLE_QUOTES='single_quotes' # string
22 | SINGLE_QUOTES_SPACED=' single quotes ' # string
23 | DOUBLE_QUOTES="double_quotes" # string
24 | DOUBLE_QUOTES_SPACED=" double quotes " # string
25 | RETAIN_INNER_QUOTES={"foo": "bar"} # json
26 | RETAIN_LEADING_DQUOTE="retained # string
27 | RETAIN_LEADING_SQUOTE='retained # string
28 | RETAIN_TRAILING_DQUOTE=retained" # string
29 | RETAIN_TRAILING_SQUOTE=retained' # string
30 | RETAIN_INNER_QUOTES_AS_STRING='{"k":"v"}' # string
31 | TRIM_SPACE_FROM_UNQUOTED= spaced out string # string
32 | USERNAME=therealnerdybeast@example.tld # string
33 | SPACED_KEY = parsed # string
34 | EXPAND_NEWLINES="expand\nnew\nlines" # string
35 | DONT_EXPAND_UNQUOTED=dontexpand\nnewlines # string
36 | DONT_EXPAND_SQUOTED='dontexpand\nnewlines' # string
37 | EQUAL_SIGNS=equals== # string
38 |
--------------------------------------------------------------------------------
/examples/example_chmod.py:
--------------------------------------------------------------------------------
1 | from thatlib import chmod
2 | chmod(__file__, 0o777)
3 |
--------------------------------------------------------------------------------
/examples/example_cwd.py:
--------------------------------------------------------------------------------
1 | from thatlib import cwd
2 | print(cwd())
3 |
--------------------------------------------------------------------------------
/examples/example_dotenv.py:
--------------------------------------------------------------------------------
1 | from thatlib import dotenv
2 | print(dotenv(".env")) # ".env" file assumed to be in the same folder for this example.
3 |
--------------------------------------------------------------------------------
/examples/example_expanduser.py:
--------------------------------------------------------------------------------
1 | from thatlib import expanduser
2 | print(expanduser("~/"))
3 |
--------------------------------------------------------------------------------
/examples/example_get_exe.py:
--------------------------------------------------------------------------------
1 | from thatlib import get_exe
2 | print(get_exe("python"))
3 |
--------------------------------------------------------------------------------
/examples/example_get_file_info.py:
--------------------------------------------------------------------------------
1 | from thatlib import get_file_info
2 | print(get_file_info(__file__))
3 |
--------------------------------------------------------------------------------
/examples/example_get_file_times.py:
--------------------------------------------------------------------------------
1 | from thatlib import get_file_times_iso
2 | print(get_file_times_iso(__file__))
3 |
--------------------------------------------------------------------------------
/examples/example_get_size.py:
--------------------------------------------------------------------------------
1 | from thatlib import get_size
2 | print(get_size(__file__))
3 |
--------------------------------------------------------------------------------
/examples/example_home.py:
--------------------------------------------------------------------------------
1 | from thatlib import home
2 | print(home())
3 |
--------------------------------------------------------------------------------
/examples/example_is_file.py:
--------------------------------------------------------------------------------
1 | from thatlib import is_file
2 | print(is_file(__file__))
3 |
--------------------------------------------------------------------------------
/examples/example_is_valid_path.py:
--------------------------------------------------------------------------------
1 | from thatlib import is_valid_path
2 | print(is_valid_path("NUL"))
3 | print(is_valid_path("LPT1"))
4 | print(is_valid_path("COM1"))
5 | print(is_valid_path("CON"))
6 |
--------------------------------------------------------------------------------
/examples/example_joinpath.py:
--------------------------------------------------------------------------------
1 | from thatlib import joinpath
2 | print(joinpath(["foo", "bar", "baz"]))
3 |
--------------------------------------------------------------------------------
/examples/example_lines.py:
--------------------------------------------------------------------------------
1 | from thatlib import lines
2 | print(lines(__file__))
3 |
--------------------------------------------------------------------------------
/examples/example_mkdir.py:
--------------------------------------------------------------------------------
1 | from thatlib import mkdir
2 | mkdir("example")
3 |
--------------------------------------------------------------------------------
/examples/example_path_splitted.py:
--------------------------------------------------------------------------------
1 | from thatlib import path_splitted
2 | print(path_splitted(__file__))
3 |
--------------------------------------------------------------------------------
/examples/example_replaced.py:
--------------------------------------------------------------------------------
1 | from thatlib import replaced
2 | print(replaced(__file__, [("example", "sample")]))
3 |
--------------------------------------------------------------------------------
/examples/example_resolve.py:
--------------------------------------------------------------------------------
1 | from thatlib import resolve
2 | print(resolve("./"))
3 |
--------------------------------------------------------------------------------
/examples/example_rmdir.py:
--------------------------------------------------------------------------------
1 | from thatlib import rmdir
2 | rmdir("example")
3 |
--------------------------------------------------------------------------------
/examples/example_tokenized.py:
--------------------------------------------------------------------------------
1 | from thatlib import tokenized
2 | print(tokenized(__file__))
3 |
--------------------------------------------------------------------------------
/examples/example_walk.py:
--------------------------------------------------------------------------------
1 | from thatlib import walk
2 | print(walk(
3 | folderpath = ".",
4 | extensions = [".py", ".nim"],
5 | followlinks = False,
6 | yieldfiles = True,
7 | debugs = True,
8 | check_folders = False,
9 | prealloc = 9,
10 | ))
11 |
--------------------------------------------------------------------------------
/examples/example_walk_glob.py:
--------------------------------------------------------------------------------
1 | from thatlib import walk_glob
2 | print(walk_glob("*.py"))
3 |
--------------------------------------------------------------------------------
/examples/example_with_name.py:
--------------------------------------------------------------------------------
1 | from thatlib import with_name
2 | print(with_name(__file__, "temp.txt"))
3 |
--------------------------------------------------------------------------------
/examples/example_with_stem.py:
--------------------------------------------------------------------------------
1 | from thatlib import with_stem
2 | print(with_stem(__file__, "OwO"))
3 |
--------------------------------------------------------------------------------
/examples/example_with_suffix.py:
--------------------------------------------------------------------------------
1 | from thatlib import with_suffix
2 | print(with_suffix(__file__, ".txt"))
3 |
--------------------------------------------------------------------------------
/package4pypi.sh:
--------------------------------------------------------------------------------
1 | rm --verbose --force dist/*.zip
2 | rm --verbose --force --recursive dist/thatlib/
3 | rm --verbose --force --recursive dist/thatlib/__pycache__/
4 | cp --verbose --recursive thatlib dist/
5 | cd dist && zip -9 -T -v -r thatlib.zip *
6 |
--------------------------------------------------------------------------------
/results_graph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/juancarlospaco/thatlib/75acf89e7bd0fff6583238fd2481aa97f5877fae/results_graph.png
--------------------------------------------------------------------------------
/run-benchmark.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | python3 benchmark.py # Start script for Benchmark.
3 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import setuptools
2 | from nimporter import get_nim_extensions, WINDOWS, MACOS, LINUX
3 |
4 | setuptools.setup(
5 | name = 'thatlib',
6 | install_requires = ['nimporter'],
7 | py_modules = ['thatlib.py'],
8 | ext_modules = get_nim_extensions(platforms = (WINDOWS, LINUX, MACOS)),
9 | )
10 |
--------------------------------------------------------------------------------
/thatlib-logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/juancarlospaco/thatlib/75acf89e7bd0fff6583238fd2481aa97f5877fae/thatlib-logo.jpg
--------------------------------------------------------------------------------
/thatlib/thatlib.nim:
--------------------------------------------------------------------------------
1 | ## .. image:: https://raw.githubusercontent.com/juancarlospaco/thatlib/nim/results_graph.png
2 | import std/[strutils, os, sha1, md5, json, parseutils, times], nimpy
3 |
4 | proc cwd*(): string {.exportpy.} =
5 | getCurrentDir()
6 |
7 | proc home*(): string {.exportpy.} =
8 | getHomeDir()
9 |
10 | proc mkdir*(path: string) {.exportpy.} =
11 | createDir(path)
12 |
13 | proc rmdir*(path: string; check: bool = false) {.exportpy.} =
14 | removeDir(path, check)
15 |
16 | proc is_file*(path: string): bool {.exportpy.} =
17 | fileExists(path)
18 |
19 | proc is_dir*(path: string): bool {.exportpy.} =
20 | dirExists(path)
21 |
22 | proc exists*(path: string): bool {.exportpy.} =
23 | fileExists(path) or dirExists(path)
24 |
25 | proc rename*(source, destination: string) {.exportpy.} =
26 | moveFile(source, destination)
27 |
28 | proc replace*(source, destination: string): string {.exportpy.} =
29 | moveFile(source, destination)
30 | result = destination
31 |
32 | proc resolve*(path: string): string {.exportpy.} =
33 | absolutePath(path)
34 |
35 | proc absolute*(path: string): string {.exportpy.} =
36 | absolutePath(path)
37 |
38 | func samefile*(pathA, pathB: string): bool {.exportpy.} =
39 | sameFile(pathA, pathB)
40 |
41 | func is_absolute*(path: string): bool {.exportpy.} =
42 | os.isAbsolute(path)
43 |
44 | func joinpath*(paths: openArray[string]): string {.exportpy.} =
45 | os.joinPath(paths)
46 |
47 | func with_suffix*(path, ext: string): string {.exportpy.} =
48 | changeFileExt(path, ext)
49 |
50 | func with_stem*(path, stem: string): string {.exportpy.} =
51 | let f = splitFile(path)
52 | result = f.dir / stem & f.ext
53 |
54 | func with_name*(path, name: string): string {.exportpy.} =
55 | let f = splitFile(path)
56 | result = f.dir / name
57 |
58 | func suffix*(path: string): string {.exportpy.} =
59 | splitFile(path).ext
60 |
61 | func stem*(path: string): string {.exportpy.} =
62 | splitFile(path).name
63 |
64 | func parent*(path: string): string {.exportpy.} =
65 | splitFile(path).dir
66 |
67 | proc write_bytes*(path, data: string): string {.exportpy.} =
68 | writeFile(path, data)
69 |
70 | proc read_bytes*(path: string): string {.exportpy.} =
71 | readFile(path)
72 |
73 | proc is_relative_to*(path, base: string): bool {.exportpy.} =
74 | os.isRelativeTo(path, base)
75 |
76 | proc expanduser*(path: string): string {.exportpy.} =
77 | os.expandTilde(path)
78 |
79 | proc as_uri*(path: string): string {.exportpy.} =
80 | (when defined(windows): "file:///" else: "file://") / absolutePath(path)
81 |
82 | proc parts*(path: string): seq[string] {.exportpy.} =
83 | absolutePath(path).split(DirSep)
84 |
85 | proc chmod*(path: string; permissions: uint) {.exportpy.} =
86 | var results: set[FilePermission]
87 | var perm = permissions
88 | for permBase in [fpOthersExec, fpGroupExec, fpUserExec]:
89 | if (perm and 1) != 0: results.incl permBase # Exec
90 | if (perm and 2) != 0: results.incl permBase.succ() # Read
91 | if (perm and 4) != 0: results.incl permBase.succ(2) # Write
92 | perm = perm shr 3 # Shift to next permission group
93 | setFilePermissions(path, results)
94 |
95 |
96 | # ^ API mimic from Python "pathlib" ################################## v Extras
97 |
98 |
99 | proc is_root*(): bool {.exportpy.} =
100 | when compiles(os.isAdmin): os.isAdmin()
101 |
102 | proc symlink*(source, destination: string) {.exportpy.} =
103 | os.createSymlink(source, destination)
104 |
105 | proc hardlink*(source, destination: string) {.exportpy.} =
106 | os.createHardlink(source, destination)
107 |
108 | proc env_vars_pairs*(): seq[(string, string)] {.exportpy.} =
109 | for item in os.envPairs(): result.add item
110 |
111 | func parents*(path: string): string {.exportpy.} =
112 | parentDir(path)
113 |
114 | func is_fs_casesensitive*(): bool {.exportpy.} =
115 | os.FileSystemCaseSensitive
116 |
117 | func get_dynlib_format*(): string {.exportpy.} =
118 | os.DynlibFormat
119 |
120 | proc lines*(path: string; start: int = 0; ends: int = 1): seq[string] {.exportpy.} =
121 | readFile(path).splitLines[start .. ^ends]
122 |
123 | proc line*(path: string; line_number: Natural): string {.exportpy.} =
124 | readFile(path).splitLines[line_number]
125 |
126 | proc counted_lines*(path: string): int {.exportpy.} =
127 | readFile(path).countLines
128 |
129 | proc tokenized*(path: string): seq[tuple[token: string, isSep: bool]] {.exportpy.} =
130 | for item in tokenize(readFile(path)): result.add item
131 |
132 | func replaced*(path: string; replacements: openArray[(string, string)]): string {.exportpy.} =
133 | path.multiReplace(replacements)
134 |
135 | func normalized*(path: string): string {.exportpy.} =
136 | path.strip.normalize
137 |
138 | func is_root_dir*(path: string): bool {.exportpy.} =
139 | isRootDir(path)
140 |
141 | func get_suffix_index*(path: string): int {.exportpy.} =
142 | searchExtPos(path)
143 |
144 | func path_splitted*(path: string): tuple[dir, name, ext: string] {.exportpy.} =
145 | splitFile(path)
146 |
147 | func compare_paths*(pathA, pathB: string): int {.exportpy.} =
148 | cmpPaths(pathA, pathB)
149 |
150 | proc get_conf_dir*(): string {.exportpy.} =
151 | getConfigDir()
152 |
153 | proc get_temporary_dir*(): string {.exportpy.} =
154 | getTempDir()
155 |
156 | func paths_quoted*(paths: openArray[string]): string {.exportpy.} =
157 | quoteShellCommand(paths)
158 |
159 | proc is_file_newer*(pathA, pathB: string): bool {.exportpy.} =
160 | fileNewer(pathA, pathB)
161 |
162 | func symlink_exists*(path: string): bool {.exportpy.} =
163 | symlinkExists(path)
164 |
165 | proc get_exe*(path: string; followSymlinks: bool = true): string {.exportpy.} =
166 | findExe(path, followSymlinks)
167 |
168 | proc mksymlink*(source, destination: string): uint {.exportpy.} =
169 | createSymlink(source, destination)
170 |
171 | proc get_symlink*(path: string): string {.exportpy.} =
172 | expandSymlink(path)
173 |
174 | proc try_rmfile*(path: string): bool {.exportpy.} =
175 | tryRemoveFile(path)
176 |
177 | proc exists_create_dir*(path: string): bool {.exportpy.} =
178 | existsOrCreateDir(path)
179 |
180 | proc mkhardlink*(source, destination: string) {.exportpy.} =
181 | createHardlink(source, destination)
182 |
183 | proc get_size*(path: string): BiggestInt {.exportpy.} =
184 | getFileSize(path)
185 |
186 | template divmod(a, b): array[2, int] =
187 | [int(int(a) / int(b)), int(a mod b)]
188 |
189 | template abytes(stringy: var string; unit: static[string]) =
190 | when len(unit) > 0:
191 | stringy.add unit # "SOMETHINGbytes"
192 | stringy.add 'b'
193 | else:
194 | stringy.add 'B' # Just "Bytes"
195 | stringy.add 'y'
196 | stringy.add 't'
197 | stringy.add 'e'
198 | stringy.add 's'
199 | stringy.add ' '
200 |
201 | template bytes2human(integer_bytes: int64; result: var string) =
202 | var bite, kilo, mega, giga, tera, peta, exa, zetta, yotta: int64
203 | (kilo, bite) = divmod(integer_bytes, int64(1_024))
204 | (mega, kilo) = divmod(kilo, int64(1_024))
205 | (giga, mega) = divmod(mega, int64(1_024))
206 | (tera, giga) = divmod(giga, int64(1_024))
207 | (peta, tera) = divmod(tera, int64(1_024))
208 | (exa, peta) = divmod(peta, int64(1_024))
209 | (zetta, exa) = divmod(exa, int64(1_024))
210 | (yotta, zetta) = divmod(zetta, int64(1_024))
211 | if unlikely(zetta > 0):
212 | result.addInt zetta
213 | abytes(result, "Zetta")
214 | if unlikely(exa > 0):
215 | result.addInt exa
216 | abytes(result, "Exa")
217 | if unlikely(peta > 0):
218 | result.addInt peta
219 | abytes(result, "Peta")
220 | if tera > 0:
221 | result.addInt tera
222 | abytes(result, "Tera")
223 | if giga > 0:
224 | result.addInt giga
225 | abytes(result, "Giga")
226 | if mega > 0:
227 | result.addInt mega
228 | abytes(result, "Mega")
229 | if kilo > 0:
230 | result.addInt kilo
231 | abytes(result, "Kilo")
232 | result.addInt bite
233 | abytes(result, "")
234 |
235 | proc get_size_human*(path: string): string {.exportpy.} =
236 | bytes2human(getFileSize(path), result)
237 |
238 | proc is_hidden_path*(path: string) : bool {.exportpy.} =
239 | isHidden(path)
240 |
241 | func is_valid_path*(path: string) : bool {.exportpy.} =
242 | isValidFilename(path)
243 |
244 | proc get_md5*(path: string): string {.exportpy.} =
245 | md5.getMD5(readFile(path))
246 |
247 | proc get_sha1*(path: string): string {.exportpy.} =
248 | $secureHashFile(path)
249 |
250 | proc copy_file_permissions*(source, dest: string; ignore_errors: bool = true) {.exportpy.} =
251 | copyFileWithPermissions(source, dest, ignore_errors)
252 |
253 | proc copy_dir_permissions*(source, dest: string; ignore_errors: bool = true) {.exportpy.} =
254 | copyDirWithPermissions(source, dest, ignore_errors)
255 |
256 | func fromFilePermissions(perm: set[FilePermission]): uint {.inline.} =
257 | if fpUserExec in perm: inc result, 0o100 # User
258 | if fpUserWrite in perm: inc result, 0o200
259 | if fpUserRead in perm: inc result, 0o400
260 | if fpGroupExec in perm: inc result, 0o010 # Group
261 | if fpGroupWrite in perm: inc result, 0o020
262 | if fpGroupRead in perm: inc result, 0o040
263 | if fpOthersExec in perm: inc result, 0o001 # Others
264 | if fpOthersWrite in perm: inc result, 0o002
265 | if fpOthersRead in perm: inc result, 0o004
266 |
267 | proc get_file_info*(path: string; follow_symlinks: bool = true): tuple[size, link_count, block_size, permissions: int64] {.exportpy.} =
268 | let f = os.getFileInfo(path, follow_symlinks)
269 | result = (
270 | size: int64(f.size), link_count: int64(f.linkCount - 1),
271 | block_size: int64(when compiles(f.blockSize): f.blockSize else: 0),
272 | permissions: int64(fromFilePermissions(f.permissions)), # Permissions are Octal Unix.
273 | )
274 |
275 | proc get_file_times_iso*(path: string; follow_symlinks: bool = true): tuple[last_access, last_write, creation: string] {.exportpy.} =
276 | let f = os.getFileInfo(path, follow_symlinks)
277 | result = (last_access: $f.lastAccessTime, last_write: $f.lastWriteTime, creation: $f.creationTime)
278 |
279 | proc get_file_times_unix*(path: string; follow_symlinks: bool = true): tuple[last_access, last_write, creation: int64] {.exportpy.} =
280 | let f = os.getFileInfo(path, follow_symlinks)
281 | result = (last_access: toUnix(f.lastAccessTime), last_write: toUnix(f.lastWriteTime), creation: toUnix(f.creationTime))
282 |
283 | proc walk*(folderpath: string; extensions: seq[string] = @[""]; followlinks : bool = false; yieldfiles: bool = true; debugs: bool = false; check_folders: bool = false; prealloc: Positive = 99): seq[string] {.exportpy.} =
284 | result = newSeqOfCap[string](prealloc)
285 | let extused {.noalias.} = create bool
286 | extused[] = extensions != @[""] and extensions.len > 0
287 | for item in walkDirRec(folderpath, {if yieldfiles: pcFile else: pcDir}, {if followlinks: pcLinkToDir else: pcDir}, checkDir = check_folders):
288 | if unlikely(debugs): echo item
289 | if unlikely(extused[]):
290 | for ext in extensions:
291 | if item.normalize.endsWith(ext): result.add absolutePath(item)
292 | else: result.add absolutePath(item)
293 | if extused != nil: dealloc extused
294 |
295 | proc walk_glob*(globpattern: string; prealloc: Positive = 99): seq[string] {.exportpy.} =
296 | result = newSeqOfCap[string](prealloc)
297 | for item in walkPattern(globpattern): result.add absolutePath(item)
298 |
299 | proc walk_simple*(folderpath: string; relative: bool = false; check_folders: bool = false; prealloc: Positive = 99): seq[string] {.exportpy.} =
300 | result = newSeqOfCap[string](prealloc)
301 | for item in walkDirRec(folderpath, relative=relative, checkDir=check_folders): result.add absolutePath(item)
302 |
303 | proc walk_folders*(globpattern: string; prealloc: Positive = 99): seq[string] {.exportpy.} =
304 | result = newSeqOfCap[string](prealloc)
305 | for item in walkDirs(globpattern): result.add absolutePath(item)
306 |
307 | proc walk_files*(globpattern: string; prealloc: Positive = 99): seq[string] {.exportpy.} =
308 | result = newSeqOfCap[string](prealloc)
309 | for item in walkFiles(globpattern): result.add absolutePath(item)
310 |
311 | proc parseBool(s: string): bool {.inline.} =
312 | case s
313 | of "y", "Y", "1", "ON", "On", "oN", "on",
314 | "yes", "YES", "YEs", "YeS", "Yes", "yES", "yEs", "yeS",
315 | "TRUE", "TRUe", "TRuE", "TRue", "TrUE", "TrUe", "TruE", "True", "tRUE",
316 | "tRUe", "tRuE", "tRue", "trUE", "trUe", "truE", "true": result = true
317 | of "n", "N", "0", "NO", "No", "nO", "no", "",
318 | "OFF", "OFf", "OfF", "Off", "oFF", "oFf", "ofF", "off",
319 | "FALSE", "FALSe", "FALsE", "FALse", "FAlSE", "FAlSe", "FAlsE", "FAlse",
320 | "FaLSE", "FaLSe", "FaLsE", "FaLse", "FalSE", "FalSe", "FalsE", "False",
321 | "fALSE", "fALSe", "fALsE", "fALse", "fAlSE", "fAlSe", "fAlsE", "fAlse",
322 | "faLSE", "faLSe", "faLsE", "faLse", "falSE", "falSe", "falsE", "false": result = false
323 | else: doAssert false, "cannot interpret as a bool"
324 |
325 | func strip(s: var string) =
326 | var first = 0
327 | var last = s.high
328 | while first <= last and s[first] in {' ', '\t'}: inc first
329 | while last >= first and s[last] in {' ', '\t'}: dec last
330 | if unlikely(first > last):
331 | s.setLen 0
332 | return
333 | template impl =
334 | for index in first .. last: s[index - first] = s[index]
335 | if first > 0:
336 | when nimvm: impl()
337 | else:
338 | when not declared(moveMem): impl()
339 | else:
340 | when defined(nimSeqsV2) and declared(prepareMutation): prepareMutation(s)
341 | moveMem(addr s[0], addr s[first], last - first + 1)
342 | s.setLen last - first + 1
343 |
344 | func validateKey(s: string): bool {.inline.} =
345 | result = true
346 | for c in s:
347 | if c notin {'a'..'z', 'A'..'Z', '0'..'9', '_'}: return false
348 |
349 | proc dotenv*(path: string): string {.exportpy.} =
350 | var s = readFile(path)
351 | var temp = newJObject()
352 | if likely(s.len > 1):
353 | for zz in s.split('\n'): # Split by lines
354 | var z = zz # k= is the shortest possible
355 | strip(z)
356 | if z.len > 1 and z[0] != '#': # No comment lines, no empty lines
357 | let k_v = z.split('=')
358 | if k_v.len >= 2: # k sep v
359 | var k = k_v[0] # Key name
360 | strip(k)
361 | doAssert validateKey(k), "DotEnv key must be a non-empty ASCII string ([a-zA-Z0-9_])"
362 | var v = k_v[1].split('#')[0] # remove inline comments
363 | strip(v)
364 | var tipe = k_v[^1].split('#')[1] # Get type annotation
365 | strip(tipe)
366 | if k.len > 0: # k must not be empty string
367 | case tipe
368 | of "bool": temp.add k, newJBool(parseBool(v))
369 | of "string": temp.add k, newJString(v)
370 | of "json": temp.add k, parseJson(v)
371 | of "int":
372 | var i = 0
373 | discard parseSaturatedNatural(v, i)
374 | temp.add k, newJInt(i)
375 | of "float":
376 | var f = 0.0
377 | discard parseFloat(v, f)
378 | temp.add k, newJFloat(f)
379 | else: doAssert false, "Type must be 1 of int, float, bool, string, json"
380 | result = temp.pretty
381 |
--------------------------------------------------------------------------------
/thatlib/thatlib.nim.cfg:
--------------------------------------------------------------------------------
1 | -d:lto
2 | -d:strip
3 | -d:noSignalHandler
4 | -d:nimBinaryStdFiles
5 |
6 | --gc:arc
7 | --app:lib
8 | --listFullPaths:off
9 | --excessiveStackTrace:off
10 |
--------------------------------------------------------------------------------
/thatlib/thatlib.nimble:
--------------------------------------------------------------------------------
1 | requires "nimpy"
2 |
--------------------------------------------------------------------------------
/thatlib/thatlib.py:
--------------------------------------------------------------------------------
1 | import nimporter
2 | import thatlibcore
3 |
4 | def cwd():
5 | return thatlibcore.getCurrentDir()
6 |
7 | def home():
8 | return thatlibcore.home()
9 |
10 | def mkdir(path):
11 | return thatlibcore.mkdir(path)
12 |
13 | def rmdir(path, check = False):
14 | return thatlibcore.rmdir(path, check)
15 |
16 | def is_file(path):
17 | return thatlibcore.is_file(path)
18 |
19 | def is_dir(path):
20 | return thatlibcore.is_dir(path)
21 |
22 | def exists(path):
23 | return thatlibcore.exists(path)
24 |
25 | def rename(source, destination):
26 | return thatlibcore.rename(source, destination)
27 |
28 | def replace(source, destination):
29 | return thatlibcore.replace(source, destination)
30 |
31 | def resolve(path):
32 | return thatlibcore.resolve(path)
33 |
34 | def absolute(path):
35 | return thatlibcore.absolute(path)
36 |
37 | def samefile(pathA, pathB):
38 | return thatlibcore.samefile(pathA, pathB)
39 |
40 | def is_absolute(path):
41 | return thatlibcore.is_absolute(path)
42 |
43 | def joinpath(paths):
44 | return thatlibcore.joinpath(paths)
45 |
46 | def with_suffix(path, ext):
47 | return thatlibcore.with_suffix(path, ext)
48 |
49 | def with_stem(path, stem):
50 | return thatlibcore.with_stem(path, stem)
51 |
52 | def with_name(path, name):
53 | return thatlibcore.with_name(path, name)
54 |
55 | def suffix(path):
56 | return thatlibcore.suffix(path)
57 |
58 | def stem(path):
59 | return thatlibcore.stem(path)
60 |
61 | def parent(path):
62 | return thatlibcore.parent(path)
63 |
64 | def write_bytes(path, data):
65 | return thatlibcore.write_bytes(path, data)
66 |
67 | def read_bytes(path):
68 | return thatlibcore.read_bytes(path)
69 |
70 | def is_relative_to(path, base):
71 | return thatlibcore.is_relative_to(path, base)
72 |
73 | def expanduser(path):
74 | return thatlibcore.expanduser(path)
75 |
76 | def as_uri(path):
77 | return thatlibcore.as_uri(path)
78 |
79 | def parts(path):
80 | return thatlibcore.parts(path)
81 |
82 | def chmod(path, permissions):
83 | return thatlibcore.chmod(path, permissions)
84 |
85 |
86 | # ^ API mimic from Python "pathlib" ################################## v Extras
87 |
88 |
89 | def is_root():
90 | return thatlibcore.is_root()
91 |
92 | def symlink(source, destination):
93 | return thatlibcore.symlink(source, destination)
94 |
95 | def hardlink(source, destination):
96 | return thatlibcore.hardlink(source, destination)
97 |
98 | def env_vars_pairs():
99 | return thatlibcore.env_vars_pairs()
100 |
101 | def parents(path):
102 | return thatlibcore.parents(path)
103 |
104 | def is_fs_casesensitive():
105 | return thatlibcore.is_fs_casesensitive()
106 |
107 | def get_dynlib_format():
108 | return thatlibcore.get_dynlib_format()
109 |
110 | def lines(path, start = 0, ends = 1):
111 | return thatlibcore.lines(path, start, ends)
112 |
113 | def line(path, line_number):
114 | return thatlibcore.line(path, line_number)
115 |
116 | def counted_lines(path):
117 | return thatlibcore.counted_lines(path)
118 |
119 | def tokenized(path):
120 | return thatlibcore.tokenized(path)
121 |
122 | def replaced(path, replacements):
123 | return thatlibcore.replaced(path, replacements)
124 |
125 | def normalized(path):
126 | return thatlibcore.normalized(path)
127 |
128 | def is_root_dir(path):
129 | return thatlibcore.is_root_dir(path)
130 |
131 | def get_suffix_index(path):
132 | return thatlibcore.get_suffix_index(path)
133 |
134 | def path_splitted(path):
135 | return thatlibcore.path_splitted(path)
136 |
137 | def compare_paths(pathA, pathB):
138 | return thatlibcore.compare_paths(pathA, pathB)
139 |
140 | def get_conf_dir():
141 | return thatlibcore.get_conf_dir()
142 |
143 | def get_temporary_dir():
144 | return thatlibcore.get_temporary_dir()
145 |
146 | def paths_quoted(paths):
147 | return thatlibcore.paths_quoted(paths)
148 |
149 | def is_file_newer(pathA, pathB):
150 | return thatlibcore.is_file_newer(pathA, pathB)
151 |
152 | def symlink_exists(path):
153 | return thatlibcore.symlink_exists(path)
154 |
155 | def get_exe(path, followSymlinks = True):
156 | return thatlibcore.get_exe(path, followSymlinks)
157 |
158 | def mksymlink(source, destination):
159 | return thatlibcore.mksymlink(source, destination)
160 |
161 | def get_symlink(path):
162 | return thatlibcore.get_symlink(path: string)
163 |
164 | def try_rmfile(path):
165 | return thatlibcore.try_rmfile(path)
166 |
167 | def exists_create_dir(path):
168 | return thatlibcore.exists_create_dir(path)
169 |
170 | def mkhardlink(source, destination):
171 | return thatlibcore.mkhardlink(source, destination)
172 |
173 | def get_size(path):
174 | return thatlibcore.get_size(path)
175 |
176 | def get_size_human(path):
177 | return thatlibcore.get_size_human(path)
178 |
179 | def is_hidden_path(path):
180 | return thatlibcore.is_hidden_path(path)
181 |
182 | def is_valid_path(path):
183 | return thatlibcore.is_valid_path(path)
184 |
185 | def get_md5(path):
186 | return thatlibcore.get_md5(path)
187 |
188 | def get_sha1(path):
189 | return thatlibcore.get_sha1(path)
190 |
191 | def copy_file_permissions(source, dest, ignore_errors = True)
192 | return thatlibcore.copy_file_permissions(source, dest, ignore_errors)
193 |
194 | def copy_dir_permissions(source, dest, ignore_errors = True)
195 | return thatlibcore.copy_dir_permissions(source, dest, ignore_errors)
196 |
197 | def get_file_info(path, follow_symlinks = True):
198 | return thatlibcore.get_file_info(path, follow_symlinks)
199 |
200 | def get_file_times_iso(path, follow_symlinks = True):
201 | return thatlibcore.get_file_times_iso(path, follow_symlinks)
202 |
203 | def get_file_times_unix(path, follow_symlinks = True):
204 | return thatlibcore.get_file_times_unix(path, follow_symlinks)
205 |
206 | def walk(folderpath; extensions = [], followlinks = False, yieldfiles = True, debugs = False, check_folders = False, prealloc = 99):
207 | return thatlibcore.walk(folderpath, extensions, followlinks, yieldfiles, debugs, check_folders, prealloc)
208 |
209 | def walk_glob(globpattern, prealloc = 99):
210 | return thatlibcore.walk_glob(globpattern, prealloc)
211 |
212 | def walk_simple(folderpath, relative = False, check_folders = False, prealloc = 99):
213 | return thatlibcore.walk_simple(folderpath, relative, check_folders, prealloc)
214 |
215 | def walk_folders(globpattern, prealloc = 99):
216 | return thatlibcore.walk_folders(globpattern, prealloc)
217 |
218 | def walk_files(globpattern, prealloc = 99):
219 | return thatlibcore.walk_files(globpattern, prealloc)
220 |
221 | def dotenv(path):
222 | return thatlibcore.dotenv(path)
223 |
--------------------------------------------------------------------------------
/upload2pypi.sh:
--------------------------------------------------------------------------------
1 | twine upload --verbose dist/*.zip
2 |
--------------------------------------------------------------------------------